aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/dpaa/sec_var.h
blob: f3f6565adc0b8534472f5d1fdc1492c0c1027829 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * Copyright 2026 Justin Hibbits <jhibbits@FreeBSD.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifndef	DPAA_SEC_VAR_H
#define	DPAA_SEC_VAR_H

#include <sys/param.h>
#include <sys/bus.h>
#include <sys/callout.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/queue.h>
#include <sys/rman.h>
#include <sys/smp.h>

#include <machine/atomic.h>
#include <machine/bus.h>
#include <machine/resource.h>

#include <vm/vm.h>
#include <vm/pmap.h>

#include <sys/endian.h>

#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <opencrypto/cryptodev.h>
#include <opencrypto/xform_auth.h>

#include "dpaa_common.h"

#include "cryptodev_if.h"

/* A job descriptor can have up to 64 words */
#define	SEC_MAX_DESC_WORDS	64

/* Arbitrary limit */
#define	SEC_MAX_SEGMENTS	64
#define	SEC_MAX_SIZE		((SEC_MAX_SEGMENTS - 1) * PAGE_SIZE)

#define	SEC_MAX_DIGEST		64	/* SHA-512 */
#define	SEC_CCM_CTX_LEN		56

/*
 * SEC's output ring entry: 8-byte descriptor phys addr
 * echoed from the input ring, followed by a 4-byte job termination
 * status word.  Entries are packed.
 */
struct sec_or_entry {
	uint64_t	desc_addr;
	uint32_t	status;
} __packed;

_Static_assert(sizeof(struct sec_or_entry) == 12, "OR entry size");

struct sec_job;
struct sec_session;

/*
 * One Job Ring.  Rings are independent all the way down: separate
 * register block, separate completion interrupt, separate lock.
 * Spreading jobs across them keeps submitters off each other's locks.
 * The rings themselves live in DMA-safe memory from bus_dmamem_alloc.
 */
struct sec_jr {
	struct sec_softc	*jr_sc;		/* for the interrupt handler */
	phandle_t		 jr_node;	/* FDT node for this JR */
	uint32_t		 jr_off;	/* JR base within sc_rres */

	bus_dma_tag_t		 jr_ring_tag;
	bus_dmamap_t		 jr_map;	/* covers both rings */
	uint64_t		*jr_ir;		/* input, JR_RING_SIZE * 8B */
	vm_paddr_t		 jr_ir_pa;
	struct sec_or_entry	*jr_or;		/* output ring */
	vm_paddr_t		 jr_or_pa;
	uint32_t		 jr_ir_head;	/* next slot driver writes */
	uint32_t		 jr_or_tail;	/* next slot driver reads */

	/* Completion IRQ, separate from the SEC top-level error IRQ. */
	struct resource		*jr_ires;
	int			 jr_irid;
	void			*jr_icookie;

	/*
	 * Jobs handed to the ring and not yet seen on the output ring.
	 * jr_lock covers this and both ring indices, and is held only for
	 * the ring manipulation itself, never across a job.  When the ring
	 * fills, jr_blocked records that opencrypto needs a
	 * crypto_unblock() once slots free up.
	 */
	uint32_t		 jr_inflight;
	int			 jr_blocked;

	/*
	 * Outstanding jobs in submission order, so the watchdog only has
	 * to look at the head to find the oldest.  jr_flushing marks the
	 * window between asking SEC to flush the ring and clearing HALT.
	 */
	TAILQ_HEAD(, sec_job)	 jr_active;
	struct callout		 jr_wdog;
	bool			 jr_flushing;
	bool			 jr_dying;

	struct mtx		 jr_lock;
};

struct sec_softc {
	device_t		 sc_dev;
	struct resource		*sc_rres;	/* CCSR MMIO for SEC */
	int			 sc_rrid;
	struct resource		*sc_ires;	/* SEC error IRQ */
	int			 sc_irid;
	void			*sc_icookie;
	bus_dma_tag_t		 sc_dmatag;	/* for crypto payloads */
	int32_t			 sc_cid;	/* opencrypto driver id */
	int			 sc_version;

	struct sec_jr		 *sc_jr;	/* Job rings */
	u_int			 sc_njr;
};

/*
 * Per-request state.  The job descriptor at the head becomes the
 * address we push into the input ring.  SEC echoes that same address
 * in the output ring, and PHYS_TO_DMAP() gives us the struct back.
 */

struct sec_job {
	uint32_t		 jd[SEC_MAX_DESC_WORDS];
	struct dpaa_sgte		 in_sgt[1 + SEC_MAX_SEGMENTS];
	struct dpaa_sgte		 out_sgt[SEC_MAX_SEGMENTS];
	/* Driver-private (SEC does not touch anything below). */
	struct cryptop		*crp;
	struct sec_session	*sess;
	bus_dmamap_t		 map;
	TAILQ_ENTRY(sec_job)	 job_link;
	int			 job_deadline;	/* ticks */
	/* Also holds the expanded 16-byte XTS tweak; see sec_xts_tweak(). */
	uint8_t			 iv[AES_BLOCK_LEN];
	uint8_t			 ccm_ctx[SEC_CCM_CTX_LEN];
	uint8_t			 ccm_alen[2];
	uint8_t			 digest[SEC_MAX_DIGEST];
	int			 nsegs;
	bus_dma_segment_t	 segs[SEC_MAX_SEGMENTS];
};

int	sec_init_rings(struct sec_softc *sc);
int	sec_destroy_rings(struct sec_softc *sc);
int	sec_jr_submit_job(struct sec_softc *sc, struct sec_jr *jr,
    struct sec_job *job);
void	sec_jr_teardown(struct sec_softc *sc, struct sec_jr *jr);
void	sec_complete_one(struct sec_softc *sc, uint64_t desc_pa, uint32_t status);

MALLOC_DECLARE(M_SEC);

#endif