1 /*
2 * Copyright (c) 2026 Justin Hibbits
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * FMan RX port driver.
7 */
8
9 #include <sys/param.h>
10 #include <sys/bus.h>
11 #include <sys/kernel.h>
12 #include <sys/module.h>
13
14 #include <dev/ofw/ofw_bus.h>
15 #include <dev/ofw/ofw_bus_subr.h>
16 #include <machine/bus.h>
17
18 #include "fman.h"
19 #include "fman_parser.h"
20 #include "fman_port.h"
21 #include "fman_port_var.h"
22 #include "fman_if.h"
23 #include "fman_port_if.h"
24
25 #define RX_10G_PORT_BASE 0x10
26
27 /* BMI Rx registers. */
28 #define FMBM_RCFG 0x000
29 #define FMBM_RST 0x004
30 #define FMBM_RDA 0x008
31 #define RDA_WOPT 0x00100000
32 #define FMBM_RFP 0x00c
33 #define FMBM_RFED 0x010
34 #define BMI_RX_FRAME_END_CUT_SHIFT 16
35 #define FMBM_RICP 0x014 /* Counts are units of 16 bytes */
36 #define RICP_ICEOF_M 0x001f0000
37 #define RICP_ICEOF_S 16
38 #define RICP_ICIOF_M 0x00000f00
39 #define RICP_ICIOF_S 8
40 #define RICP_ICSZ_S 0x0000001f
41 #define FMBM_RIM 0x018
42 #define FMBM_REBM 0x01c
43 #define REBM_BSM_M 0x01ff0000
44 #define REBM_BSM_S 16
45 #define REBM_BEM_M 0x000001ff
46 #define FMBM_RFNE 0x020
47 #define FMBM_RFCA 0x024
48 #define RFCA_OR 0x80000000
49 #define RFCA_COLOR 0x0c000000
50 #define RFCA_SYNC 0x03000000
51 #define RFCA_SYNC_REQ 0x02000000
52 #define RFCA_MR 0x003f0000
53 #define RFCA_MR_DEF 0x003c0000
54 #define FMBM_RFPNE 0x028
55 #define FMBM_RETH 0x038
56 #define RETH_ETHE 0x80000000 /* Excessive Threshold Enable */
57 #define FMBM_RFQID 0x060
58 #define FMBM_REFQID 0x064
59 #define FMBM_RFSDM 0x068
60 #define FMBM_RFSEM 0x06c
61 #define FMBM_RFENE 0x070
62 #define FMBM_REBMPI(i) (0x100 + (4 * (i)))
63 #define REBMPI_VAL 0x80000000
64 #define REBMPI_ACE 0x40000000
65 #define REBMPI_BPID_S 16
66 #define FMBM_RSTC 0x0200
67 #define RSTC_EN 0x80000000
68
69 /* Hardware Parser (HWP). */
70 #define HWP_PCAC 0xbf8
71 #define HWP_PCAC_PSTOP 0x00000001
72 #define HWP_HXS_PCAC_PSTAT 0x00000100
73 #define HWP_HXS_SSA(x) (0x800 + x * 2 * sizeof(uint32_t))
74 #define HWP_HXS_LCV(x) (0x800 + (x * 2 + 1) * sizeof(uint32_t))
75 #define HWP_HXS_TCP 0xA
76 #define HWP_HXS_UDP 0xB
77 #define HXS_SH_PAD_REM 0x80000000
78 #define HWP_HXS_COUNT 16
79
80 #define BMI_RX_ERR (FM_FD_ERR_DMA | FM_FD_ERR_FPE | \
81 FM_FD_ERR_FSE | FM_FD_ERR_DIS | \
82 FM_FD_ERR_EOF | FM_FD_ERR_NSS | \
83 FM_FD_ERR_KSO | FM_FD_ERR_IPP | \
84 FM_FD_ERR_PTE | FM_FD_ERR_PHE | \
85 FM_FD_ERR_BLE)
86
87 #define DEFAULT_RX_CUT_END_BYTES 4
88
89 struct fman_port_rx_softc {
90 struct fman_port_softc sc_base;
91 struct fman_port_buffer_pool sc_bpools[FMAN_PORT_MAX_POOLS];
92 };
93
94 static struct ofw_compat_data rx_compats[] = {
95 { "fsl,fman-v2-port-rx", 0 },
96 { "fsl,fman-v3-port-rx", PORT_V3 },
97 { NULL, 0 }
98 };
99
100 static int
fman_port_rx_probe(device_t dev)101 fman_port_rx_probe(device_t dev)
102 {
103
104 if (ofw_bus_search_compatible(dev, rx_compats)->ocd_str == NULL)
105 return (ENXIO);
106
107 device_set_desc(dev, "FMan RX port");
108 return (BUS_PROBE_DEFAULT);
109 }
110
111 static int
fman_port_rx_attach(device_t dev)112 fman_port_rx_attach(device_t dev)
113 {
114 struct fman_port_rx_softc *sc;
115 uintptr_t compat_data;
116 int port_speed;
117
118 sc = device_get_softc(dev);
119 compat_data = ofw_bus_search_compatible(dev, rx_compats)->ocd_data;
120
121 port_speed = 1000;
122 if ((compat_data & PORT_V3) == PORT_V3) {
123 if (OF_hasprop(ofw_bus_get_node(dev), "fsl,fman-10g-port"))
124 port_speed = 10000;
125 } else {
126 int cell = 0;
127 OF_getencprop(ofw_bus_get_node(dev), "cell-index", &cell,
128 sizeof(cell));
129 if (cell > RX_10G_PORT_BASE)
130 port_speed = 10000;
131 }
132
133 return (fman_port_attach_common(dev, &sc->sc_base, port_speed));
134 }
135
136 static int
fman_port_rx_detach(device_t dev)137 fman_port_rx_detach(device_t dev)
138 {
139 struct fman_port_rx_softc *sc = device_get_softc(dev);
140
141 return (fman_port_detach_common(dev, &sc->sc_base));
142 }
143
144 static int
fman_port_rx_config(device_t dev,struct fman_port_params * params)145 fman_port_rx_config(device_t dev, struct fman_port_params *params)
146 {
147 struct fman_port_rx_softc *sc = device_get_softc(dev);
148 struct fman_port_softc *base = &sc->sc_base;
149
150 fman_port_config_common(base, params);
151
152 base->sc_tasks.extra = 0;
153 switch (base->sc_port_speed) {
154 case 10000:
155 if (base->sc_revision_major < 6) {
156 base->sc_tasks.num = 16;
157 base->sc_tasks.extra = 8;
158 } else
159 base->sc_tasks.num = 14;
160 break;
161 case 1000:
162 if (base->sc_revision_major >= 6)
163 base->sc_tasks.num = 4;
164 else {
165 base->sc_tasks.num = 3;
166 base->sc_tasks.extra = 2;
167 }
168 break;
169 default:
170 base->sc_tasks.num = 0;
171 break;
172 }
173
174 if (base->sc_revision_major >= 6) {
175 base->sc_open_dmas.extra = 0;
176 base->sc_open_dmas.num =
177 (base->sc_port_speed == 10000) ? 8 : 2;
178 } else if (base->sc_port_speed == 10000) {
179 base->sc_open_dmas.num = 8;
180 base->sc_open_dmas.extra = 8;
181 } else {
182 base->sc_open_dmas.num = 1;
183 base->sc_open_dmas.extra = 1;
184 }
185
186 if (base->sc_revision_major >= 6)
187 base->sc_fifo_bufs.num =
188 (base->sc_port_speed == 10000) ? 96 : 50;
189 else
190 base->sc_fifo_bufs.num =
191 (base->sc_port_speed == 10000) ? 48 : 45;
192 base->sc_fifo_bufs.extra = 0;
193 base->sc_fifo_bufs.num *= FMAN_BMI_FIFO_UNITS;
194
195 for (int i = 0; i < params->rx_params.num_pools; i++)
196 sc->sc_bpools[i] = params->rx_params.bpools[i];
197
198 /* TODO: buf_margins? See fman_sp_build_buffer_struct */
199 return (0);
200 }
201
202 static int
fman_port_rx_init_bmi(struct fman_port_rx_softc * sc)203 fman_port_rx_init_bmi(struct fman_port_rx_softc *sc)
204 {
205 struct fman_port_softc *base = &sc->sc_base;
206 uint32_t reg;
207
208 /* TODO: Sort the buffer pool list. */
209 /* TODO: Backup pools */
210 /* TODO: Depletion mode */
211 for (int i = 0; i < FMAN_PORT_MAX_POOLS; i++) {
212 if (sc->sc_bpools[i].size != 0) {
213 bus_write_4(base->sc_mem, FMBM_REBMPI(i),
214 REBMPI_VAL | REBMPI_ACE |
215 (sc->sc_bpools[i].bpid << REBMPI_BPID_S) |
216 sc->sc_bpools[i].size);
217 } else
218 bus_write_4(base->sc_mem, FMBM_REBMPI(i), 0);
219 }
220
221 bus_write_4(base->sc_mem, FMBM_RDA, RDA_WOPT);
222
223 bus_write_4(base->sc_mem, FMBM_RFCA,
224 RFCA_OR | RFCA_SYNC_REQ | RFCA_MR_DEF);
225
226 /*
227 * Route the Parser output through KeyGen (HWK), not straight to
228 * BMI enqueue. KG then hands off to BMI-enqueue via its own
229 * default NIA (FMKG_GCR low bits, programmed by fman_kg_init as
230 * NIA_ENG_BMI|NIA_BMI_AC_ENQ_FRAME). Ports with no bound KG
231 * scheme fall through KG's default path to the port's dflt_fqid,
232 * matching the old direct-to-BMI behaviour; ports with a scheme
233 * bound (via fman_kg_alloc_hash_scheme, e.g. from the dpaa_eth
234 * RSS setup) get real hash distribution.
235 */
236 bus_write_4(base->sc_mem, FMBM_RFPNE, NIA_ENG_HWK);
237 bus_write_4(base->sc_mem, FMBM_RFENE,
238 NIA_ENG_QMI_ENQ | NIA_ORDER_RESTORE);
239
240 bus_write_4(base->sc_mem, FMBM_RFQID, base->sc_default_fqid);
241 bus_write_4(base->sc_mem, FMBM_REFQID, base->sc_err_fqid);
242
243 if (base->sc_revision_major < 6)
244 bus_write_4(base->sc_mem, FMBM_RETH, RETH_ETHE);
245
246 /* Errata A006320 makes CFED field bad */
247 if (base->sc_revision_major == 6 && base->sc_revision_minor == 0)
248 /* These are under errata A006320 */;
249 else
250 bus_write_4(base->sc_mem, FMBM_RFED,
251 DEFAULT_RX_CUT_END_BYTES << BMI_RX_FRAME_END_CUT_SHIFT);
252
253 /* Insert internal context ahead of the frame */
254 reg = sizeof(struct fman_internal_context) << REBM_BSM_S;
255 bus_write_4(base->sc_mem, FMBM_REBM, reg);
256 reg = howmany(FMAN_PARSE_RESULT_OFF, 0x10) << RICP_ICIOF_S;
257 reg |= howmany(sizeof(struct fman_internal_context), 0x10);
258 bus_write_4(base->sc_mem, FMBM_RICP, reg);
259
260 bus_write_4(base->sc_mem, FMBM_RFNE, NIA_ENG_HWP);
261 bus_write_4(base->sc_mem, FMBM_RFSDM, FM_FD_ERR_DIS);
262 bus_write_4(base->sc_mem, FMBM_RFSEM, BMI_RX_ERR & ~FM_FD_ERR_DIS);
263
264 return (0);
265 }
266
267 static int
fman_port_rx_init_hwp(struct fman_port_rx_softc * sc)268 fman_port_rx_init_hwp(struct fman_port_rx_softc *sc)
269 {
270 struct fman_port_softc *base = &sc->sc_base;
271 int i;
272
273 bus_write_4(base->sc_mem, HWP_PCAC, HWP_PCAC_PSTOP);
274 for (i = 0; i < 100 &&
275 (bus_read_4(base->sc_mem, HWP_PCAC) & HWP_HXS_PCAC_PSTAT) != 0;
276 i++) {
277 DELAY(10);
278 }
279 if (i == 100) {
280 device_printf(base->sc_dev, "Timeout stopping HW parser\n");
281 return (ENXIO);
282 }
283
284 for (i = 0; i < HWP_HXS_COUNT; i++) {
285 bus_write_4(base->sc_mem, HWP_HXS_SSA(i), 0);
286 bus_write_4(base->sc_mem, HWP_HXS_LCV(i), 0xffffffff);
287 }
288 bus_write_4(base->sc_mem, HWP_HXS_SSA(HWP_HXS_TCP), HXS_SH_PAD_REM);
289 bus_write_4(base->sc_mem, HWP_HXS_SSA(HWP_HXS_UDP), HXS_SH_PAD_REM);
290
291 bus_write_4(base->sc_mem, HWP_PCAC, 0);
292 return (0);
293 }
294
295 static int
fman_port_rx_init(device_t dev)296 fman_port_rx_init(device_t dev)
297 {
298 struct fman_port_rx_softc *sc = device_get_softc(dev);
299 struct fman_port_softc *base = &sc->sc_base;
300 struct fman_port_init_params params;
301 int err;
302
303 params.port_id = base->sc_port_id;
304 params.is_rx_port = true;
305 params.num_tasks = base->sc_tasks.num;
306 params.extra_tasks = base->sc_tasks.extra;
307 params.open_dmas = base->sc_open_dmas.num;
308 params.extra_dmas = base->sc_open_dmas.extra;
309 params.fifo_size = base->sc_fifo_bufs.num;
310 params.extra_fifo_size = base->sc_fifo_bufs.extra;
311 params.max_frame_length = base->sc_max_frame_length;
312 params.deq_pipeline_size = 0;
313
314 /* TODO: verify_size_of_fifo() from Linux driver */
315 err = FMAN_SET_PORT_PARAMS(device_get_parent(dev), ¶ms);
316 if (err != 0)
317 return (err);
318
319 err = fman_port_rx_init_bmi(sc);
320 if (err == 0)
321 err = fman_port_rx_init_hwp(sc);
322 if (err != 0)
323 return (err);
324
325 bus_write_4(base->sc_mem, FMQM_PNEN,
326 NIA_ENG_BMI | NIA_BMI_AC_RELEASE);
327
328 /* TODO: keygen here */
329 return (0);
330 }
331
332 static int
fman_port_rx_disable(device_t dev)333 fman_port_rx_disable(device_t dev)
334 {
335 struct fman_port_rx_softc *sc = device_get_softc(dev);
336 struct fman_port_softc *base = &sc->sc_base;
337 uint32_t reg;
338 int count;
339
340 reg = bus_read_4(base->sc_mem, FMBM_RCFG);
341 bus_write_4(base->sc_mem, FMBM_RCFG, reg & ~BMI_PORT_CFG_EN);
342 for (count = 0; count < 100; count++) {
343 DELAY(10);
344 reg = bus_read_4(base->sc_mem, FMBM_RST);
345 if (!(reg & PNS_DEQ_FD_BSY))
346 break;
347 }
348 if (count == 100)
349 device_printf(base->sc_dev, "Timeout stopping BMI\n");
350
351 return (0);
352 }
353
354 static int
fman_port_rx_enable(device_t dev)355 fman_port_rx_enable(device_t dev)
356 {
357 struct fman_port_rx_softc *sc = device_get_softc(dev);
358 struct fman_port_softc *base = &sc->sc_base;
359 uint32_t reg;
360
361 reg = bus_read_4(base->sc_mem, FMQM_PNC);
362 bus_write_4(base->sc_mem, FMQM_PNC, reg | PNC_EN | PNC_STEN);
363
364 reg = bus_read_4(base->sc_mem, FMBM_RCFG);
365 bus_write_4(base->sc_mem, FMBM_RCFG, reg | BMI_PORT_CFG_EN);
366
367 bus_write_4(base->sc_mem, FMBM_RSTC, RSTC_EN);
368
369 return (0);
370 }
371
372 void
fman_port_rx_use_kg(device_t dev,bool enable)373 fman_port_rx_use_kg(device_t dev, bool enable)
374 {
375 struct fman_port_rx_softc *sc = device_get_softc(dev);
376
377 bus_write_4(sc->sc_base.sc_mem, FMBM_RFPNE,
378 enable ? NIA_ENG_HWK :
379 (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME));
380 }
381
382 static device_method_t fman_port_rx_methods[] = {
383 DEVMETHOD(device_probe, fman_port_rx_probe),
384 DEVMETHOD(device_attach, fman_port_rx_attach),
385 DEVMETHOD(device_detach, fman_port_rx_detach),
386
387 DEVMETHOD(fman_port_config, fman_port_rx_config),
388 DEVMETHOD(fman_port_init, fman_port_rx_init),
389 DEVMETHOD(fman_port_enable, fman_port_rx_enable),
390 DEVMETHOD(fman_port_disable, fman_port_rx_disable),
391
392 DEVMETHOD_END
393 };
394
395 DEFINE_CLASS_0(fman_port_rx, fman_port_rx_driver, fman_port_rx_methods,
396 sizeof(struct fman_port_rx_softc));
397 EARLY_DRIVER_MODULE(fman_port_rx, fman, fman_port_rx_driver, 0, 0,
398 BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE);
399