1*4dccd3acSJustin Hibbits /*-
2*4dccd3acSJustin Hibbits * Copyright (c) 2026 Justin Hibbits
3*4dccd3acSJustin Hibbits *
4*4dccd3acSJustin Hibbits * SPDX-License-Identifier: BSD-2-Clause
5*4dccd3acSJustin Hibbits *
6*4dccd3acSJustin Hibbits * FMan KeyGen (KG) support. The KG block is the FMan sub-unit that
7*4dccd3acSJustin Hibbits * classifies incoming frames into destination FQIDs via user-defined
8*4dccd3acSJustin Hibbits * "schemes". Each scheme extracts a key from the frame's parse
9*4dccd3acSJustin Hibbits * result, hashes it, and enqueues to FQID = base | (hash & mask).
10*4dccd3acSJustin Hibbits */
11*4dccd3acSJustin Hibbits
12*4dccd3acSJustin Hibbits #include <sys/param.h>
13*4dccd3acSJustin Hibbits #include <sys/systm.h>
14*4dccd3acSJustin Hibbits #include <sys/bus.h>
15*4dccd3acSJustin Hibbits #include <sys/rman.h>
16*4dccd3acSJustin Hibbits
17*4dccd3acSJustin Hibbits #include <machine/bus.h>
18*4dccd3acSJustin Hibbits
19*4dccd3acSJustin Hibbits #include "fman.h"
20*4dccd3acSJustin Hibbits #include "fman_keygen.h"
21*4dccd3acSJustin Hibbits
22*4dccd3acSJustin Hibbits #define FMAN_KG_OFFSET 0xc1000
23*4dccd3acSJustin Hibbits
24*4dccd3acSJustin Hibbits /*
25*4dccd3acSJustin Hibbits * Register offsets, relative to FMAN_KG_OFFSET (0xc1000) inside the
26*4dccd3acSJustin Hibbits * FMan register block.
27*4dccd3acSJustin Hibbits */
28*4dccd3acSJustin Hibbits #define FMKG_GCR 0x000 /* general configuration */
29*4dccd3acSJustin Hibbits #define FMKG_GCR_EN 0x80000000
30*4dccd3acSJustin Hibbits #define FMKG_EER 0x00C /* error event */
31*4dccd3acSJustin Hibbits #define FMKG_EER_DOUBLE_ECC 0x80000000
32*4dccd3acSJustin Hibbits #define FMKG_EER_KEYSIZE_OVF 0x40000000
33*4dccd3acSJustin Hibbits #define FMKG_EEER 0x010 /* error event enable */
34*4dccd3acSJustin Hibbits #define FMKG_SEER 0x01C /* scheme error event */
35*4dccd3acSJustin Hibbits #define FMKG_SEEER 0x020 /* scheme error event enable */
36*4dccd3acSJustin Hibbits #define FMKG_GSR 0x024 /* global status */
37*4dccd3acSJustin Hibbits #define FMKG_GSR_BSY 0x80000000
38*4dccd3acSJustin Hibbits #define FMKG_TPC 0x028 /* total packet counter */
39*4dccd3acSJustin Hibbits #define FMKG_SERC 0x02C /* soft error capture */
40*4dccd3acSJustin Hibbits #define FMKG_FDOR 0x034 /* frame data offset */
41*4dccd3acSJustin Hibbits #define FMKG_GDV0R 0x038 /* global default value 0 */
42*4dccd3acSJustin Hibbits #define FMKG_GDV1R 0x03C /* global default value 1 */
43*4dccd3acSJustin Hibbits #define FMKG_FEER 0x044 /* force error event */
44*4dccd3acSJustin Hibbits #define FMKG_AR 0x1FC /* action register */
45*4dccd3acSJustin Hibbits #define FMKG_AR_GO 0x80000000
46*4dccd3acSJustin Hibbits #define FMKG_AR_READ 0x40000000 /* clear = write */
47*4dccd3acSJustin Hibbits #define FMKG_AR_ERR 0x20000000
48*4dccd3acSJustin Hibbits #define FMKG_AR_SEL_CLS_PLAN 0x01000000
49*4dccd3acSJustin Hibbits #define FMKG_AR_SEL_PORT 0x02000000 /* clear = scheme entry */
50*4dccd3acSJustin Hibbits #define FMKG_AR_PORT_WSEL_SP 0x00008000
51*4dccd3acSJustin Hibbits #define FMKG_AR_PORT_WSEL_CPP 0x00004000
52*4dccd3acSJustin Hibbits #define FMKG_AR_SCM_WSEL_UPDCNT 0x00008000
53*4dccd3acSJustin Hibbits #define FMKG_AR_NUM_SHIFT 16 /* scheme id here */
54*4dccd3acSJustin Hibbits
55*4dccd3acSJustin Hibbits /*
56*4dccd3acSJustin Hibbits * Indirect access sub-region (union of "scheme entry" and "port
57*4dccd3acSJustin Hibbits * entry" views, discriminated by the last AR selector written).
58*4dccd3acSJustin Hibbits */
59*4dccd3acSJustin Hibbits #define FMKG_IND 0x100
60*4dccd3acSJustin Hibbits
61*4dccd3acSJustin Hibbits /* Scheme-view offsets, relative to FMKG_IND. */
62*4dccd3acSJustin Hibbits #define FMKG_SE_MODE 0x00 /* mode + NIA */
63*4dccd3acSJustin Hibbits #define FMKG_SE_MODE_EN 0x80000000
64*4dccd3acSJustin Hibbits #define FMKG_SE_EKFC 0x04 /* extract known fields command */
65*4dccd3acSJustin Hibbits #define FMKG_EKFC_IPSRC1 0x00100000
66*4dccd3acSJustin Hibbits #define FMKG_EKFC_IPDST1 0x00080000
67*4dccd3acSJustin Hibbits #define FMKG_EKFC_L4PSRC 0x00000004
68*4dccd3acSJustin Hibbits #define FMKG_EKFC_L4PDST 0x00000002
69*4dccd3acSJustin Hibbits #define FMKG_EKFC_IPSEC_SPI 0x00000200
70*4dccd3acSJustin Hibbits #define FMKG_SE_EKDV 0x08 /* extract known default value */
71*4dccd3acSJustin Hibbits #define FMKG_EKDV_IP_ADDR_SHIFT 18
72*4dccd3acSJustin Hibbits #define FMKG_EKDV_L4_PORT_SHIFT 8
73*4dccd3acSJustin Hibbits #define FMKG_EKDV_USE_DV0 2
74*4dccd3acSJustin Hibbits #define FMKG_EKDV_USE_DV1 3
75*4dccd3acSJustin Hibbits #define FMKG_SE_BMCH 0x0C /* bit mask high */
76*4dccd3acSJustin Hibbits #define FMKG_SE_BMCL 0x10 /* bit mask low */
77*4dccd3acSJustin Hibbits #define FMKG_SE_FQB 0x14 /* frame queue base */
78*4dccd3acSJustin Hibbits #define FMKG_SE_HC 0x18 /* hash command */
79*4dccd3acSJustin Hibbits #define FMKG_SE_HC_SYM 0x40000000 /* symmetric hash */
80*4dccd3acSJustin Hibbits #define FMKG_SE_HC_SHIFT_SHIFT 24
81*4dccd3acSJustin Hibbits #define FMKG_SE_HC_MASK_SHIFT 0
82*4dccd3acSJustin Hibbits #define FMKG_SE_PPC 0x1C /* policer profile command */
83*4dccd3acSJustin Hibbits #define FMKG_SE_GEC(i) (0x20 + (i) * 4) /* generic extract command [0..7] */
84*4dccd3acSJustin Hibbits #define FMKG_SE_SPC 0x40 /* statistic packet counter */
85*4dccd3acSJustin Hibbits #define FMKG_SE_DV0 0x44 /* default value 0 */
86*4dccd3acSJustin Hibbits #define FMKG_SE_DV1 0x48 /* default value 1 */
87*4dccd3acSJustin Hibbits #define FMKG_SE_CCBS 0x4C /* coarse classification */
88*4dccd3acSJustin Hibbits #define FMKG_SE_MV 0x50 /* match vector */
89*4dccd3acSJustin Hibbits #define FMKG_SE_OM 0x54 /* operation mode */
90*4dccd3acSJustin Hibbits #define FMKG_SE_VSP 0x58 /* virtual storage profile */
91*4dccd3acSJustin Hibbits #define FMKG_SE_VSP_NO_KSP_EN 0x80000000
92*4dccd3acSJustin Hibbits
93*4dccd3acSJustin Hibbits /* Port-view offsets, relative to FMKG_IND. */
94*4dccd3acSJustin Hibbits #define FMKG_PE_SP 0x00 /* port scheme partition */
95*4dccd3acSJustin Hibbits #define FMKG_PE_CPP 0x04 /* port classification-plan partition */
96*4dccd3acSJustin Hibbits
97*4dccd3acSJustin Hibbits /*
98*4dccd3acSJustin Hibbits * Default NIA for post-KeyGen
99*4dccd3acSJustin Hibbits */
100*4dccd3acSJustin Hibbits #define FMKG_ENQ_KG_DFLT_NIA \
101*4dccd3acSJustin Hibbits (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)
102*4dccd3acSJustin Hibbits
103*4dccd3acSJustin Hibbits /*
104*4dccd3acSJustin Hibbits * Arbitrary fillers used for the "missing field" fallback slots.
105*4dccd3acSJustin Hibbits * The exact values don't matter for correctness -- the hash still
106*4dccd3acSJustin Hibbits * distributes uniformly across FQs -- but a non-zero pattern makes
107*4dccd3acSJustin Hibbits * two frames missing the same field hash to a consistent bucket.
108*4dccd3acSJustin Hibbits */
109*4dccd3acSJustin Hibbits #define FMKG_DFLT_IPv4_ADDR 0x0a0a0a0a
110*4dccd3acSJustin Hibbits #define FMKG_DFLT_L4_PORT 0x0b0b0b0b
111*4dccd3acSJustin Hibbits
112*4dccd3acSJustin Hibbits /* Sizing. */
113*4dccd3acSJustin Hibbits #define FMKG_MAX_SCHEMES 32
114*4dccd3acSJustin Hibbits #define FMKG_MAX_HW_PORTS 64
115*4dccd3acSJustin Hibbits
116*4dccd3acSJustin Hibbits /*
117*4dccd3acSJustin Hibbits * AR-write acknowledge wait. Linux busy-loops with no bound; we
118*4dccd3acSJustin Hibbits * cap at ~1 ms of DELAY(1) to survive a wedged block without
119*4dccd3acSJustin Hibbits * hanging the boot.
120*4dccd3acSJustin Hibbits */
121*4dccd3acSJustin Hibbits #define FMKG_AR_WAIT_US 1000
122*4dccd3acSJustin Hibbits
123*4dccd3acSJustin Hibbits static inline uint32_t
kg_read(struct fman_softc * sc,bus_size_t off)124*4dccd3acSJustin Hibbits kg_read(struct fman_softc *sc, bus_size_t off)
125*4dccd3acSJustin Hibbits {
126*4dccd3acSJustin Hibbits return (bus_read_4(sc->mem_res, FMAN_KG_OFFSET + off));
127*4dccd3acSJustin Hibbits }
128*4dccd3acSJustin Hibbits
129*4dccd3acSJustin Hibbits static inline void
kg_write(struct fman_softc * sc,bus_size_t off,uint32_t val)130*4dccd3acSJustin Hibbits kg_write(struct fman_softc *sc, bus_size_t off, uint32_t val)
131*4dccd3acSJustin Hibbits {
132*4dccd3acSJustin Hibbits bus_write_4(sc->mem_res, FMAN_KG_OFFSET + off, val);
133*4dccd3acSJustin Hibbits }
134*4dccd3acSJustin Hibbits
135*4dccd3acSJustin Hibbits static int
kg_ar_write(struct fman_softc * sc,uint32_t ar)136*4dccd3acSJustin Hibbits kg_ar_write(struct fman_softc *sc, uint32_t ar)
137*4dccd3acSJustin Hibbits {
138*4dccd3acSJustin Hibbits int i;
139*4dccd3acSJustin Hibbits
140*4dccd3acSJustin Hibbits kg_write(sc, FMKG_AR, ar);
141*4dccd3acSJustin Hibbits for (i = 0; i < FMKG_AR_WAIT_US; i++) {
142*4dccd3acSJustin Hibbits ar = kg_read(sc, FMKG_AR);
143*4dccd3acSJustin Hibbits if ((ar & FMKG_AR_GO) == 0)
144*4dccd3acSJustin Hibbits break;
145*4dccd3acSJustin Hibbits DELAY(1);
146*4dccd3acSJustin Hibbits }
147*4dccd3acSJustin Hibbits if ((ar & FMKG_AR_GO) != 0) {
148*4dccd3acSJustin Hibbits device_printf(sc->sc_base.dev,
149*4dccd3acSJustin Hibbits "fman_kg: AR stuck busy (0x%08x)\n", ar);
150*4dccd3acSJustin Hibbits return (ETIMEDOUT);
151*4dccd3acSJustin Hibbits }
152*4dccd3acSJustin Hibbits if ((ar & FMKG_AR_ERR) != 0) {
153*4dccd3acSJustin Hibbits device_printf(sc->sc_base.dev,
154*4dccd3acSJustin Hibbits "fman_kg: AR reported error (0x%08x)\n", ar);
155*4dccd3acSJustin Hibbits return (EIO);
156*4dccd3acSJustin Hibbits }
157*4dccd3acSJustin Hibbits return (0);
158*4dccd3acSJustin Hibbits }
159*4dccd3acSJustin Hibbits
160*4dccd3acSJustin Hibbits /*
161*4dccd3acSJustin Hibbits * Populate the indirect scheme registers for an RSS-style hash
162*4dccd3acSJustin Hibbits * scheme and commit it via an AR-write.
163*4dccd3acSJustin Hibbits */
164*4dccd3acSJustin Hibbits static int
kg_program_scheme(struct fman_softc * sc,uint8_t scheme_id,uint32_t base_fqid,uint32_t nfqs)165*4dccd3acSJustin Hibbits kg_program_scheme(struct fman_softc *sc, uint8_t scheme_id,
166*4dccd3acSJustin Hibbits uint32_t base_fqid, uint32_t nfqs)
167*4dccd3acSJustin Hibbits {
168*4dccd3acSJustin Hibbits uint32_t ekdv;
169*4dccd3acSJustin Hibbits int error;
170*4dccd3acSJustin Hibbits
171*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_MODE,
172*4dccd3acSJustin Hibbits FMKG_SE_MODE_EN | FMKG_ENQ_KG_DFLT_NIA);
173*4dccd3acSJustin Hibbits
174*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_EKFC,
175*4dccd3acSJustin Hibbits FMKG_EKFC_IPSRC1 | FMKG_EKFC_IPDST1 |
176*4dccd3acSJustin Hibbits FMKG_EKFC_L4PSRC | FMKG_EKFC_L4PDST |
177*4dccd3acSJustin Hibbits FMKG_EKFC_IPSEC_SPI);
178*4dccd3acSJustin Hibbits
179*4dccd3acSJustin Hibbits ekdv = (FMKG_EKDV_USE_DV0 << FMKG_EKDV_IP_ADDR_SHIFT) |
180*4dccd3acSJustin Hibbits (FMKG_EKDV_USE_DV1 << FMKG_EKDV_L4_PORT_SHIFT);
181*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_EKDV, ekdv);
182*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_DV0, FMKG_DFLT_IPv4_ADDR);
183*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_DV1, FMKG_DFLT_L4_PORT);
184*4dccd3acSJustin Hibbits
185*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_FQB, base_fqid);
186*4dccd3acSJustin Hibbits /*
187*4dccd3acSJustin Hibbits * FQID mask width = (nfqs - 1), no hash right-shift. Symmetric
188*4dccd3acSJustin Hibbits * hash is deliberately off: per NXP's own driver notes,
189*4dccd3acSJustin Hibbits * spreading breaks with SYM set even though the extraction key
190*4dccd3acSJustin Hibbits * is nominally symmetric.
191*4dccd3acSJustin Hibbits */
192*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_HC,
193*4dccd3acSJustin Hibbits (nfqs - 1) << FMKG_SE_HC_MASK_SHIFT);
194*4dccd3acSJustin Hibbits
195*4dccd3acSJustin Hibbits /*
196*4dccd3acSJustin Hibbits * TODO: Revisit these registers later, if necessary.
197*4dccd3acSJustin Hibbits */
198*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_BMCH, 0);
199*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_BMCL, 0);
200*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_PPC, 0);
201*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_SPC, 0);
202*4dccd3acSJustin Hibbits for (int i = 0; i < 8; i++)
203*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_GEC(i), 0);
204*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_CCBS, 0);
205*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_MV, 0); /* indirect scheme */
206*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_OM, 0);
207*4dccd3acSJustin Hibbits /*
208*4dccd3acSJustin Hibbits * Don't let the scheme override the port's Virtual Storage
209*4dccd3acSJustin Hibbits * Profile.
210*4dccd3acSJustin Hibbits */
211*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_VSP, FMKG_SE_VSP_NO_KSP_EN);
212*4dccd3acSJustin Hibbits error = kg_ar_write(sc, FMKG_AR_GO |
213*4dccd3acSJustin Hibbits (scheme_id << FMKG_AR_NUM_SHIFT) | FMKG_AR_SCM_WSEL_UPDCNT);
214*4dccd3acSJustin Hibbits if (error != 0)
215*4dccd3acSJustin Hibbits device_printf(sc->sc_base.dev,
216*4dccd3acSJustin Hibbits "fman_kg: scheme %u program failed\n", scheme_id);
217*4dccd3acSJustin Hibbits return (error);
218*4dccd3acSJustin Hibbits }
219*4dccd3acSJustin Hibbits
220*4dccd3acSJustin Hibbits static int
kg_disable_scheme(struct fman_softc * sc,uint8_t scheme_id)221*4dccd3acSJustin Hibbits kg_disable_scheme(struct fman_softc *sc, uint8_t scheme_id)
222*4dccd3acSJustin Hibbits {
223*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_SE_MODE, 0);
224*4dccd3acSJustin Hibbits return (kg_ar_write(sc, FMKG_AR_GO | (scheme_id << FMKG_AR_NUM_SHIFT)));
225*4dccd3acSJustin Hibbits }
226*4dccd3acSJustin Hibbits
227*4dccd3acSJustin Hibbits /*
228*4dccd3acSJustin Hibbits * Read-modify-write the port's scheme-partition bitmap to add or
229*4dccd3acSJustin Hibbits * remove @scheme_id.
230*4dccd3acSJustin Hibbits */
231*4dccd3acSJustin Hibbits static int
kg_bind_scheme(struct fman_softc * sc,uint8_t hw_port_id,uint8_t scheme_id,bool bind)232*4dccd3acSJustin Hibbits kg_bind_scheme(struct fman_softc *sc, uint8_t hw_port_id, uint8_t scheme_id,
233*4dccd3acSJustin Hibbits bool bind)
234*4dccd3acSJustin Hibbits {
235*4dccd3acSJustin Hibbits uint32_t sp;
236*4dccd3acSJustin Hibbits int error;
237*4dccd3acSJustin Hibbits
238*4dccd3acSJustin Hibbits error = kg_ar_write(sc,
239*4dccd3acSJustin Hibbits FMKG_AR_GO | FMKG_AR_READ | FMKG_AR_SEL_PORT |
240*4dccd3acSJustin Hibbits hw_port_id | FMKG_AR_PORT_WSEL_SP);
241*4dccd3acSJustin Hibbits if (error != 0)
242*4dccd3acSJustin Hibbits return (error);
243*4dccd3acSJustin Hibbits
244*4dccd3acSJustin Hibbits sp = kg_read(sc, FMKG_IND + FMKG_PE_SP);
245*4dccd3acSJustin Hibbits if (bind)
246*4dccd3acSJustin Hibbits sp |= (1U << (31 - scheme_id));
247*4dccd3acSJustin Hibbits else
248*4dccd3acSJustin Hibbits sp &= ~(1U << (31 - scheme_id));
249*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_PE_SP, sp);
250*4dccd3acSJustin Hibbits
251*4dccd3acSJustin Hibbits return (kg_ar_write(sc,
252*4dccd3acSJustin Hibbits FMKG_AR_GO | FMKG_AR_SEL_PORT | hw_port_id | FMKG_AR_PORT_WSEL_SP));
253*4dccd3acSJustin Hibbits }
254*4dccd3acSJustin Hibbits
255*4dccd3acSJustin Hibbits int
fman_kg_init(struct fman_softc * sc)256*4dccd3acSJustin Hibbits fman_kg_init(struct fman_softc *sc)
257*4dccd3acSJustin Hibbits {
258*4dccd3acSJustin Hibbits int error, i;
259*4dccd3acSJustin Hibbits
260*4dccd3acSJustin Hibbits sc->sc_kg_schemes_used = 0;
261*4dccd3acSJustin Hibbits for (i = 0; i < FMKG_MAX_HW_PORTS; i++)
262*4dccd3acSJustin Hibbits sc->sc_kg_port_scheme[i] = -1;
263*4dccd3acSJustin Hibbits
264*4dccd3acSJustin Hibbits kg_write(sc, FMKG_GCR, FMKG_ENQ_KG_DFLT_NIA);
265*4dccd3acSJustin Hibbits kg_write(sc, FMKG_EER,
266*4dccd3acSJustin Hibbits FMKG_EER_DOUBLE_ECC | FMKG_EER_KEYSIZE_OVF);
267*4dccd3acSJustin Hibbits
268*4dccd3acSJustin Hibbits kg_write(sc, FMKG_FDOR, 0);
269*4dccd3acSJustin Hibbits kg_write(sc, FMKG_GDV0R, 0);
270*4dccd3acSJustin Hibbits kg_write(sc, FMKG_GDV1R, 0);
271*4dccd3acSJustin Hibbits
272*4dccd3acSJustin Hibbits for (i = 0; i < FMKG_MAX_HW_PORTS; i++) {
273*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_PE_SP, 0);
274*4dccd3acSJustin Hibbits error = kg_ar_write(sc, FMKG_AR_GO | FMKG_AR_SEL_PORT |
275*4dccd3acSJustin Hibbits i | FMKG_AR_PORT_WSEL_SP);
276*4dccd3acSJustin Hibbits if (error != 0)
277*4dccd3acSJustin Hibbits return (error);
278*4dccd3acSJustin Hibbits
279*4dccd3acSJustin Hibbits kg_write(sc, FMKG_IND + FMKG_PE_CPP, 0);
280*4dccd3acSJustin Hibbits error = kg_ar_write(sc, FMKG_AR_GO | FMKG_AR_SEL_PORT |
281*4dccd3acSJustin Hibbits i | FMKG_AR_PORT_WSEL_CPP);
282*4dccd3acSJustin Hibbits if (error != 0)
283*4dccd3acSJustin Hibbits return (error);
284*4dccd3acSJustin Hibbits }
285*4dccd3acSJustin Hibbits
286*4dccd3acSJustin Hibbits /* Enable per-scheme error events. */
287*4dccd3acSJustin Hibbits kg_write(sc, FMKG_SEER, 0xffffffff);
288*4dccd3acSJustin Hibbits kg_write(sc, FMKG_SEEER, 0xffffffff);
289*4dccd3acSJustin Hibbits
290*4dccd3acSJustin Hibbits /* TODO: Error handling interrupts -- register with FMan */
291*4dccd3acSJustin Hibbits
292*4dccd3acSJustin Hibbits /* Enable the block. */
293*4dccd3acSJustin Hibbits kg_write(sc, FMKG_GCR, kg_read(sc, FMKG_GCR) | FMKG_GCR_EN);
294*4dccd3acSJustin Hibbits
295*4dccd3acSJustin Hibbits return (0);
296*4dccd3acSJustin Hibbits }
297*4dccd3acSJustin Hibbits
298*4dccd3acSJustin Hibbits void
fman_kg_fini(struct fman_softc * sc)299*4dccd3acSJustin Hibbits fman_kg_fini(struct fman_softc *sc)
300*4dccd3acSJustin Hibbits {
301*4dccd3acSJustin Hibbits /* No need for a full teardown, just disable the module. */
302*4dccd3acSJustin Hibbits kg_write(sc, FMKG_GCR, 0);
303*4dccd3acSJustin Hibbits while ((kg_read(sc, FMKG_GSR) & FMKG_GSR_BSY) != 0)
304*4dccd3acSJustin Hibbits DELAY(1);
305*4dccd3acSJustin Hibbits }
306*4dccd3acSJustin Hibbits
307*4dccd3acSJustin Hibbits int
fman_kg_alloc_hash_scheme(struct fman_softc * sc,int hw_port_id,uint32_t base_fqid,uint32_t nfqs)308*4dccd3acSJustin Hibbits fman_kg_alloc_hash_scheme(struct fman_softc *sc, int hw_port_id,
309*4dccd3acSJustin Hibbits uint32_t base_fqid, uint32_t nfqs)
310*4dccd3acSJustin Hibbits {
311*4dccd3acSJustin Hibbits uint8_t scheme_id;
312*4dccd3acSJustin Hibbits int error, i;
313*4dccd3acSJustin Hibbits
314*4dccd3acSJustin Hibbits if (hw_port_id < 0 || hw_port_id >= FMKG_MAX_HW_PORTS)
315*4dccd3acSJustin Hibbits return (EINVAL);
316*4dccd3acSJustin Hibbits if (base_fqid == 0 || (base_fqid & ~0x00ffffff) != 0)
317*4dccd3acSJustin Hibbits return (EINVAL);
318*4dccd3acSJustin Hibbits if (nfqs == 0 || (nfqs & (nfqs - 1)) != 0)
319*4dccd3acSJustin Hibbits return (EINVAL); /* not a power of two */
320*4dccd3acSJustin Hibbits if ((base_fqid & (nfqs - 1)) != 0)
321*4dccd3acSJustin Hibbits return (EINVAL); /* base not aligned to nfqs */
322*4dccd3acSJustin Hibbits if (sc->sc_kg_port_scheme[hw_port_id] != -1)
323*4dccd3acSJustin Hibbits return (EBUSY);
324*4dccd3acSJustin Hibbits
325*4dccd3acSJustin Hibbits for (i = 0; i < FMKG_MAX_SCHEMES; i++) {
326*4dccd3acSJustin Hibbits if ((sc->sc_kg_schemes_used & (1U << i)) == 0) {
327*4dccd3acSJustin Hibbits scheme_id = i;
328*4dccd3acSJustin Hibbits break;
329*4dccd3acSJustin Hibbits }
330*4dccd3acSJustin Hibbits }
331*4dccd3acSJustin Hibbits if (i == FMKG_MAX_SCHEMES)
332*4dccd3acSJustin Hibbits return (ENOSPC);
333*4dccd3acSJustin Hibbits
334*4dccd3acSJustin Hibbits error = kg_program_scheme(sc, scheme_id, base_fqid, nfqs);
335*4dccd3acSJustin Hibbits if (error != 0)
336*4dccd3acSJustin Hibbits return (error);
337*4dccd3acSJustin Hibbits
338*4dccd3acSJustin Hibbits error = kg_bind_scheme(sc, hw_port_id, scheme_id, true);
339*4dccd3acSJustin Hibbits if (error != 0) {
340*4dccd3acSJustin Hibbits (void)kg_disable_scheme(sc, scheme_id);
341*4dccd3acSJustin Hibbits return (error);
342*4dccd3acSJustin Hibbits }
343*4dccd3acSJustin Hibbits
344*4dccd3acSJustin Hibbits sc->sc_kg_schemes_used |= (1U << scheme_id);
345*4dccd3acSJustin Hibbits sc->sc_kg_port_scheme[hw_port_id] = scheme_id;
346*4dccd3acSJustin Hibbits return (0);
347*4dccd3acSJustin Hibbits }
348*4dccd3acSJustin Hibbits
349*4dccd3acSJustin Hibbits int
fman_kg_free_hash_scheme(struct fman_softc * sc,int hw_port_id)350*4dccd3acSJustin Hibbits fman_kg_free_hash_scheme(struct fman_softc *sc, int hw_port_id)
351*4dccd3acSJustin Hibbits {
352*4dccd3acSJustin Hibbits int8_t scheme_id;
353*4dccd3acSJustin Hibbits int error;
354*4dccd3acSJustin Hibbits
355*4dccd3acSJustin Hibbits if (hw_port_id < 0 || hw_port_id >= FMKG_MAX_HW_PORTS)
356*4dccd3acSJustin Hibbits return (EINVAL);
357*4dccd3acSJustin Hibbits scheme_id = sc->sc_kg_port_scheme[hw_port_id];
358*4dccd3acSJustin Hibbits if (scheme_id == -1)
359*4dccd3acSJustin Hibbits return (ENOENT);
360*4dccd3acSJustin Hibbits
361*4dccd3acSJustin Hibbits error = kg_bind_scheme(sc, hw_port_id, scheme_id, false);
362*4dccd3acSJustin Hibbits if (error != 0)
363*4dccd3acSJustin Hibbits return (error);
364*4dccd3acSJustin Hibbits error = kg_disable_scheme(sc, scheme_id);
365*4dccd3acSJustin Hibbits if (error != 0)
366*4dccd3acSJustin Hibbits return (error);
367*4dccd3acSJustin Hibbits
368*4dccd3acSJustin Hibbits sc->sc_kg_schemes_used &= ~(1U << scheme_id);
369*4dccd3acSJustin Hibbits sc->sc_kg_port_scheme[hw_port_id] = -1;
370*4dccd3acSJustin Hibbits return (0);
371*4dccd3acSJustin Hibbits }
372