1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright © 2021-2022 Dmitry Salychev
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 /*
30 * The DPAA2 Management Complex (MC) bus driver.
31 *
32 * MC is a hardware resource manager which can be found in several NXP
33 * SoCs (LX2160A, for example) and provides an access to the specialized
34 * hardware objects used in network-oriented packet processing applications.
35 */
36
37 #include "opt_acpi.h"
38 #include "opt_platform.h"
39
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/bus.h>
43 #include <sys/rman.h>
44 #include <sys/module.h>
45 #include <sys/malloc.h>
46 #include <sys/mutex.h>
47 #include <sys/queue.h>
48
49 #include <vm/vm.h>
50
51 #include <machine/bus.h>
52 #include <machine/resource.h>
53
54 #ifdef DEV_ACPI
55 #include <contrib/dev/acpica/include/acpi.h>
56 #include <dev/acpica/acpivar.h>
57 #endif
58
59 #ifdef FDT
60 #include <dev/ofw/openfirm.h>
61 #include <dev/ofw/ofw_bus.h>
62 #include <dev/ofw/ofw_bus_subr.h>
63 #include <dev/ofw/ofw_pci.h>
64 #endif
65
66 #include "pcib_if.h"
67 #include "pci_if.h"
68
69 #include "dpaa2_mc.h"
70
71 /* Macros to read/write MC registers */
72 #define mcreg_read_4(_sc, _r) bus_read_4(&(_sc)->map[1], (_r))
73 #define mcreg_write_4(_sc, _r, _v) bus_write_4(&(_sc)->map[1], (_r), (_v))
74
75 #define COMPARE_TYPE(t, v) (strncmp((v), (t), strlen((v))) == 0)
76
77 #define IORT_DEVICE_NAME "MCE"
78
79 /* MC Registers */
80 #define MC_REG_GCR1 0x0000u
81 #define MC_REG_GCR2 0x0004u /* TODO: Does it exist? */
82 #define MC_REG_GSR 0x0008u
83 #define MC_REG_FAPR 0x0028u
84
85 /* General Control Register 1 (GCR1) */
86 #define GCR1_P1_STOP 0x80000000u
87 #define GCR1_P2_STOP 0x40000000u
88
89 /* General Status Register (GSR) */
90 #define GSR_HW_ERR(v) (((v) & 0x80000000u) >> 31)
91 #define GSR_CAT_ERR(v) (((v) & 0x40000000u) >> 30)
92 #define GSR_DPL_OFFSET(v) (((v) & 0x3FFFFF00u) >> 8)
93 #define GSR_MCS(v) (((v) & 0xFFu) >> 0)
94
95 /* Timeouts to wait for the MC status. */
96 #define MC_STAT_TIMEOUT 1000u /* us */
97 #define MC_STAT_ATTEMPTS 100u
98
99 /**
100 * @brief Structure to describe a DPAA2 device as a managed resource.
101 */
102 struct dpaa2_mc_devinfo {
103 STAILQ_ENTRY(dpaa2_mc_devinfo) link;
104 device_t dpaa2_dev;
105 uint32_t flags;
106 uint32_t owners;
107 };
108
109 MALLOC_DEFINE(M_DPAA2_MC, "dpaa2_mc", "DPAA2 Management Complex");
110
111 static struct resource_spec dpaa2_mc_spec[] = {
112 { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_UNMAPPED },
113 { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_UNMAPPED | RF_OPTIONAL },
114 RESOURCE_SPEC_END
115 };
116
117 static u_int dpaa2_mc_get_xref(device_t, device_t);
118 static u_int dpaa2_mc_map_id(device_t, device_t, uintptr_t *);
119 static struct rman *dpaa2_mc_rman(device_t, int);
120
121 static int dpaa2_mc_alloc_msi_impl(device_t, device_t, int, int, int *);
122 static int dpaa2_mc_release_msi_impl(device_t, device_t, int, int *);
123 static int dpaa2_mc_map_msi_impl(device_t, device_t, int, uint64_t *,
124 uint32_t *);
125
126 /*
127 * For device interface.
128 */
129
130 int
dpaa2_mc_attach(device_t dev)131 dpaa2_mc_attach(device_t dev)
132 {
133 struct dpaa2_mc_softc *sc;
134 struct resource_map_request req;
135 uint32_t val;
136 int error;
137
138 sc = device_get_softc(dev);
139 sc->dev = dev;
140 sc->msi_allocated = false;
141 sc->msi_owner = NULL;
142
143 error = bus_alloc_resources(sc->dev, dpaa2_mc_spec, sc->res);
144 if (error) {
145 device_printf(dev, "%s: failed to allocate resources\n",
146 __func__);
147 return (ENXIO);
148 }
149
150 if (sc->res[1]) {
151 resource_init_map_request(&req);
152 req.memattr = VM_MEMATTR_DEVICE;
153 error = bus_map_resource(sc->dev, SYS_RES_MEMORY, sc->res[1],
154 &req, &sc->map[1]);
155 if (error) {
156 device_printf(dev, "%s: failed to map control "
157 "registers\n", __func__);
158 dpaa2_mc_detach(dev);
159 return (ENXIO);
160 }
161
162 if (bootverbose)
163 device_printf(dev,
164 "GCR1=0x%x, GCR2=0x%x, GSR=0x%x, FAPR=0x%x\n",
165 mcreg_read_4(sc, MC_REG_GCR1),
166 mcreg_read_4(sc, MC_REG_GCR2),
167 mcreg_read_4(sc, MC_REG_GSR),
168 mcreg_read_4(sc, MC_REG_FAPR));
169
170 /* Reset P1_STOP and P2_STOP bits to resume MC processor. */
171 val = mcreg_read_4(sc, MC_REG_GCR1) &
172 ~(GCR1_P1_STOP | GCR1_P2_STOP);
173 mcreg_write_4(sc, MC_REG_GCR1, val);
174
175 /* Poll MC status. */
176 if (bootverbose)
177 device_printf(dev, "polling MC status...\n");
178 for (int i = 0; i < MC_STAT_ATTEMPTS; i++) {
179 val = mcreg_read_4(sc, MC_REG_GSR);
180 if (GSR_MCS(val) != 0u)
181 break;
182 DELAY(MC_STAT_TIMEOUT);
183 }
184
185 if (bootverbose)
186 device_printf(dev,
187 "GCR1=0x%x, GCR2=0x%x, GSR=0x%x, FAPR=0x%x\n",
188 mcreg_read_4(sc, MC_REG_GCR1),
189 mcreg_read_4(sc, MC_REG_GCR2),
190 mcreg_read_4(sc, MC_REG_GSR),
191 mcreg_read_4(sc, MC_REG_FAPR));
192 }
193
194 /* At least 64 bytes of the command portal should be available. */
195 if (rman_get_size(sc->res[0]) < DPAA2_MCP_MEM_WIDTH) {
196 device_printf(dev, "%s: MC portal memory region too small: "
197 "%jd\n", __func__, rman_get_size(sc->res[0]));
198 dpaa2_mc_detach(dev);
199 return (ENXIO);
200 }
201
202 /* Map MC portal memory resource. */
203 resource_init_map_request(&req);
204 req.memattr = VM_MEMATTR_DEVICE;
205 error = bus_map_resource(sc->dev, SYS_RES_MEMORY, sc->res[0],
206 &req, &sc->map[0]);
207 if (error) {
208 device_printf(dev, "Failed to map MC portal memory\n");
209 dpaa2_mc_detach(dev);
210 return (ENXIO);
211 }
212
213 /* Initialize a resource manager for the DPAA2 I/O objects. */
214 sc->dpio_rman.rm_type = RMAN_ARRAY;
215 sc->dpio_rman.rm_descr = "DPAA2 DPIO objects";
216 error = rman_init(&sc->dpio_rman);
217 if (error) {
218 device_printf(dev, "Failed to initialize a resource manager for "
219 "the DPAA2 I/O objects: error=%d\n", error);
220 dpaa2_mc_detach(dev);
221 return (ENXIO);
222 }
223
224 /* Initialize a resource manager for the DPAA2 buffer pools. */
225 sc->dpbp_rman.rm_type = RMAN_ARRAY;
226 sc->dpbp_rman.rm_descr = "DPAA2 DPBP objects";
227 error = rman_init(&sc->dpbp_rman);
228 if (error) {
229 device_printf(dev, "Failed to initialize a resource manager for "
230 "the DPAA2 buffer pools: error=%d\n", error);
231 dpaa2_mc_detach(dev);
232 return (ENXIO);
233 }
234
235 /* Initialize a resource manager for the DPAA2 concentrators. */
236 sc->dpcon_rman.rm_type = RMAN_ARRAY;
237 sc->dpcon_rman.rm_descr = "DPAA2 DPCON objects";
238 error = rman_init(&sc->dpcon_rman);
239 if (error) {
240 device_printf(dev, "Failed to initialize a resource manager for "
241 "the DPAA2 concentrators: error=%d\n", error);
242 dpaa2_mc_detach(dev);
243 return (ENXIO);
244 }
245
246 /* Initialize a resource manager for the DPAA2 MC portals. */
247 sc->dpmcp_rman.rm_type = RMAN_ARRAY;
248 sc->dpmcp_rman.rm_descr = "DPAA2 DPMCP objects";
249 error = rman_init(&sc->dpmcp_rman);
250 if (error) {
251 device_printf(dev, "Failed to initialize a resource manager for "
252 "the DPAA2 MC portals: error=%d\n", error);
253 dpaa2_mc_detach(dev);
254 return (ENXIO);
255 }
256
257 /* Initialize a list of non-allocatable DPAA2 devices. */
258 mtx_init(&sc->mdev_lock, "MC portal mdev lock", NULL, MTX_DEF);
259 STAILQ_INIT(&sc->mdev_list);
260
261 mtx_init(&sc->msi_lock, "MC MSI lock", NULL, MTX_DEF);
262
263 /*
264 * Add a root resource container as the only child of the bus. All of
265 * the direct descendant containers will be attached to the root one
266 * instead of the MC device.
267 */
268 sc->rcdev = device_add_child(dev, "dpaa2_rc", 0);
269 if (sc->rcdev == NULL) {
270 dpaa2_mc_detach(dev);
271 return (ENXIO);
272 }
273 bus_generic_probe(dev);
274 bus_generic_attach(dev);
275
276 return (0);
277 }
278
279 int
dpaa2_mc_detach(device_t dev)280 dpaa2_mc_detach(device_t dev)
281 {
282 struct dpaa2_mc_softc *sc;
283 struct dpaa2_devinfo *dinfo = NULL;
284 int error;
285
286 bus_generic_detach(dev);
287
288 sc = device_get_softc(dev);
289 if (sc->rcdev)
290 device_delete_child(dev, sc->rcdev);
291 bus_release_resources(dev, dpaa2_mc_spec, sc->res);
292
293 dinfo = device_get_ivars(dev);
294 if (dinfo)
295 free(dinfo, M_DPAA2_MC);
296
297 error = bus_generic_detach(dev);
298 if (error != 0)
299 return (error);
300
301 return (device_delete_children(dev));
302 }
303
304 /*
305 * For bus interface.
306 */
307
308 struct resource *
dpaa2_mc_alloc_resource(device_t mcdev,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)309 dpaa2_mc_alloc_resource(device_t mcdev, device_t child, int type, int *rid,
310 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
311 {
312 struct resource *res;
313 struct rman *rm;
314 int error;
315
316 rm = dpaa2_mc_rman(mcdev, type);
317 if (!rm)
318 return (BUS_ALLOC_RESOURCE(device_get_parent(mcdev), child,
319 type, rid, start, end, count, flags));
320
321 /*
322 * Skip managing DPAA2-specific resource. It must be provided to MC by
323 * calling DPAA2_MC_MANAGE_DEV() beforehand.
324 */
325 if (type <= DPAA2_DEV_MC) {
326 error = rman_manage_region(rm, start, end);
327 if (error) {
328 device_printf(mcdev, "rman_manage_region() failed: "
329 "start=%#jx, end=%#jx, error=%d\n", start, end,
330 error);
331 goto fail;
332 }
333 }
334
335 res = rman_reserve_resource(rm, start, end, count, flags, child);
336 if (!res) {
337 device_printf(mcdev, "rman_reserve_resource() failed: "
338 "start=%#jx, end=%#jx, count=%#jx\n", start, end, count);
339 goto fail;
340 }
341
342 rman_set_rid(res, *rid);
343
344 if (flags & RF_ACTIVE) {
345 if (bus_activate_resource(child, type, *rid, res)) {
346 device_printf(mcdev, "bus_activate_resource() failed: "
347 "rid=%d, res=%#jx\n", *rid, (uintmax_t) res);
348 rman_release_resource(res);
349 goto fail;
350 }
351 }
352
353 return (res);
354 fail:
355 device_printf(mcdev, "%s() failed: type=%d, rid=%d, start=%#jx, "
356 "end=%#jx, count=%#jx, flags=%x\n", __func__, type, *rid, start, end,
357 count, flags);
358 return (NULL);
359 }
360
361 int
dpaa2_mc_adjust_resource(device_t mcdev,device_t child,int type,struct resource * r,rman_res_t start,rman_res_t end)362 dpaa2_mc_adjust_resource(device_t mcdev, device_t child, int type,
363 struct resource *r, rman_res_t start, rman_res_t end)
364 {
365 struct rman *rm;
366
367 rm = dpaa2_mc_rman(mcdev, type);
368 if (rm)
369 return (rman_adjust_resource(r, start, end));
370 return (bus_generic_adjust_resource(mcdev, child, type, r, start, end));
371 }
372
373 int
dpaa2_mc_release_resource(device_t mcdev,device_t child,int type,int rid,struct resource * r)374 dpaa2_mc_release_resource(device_t mcdev, device_t child, int type, int rid,
375 struct resource *r)
376 {
377 struct rman *rm;
378
379 rm = dpaa2_mc_rman(mcdev, type);
380 if (rm) {
381 KASSERT(rman_is_region_manager(r, rm), ("rman mismatch"));
382 rman_release_resource(r);
383 }
384
385 return (bus_generic_release_resource(mcdev, child, type, rid, r));
386 }
387
388 int
dpaa2_mc_activate_resource(device_t mcdev,device_t child,int type,int rid,struct resource * r)389 dpaa2_mc_activate_resource(device_t mcdev, device_t child, int type, int rid,
390 struct resource *r)
391 {
392 int rc;
393
394 if ((rc = rman_activate_resource(r)) != 0)
395 return (rc);
396
397 return (BUS_ACTIVATE_RESOURCE(device_get_parent(mcdev), child, type,
398 rid, r));
399 }
400
401 int
dpaa2_mc_deactivate_resource(device_t mcdev,device_t child,int type,int rid,struct resource * r)402 dpaa2_mc_deactivate_resource(device_t mcdev, device_t child, int type, int rid,
403 struct resource *r)
404 {
405 int rc;
406
407 if ((rc = rman_deactivate_resource(r)) != 0)
408 return (rc);
409
410 return (BUS_DEACTIVATE_RESOURCE(device_get_parent(mcdev), child, type,
411 rid, r));
412 }
413
414 /*
415 * For pseudo-pcib interface.
416 */
417
418 int
dpaa2_mc_alloc_msi(device_t mcdev,device_t child,int count,int maxcount,int * irqs)419 dpaa2_mc_alloc_msi(device_t mcdev, device_t child, int count, int maxcount,
420 int *irqs)
421 {
422 #if defined(INTRNG)
423 return (dpaa2_mc_alloc_msi_impl(mcdev, child, count, maxcount, irqs));
424 #else
425 return (ENXIO);
426 #endif
427 }
428
429 int
dpaa2_mc_release_msi(device_t mcdev,device_t child,int count,int * irqs)430 dpaa2_mc_release_msi(device_t mcdev, device_t child, int count, int *irqs)
431 {
432 #if defined(INTRNG)
433 return (dpaa2_mc_release_msi_impl(mcdev, child, count, irqs));
434 #else
435 return (ENXIO);
436 #endif
437 }
438
439 int
dpaa2_mc_map_msi(device_t mcdev,device_t child,int irq,uint64_t * addr,uint32_t * data)440 dpaa2_mc_map_msi(device_t mcdev, device_t child, int irq, uint64_t *addr,
441 uint32_t *data)
442 {
443 #if defined(INTRNG)
444 return (dpaa2_mc_map_msi_impl(mcdev, child, irq, addr, data));
445 #else
446 return (ENXIO);
447 #endif
448 }
449
450 int
dpaa2_mc_get_id(device_t mcdev,device_t child,enum pci_id_type type,uintptr_t * id)451 dpaa2_mc_get_id(device_t mcdev, device_t child, enum pci_id_type type,
452 uintptr_t *id)
453 {
454 struct dpaa2_devinfo *dinfo;
455
456 dinfo = device_get_ivars(child);
457
458 if (strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
459 return (ENXIO);
460
461 if (type == PCI_ID_MSI)
462 return (dpaa2_mc_map_id(mcdev, child, id));
463
464 *id = dinfo->icid;
465 return (0);
466 }
467
468 /*
469 * For DPAA2 Management Complex bus driver interface.
470 */
471
472 int
dpaa2_mc_manage_dev(device_t mcdev,device_t dpaa2_dev,uint32_t flags)473 dpaa2_mc_manage_dev(device_t mcdev, device_t dpaa2_dev, uint32_t flags)
474 {
475 struct dpaa2_mc_softc *sc;
476 struct dpaa2_devinfo *dinfo;
477 struct dpaa2_mc_devinfo *di;
478 struct rman *rm;
479 int error;
480
481 sc = device_get_softc(mcdev);
482 dinfo = device_get_ivars(dpaa2_dev);
483
484 if (!sc || !dinfo || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
485 return (EINVAL);
486
487 di = malloc(sizeof(*di), M_DPAA2_MC, M_WAITOK | M_ZERO);
488 if (!di)
489 return (ENOMEM);
490 di->dpaa2_dev = dpaa2_dev;
491 di->flags = flags;
492 di->owners = 0;
493
494 /* Append a new managed DPAA2 device to the queue. */
495 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
496 mtx_lock(&sc->mdev_lock);
497 STAILQ_INSERT_TAIL(&sc->mdev_list, di, link);
498 mtx_unlock(&sc->mdev_lock);
499
500 if (flags & DPAA2_MC_DEV_ALLOCATABLE) {
501 /* Select rman based on a type of the DPAA2 device. */
502 rm = dpaa2_mc_rman(mcdev, dinfo->dtype);
503 if (!rm)
504 return (ENOENT);
505 /* Manage DPAA2 device as an allocatable resource. */
506 error = rman_manage_region(rm, (rman_res_t) dpaa2_dev,
507 (rman_res_t) dpaa2_dev);
508 if (error)
509 return (error);
510 }
511
512 return (0);
513 }
514
515 int
dpaa2_mc_get_free_dev(device_t mcdev,device_t * dpaa2_dev,enum dpaa2_dev_type devtype)516 dpaa2_mc_get_free_dev(device_t mcdev, device_t *dpaa2_dev,
517 enum dpaa2_dev_type devtype)
518 {
519 struct rman *rm;
520 rman_res_t start, end;
521 int error;
522
523 if (strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
524 return (EINVAL);
525
526 /* Select resource manager based on a type of the DPAA2 device. */
527 rm = dpaa2_mc_rman(mcdev, devtype);
528 if (!rm)
529 return (ENOENT);
530 /* Find first free DPAA2 device of the given type. */
531 error = rman_first_free_region(rm, &start, &end);
532 if (error)
533 return (error);
534
535 KASSERT(start == end, ("start != end, but should be the same pointer "
536 "to the DPAA2 device: start=%jx, end=%jx", start, end));
537
538 *dpaa2_dev = (device_t) start;
539
540 return (0);
541 }
542
543 int
dpaa2_mc_get_dev(device_t mcdev,device_t * dpaa2_dev,enum dpaa2_dev_type devtype,uint32_t obj_id)544 dpaa2_mc_get_dev(device_t mcdev, device_t *dpaa2_dev,
545 enum dpaa2_dev_type devtype, uint32_t obj_id)
546 {
547 struct dpaa2_mc_softc *sc;
548 struct dpaa2_devinfo *dinfo;
549 struct dpaa2_mc_devinfo *di;
550 int error = ENOENT;
551
552 sc = device_get_softc(mcdev);
553
554 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
555 return (EINVAL);
556
557 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
558 mtx_lock(&sc->mdev_lock);
559
560 STAILQ_FOREACH(di, &sc->mdev_list, link) {
561 dinfo = device_get_ivars(di->dpaa2_dev);
562 if (dinfo->dtype == devtype && dinfo->id == obj_id) {
563 *dpaa2_dev = di->dpaa2_dev;
564 error = 0;
565 break;
566 }
567 }
568
569 mtx_unlock(&sc->mdev_lock);
570
571 return (error);
572 }
573
574 int
dpaa2_mc_get_shared_dev(device_t mcdev,device_t * dpaa2_dev,enum dpaa2_dev_type devtype)575 dpaa2_mc_get_shared_dev(device_t mcdev, device_t *dpaa2_dev,
576 enum dpaa2_dev_type devtype)
577 {
578 struct dpaa2_mc_softc *sc;
579 struct dpaa2_devinfo *dinfo;
580 struct dpaa2_mc_devinfo *di;
581 device_t dev = NULL;
582 uint32_t owners = UINT32_MAX;
583 int error = ENOENT;
584
585 sc = device_get_softc(mcdev);
586
587 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
588 return (EINVAL);
589
590 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
591 mtx_lock(&sc->mdev_lock);
592
593 STAILQ_FOREACH(di, &sc->mdev_list, link) {
594 dinfo = device_get_ivars(di->dpaa2_dev);
595
596 if ((dinfo->dtype == devtype) &&
597 (di->flags & DPAA2_MC_DEV_SHAREABLE) &&
598 (di->owners < owners)) {
599 dev = di->dpaa2_dev;
600 owners = di->owners;
601 }
602 }
603 if (dev) {
604 *dpaa2_dev = dev;
605 error = 0;
606 }
607
608 mtx_unlock(&sc->mdev_lock);
609
610 return (error);
611 }
612
613 int
dpaa2_mc_reserve_dev(device_t mcdev,device_t dpaa2_dev,enum dpaa2_dev_type devtype)614 dpaa2_mc_reserve_dev(device_t mcdev, device_t dpaa2_dev,
615 enum dpaa2_dev_type devtype)
616 {
617 struct dpaa2_mc_softc *sc;
618 struct dpaa2_mc_devinfo *di;
619 int error = ENOENT;
620
621 sc = device_get_softc(mcdev);
622
623 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
624 return (EINVAL);
625
626 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
627 mtx_lock(&sc->mdev_lock);
628
629 STAILQ_FOREACH(di, &sc->mdev_list, link) {
630 if (di->dpaa2_dev == dpaa2_dev &&
631 (di->flags & DPAA2_MC_DEV_SHAREABLE)) {
632 di->owners++;
633 error = 0;
634 break;
635 }
636 }
637
638 mtx_unlock(&sc->mdev_lock);
639
640 return (error);
641 }
642
643 int
dpaa2_mc_release_dev(device_t mcdev,device_t dpaa2_dev,enum dpaa2_dev_type devtype)644 dpaa2_mc_release_dev(device_t mcdev, device_t dpaa2_dev,
645 enum dpaa2_dev_type devtype)
646 {
647 struct dpaa2_mc_softc *sc;
648 struct dpaa2_mc_devinfo *di;
649 int error = ENOENT;
650
651 sc = device_get_softc(mcdev);
652
653 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
654 return (EINVAL);
655
656 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
657 mtx_lock(&sc->mdev_lock);
658
659 STAILQ_FOREACH(di, &sc->mdev_list, link) {
660 if (di->dpaa2_dev == dpaa2_dev &&
661 (di->flags & DPAA2_MC_DEV_SHAREABLE)) {
662 di->owners -= di->owners > 0 ? 1 : 0;
663 error = 0;
664 break;
665 }
666 }
667
668 mtx_unlock(&sc->mdev_lock);
669
670 return (error);
671 }
672
673 /**
674 * @brief Convert DPAA2 device type to string.
675 */
676 const char *
dpaa2_ttos(enum dpaa2_dev_type type)677 dpaa2_ttos(enum dpaa2_dev_type type)
678 {
679 switch (type) {
680 case DPAA2_DEV_MC:
681 return ("mc"); /* NOTE: to print as information only. */
682 case DPAA2_DEV_RC:
683 return ("dprc");
684 case DPAA2_DEV_IO:
685 return ("dpio");
686 case DPAA2_DEV_NI:
687 return ("dpni");
688 case DPAA2_DEV_MCP:
689 return ("dpmcp");
690 case DPAA2_DEV_BP:
691 return ("dpbp");
692 case DPAA2_DEV_CON:
693 return ("dpcon");
694 case DPAA2_DEV_MAC:
695 return ("dpmac");
696 case DPAA2_DEV_MUX:
697 return ("dpdmux");
698 case DPAA2_DEV_SW:
699 return ("dpsw");
700 default:
701 break;
702 }
703 return ("notype");
704 }
705
706 /**
707 * @brief Convert string to DPAA2 device type.
708 */
709 enum dpaa2_dev_type
dpaa2_stot(const char * str)710 dpaa2_stot(const char *str)
711 {
712 if (COMPARE_TYPE(str, "dprc")) {
713 return (DPAA2_DEV_RC);
714 } else if (COMPARE_TYPE(str, "dpio")) {
715 return (DPAA2_DEV_IO);
716 } else if (COMPARE_TYPE(str, "dpni")) {
717 return (DPAA2_DEV_NI);
718 } else if (COMPARE_TYPE(str, "dpmcp")) {
719 return (DPAA2_DEV_MCP);
720 } else if (COMPARE_TYPE(str, "dpbp")) {
721 return (DPAA2_DEV_BP);
722 } else if (COMPARE_TYPE(str, "dpcon")) {
723 return (DPAA2_DEV_CON);
724 } else if (COMPARE_TYPE(str, "dpmac")) {
725 return (DPAA2_DEV_MAC);
726 } else if (COMPARE_TYPE(str, "dpdmux")) {
727 return (DPAA2_DEV_MUX);
728 } else if (COMPARE_TYPE(str, "dpsw")) {
729 return (DPAA2_DEV_SW);
730 }
731
732 return (DPAA2_DEV_NOTYPE);
733 }
734
735 /**
736 * @internal
737 */
738 static u_int
dpaa2_mc_get_xref(device_t mcdev,device_t child)739 dpaa2_mc_get_xref(device_t mcdev, device_t child)
740 {
741 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
742 struct dpaa2_devinfo *dinfo = device_get_ivars(child);
743 #ifdef DEV_ACPI
744 u_int xref, devid;
745 #endif
746 #ifdef FDT
747 phandle_t msi_parent;
748 #endif
749 int error;
750
751 if (sc && dinfo) {
752 #ifdef DEV_ACPI
753 if (sc->acpi_based) {
754 /*
755 * NOTE: The first named component from the IORT table
756 * with the given name (as a substring) will be used.
757 */
758 error = acpi_iort_map_named_msi(IORT_DEVICE_NAME,
759 dinfo->icid, &xref, &devid);
760 if (error)
761 return (0);
762 return (xref);
763 }
764 #endif
765 #ifdef FDT
766 if (!sc->acpi_based) {
767 /* FDT-based driver. */
768 error = ofw_bus_msimap(sc->ofw_node, dinfo->icid,
769 &msi_parent, NULL);
770 if (error)
771 return (0);
772 return ((u_int) msi_parent);
773 }
774 #endif
775 }
776 return (0);
777 }
778
779 /**
780 * @internal
781 */
782 static u_int
dpaa2_mc_map_id(device_t mcdev,device_t child,uintptr_t * id)783 dpaa2_mc_map_id(device_t mcdev, device_t child, uintptr_t *id)
784 {
785 struct dpaa2_devinfo *dinfo;
786 #ifdef DEV_ACPI
787 u_int xref, devid;
788 int error;
789 #endif
790
791 dinfo = device_get_ivars(child);
792 if (dinfo) {
793 /*
794 * The first named components from IORT table with the given
795 * name (as a substring) will be used.
796 */
797 #ifdef DEV_ACPI
798 error = acpi_iort_map_named_msi(IORT_DEVICE_NAME, dinfo->icid,
799 &xref, &devid);
800 if (error == 0)
801 *id = devid;
802 else
803 #endif
804 *id = dinfo->icid; /* RID not in IORT, likely FW bug */
805
806 return (0);
807 }
808 return (ENXIO);
809 }
810
811 /**
812 * @internal
813 * @brief Obtain a resource manager based on the given type of the resource.
814 */
815 static struct rman *
dpaa2_mc_rman(device_t mcdev,int type)816 dpaa2_mc_rman(device_t mcdev, int type)
817 {
818 struct dpaa2_mc_softc *sc;
819
820 sc = device_get_softc(mcdev);
821
822 switch (type) {
823 case DPAA2_DEV_IO:
824 return (&sc->dpio_rman);
825 case DPAA2_DEV_BP:
826 return (&sc->dpbp_rman);
827 case DPAA2_DEV_CON:
828 return (&sc->dpcon_rman);
829 case DPAA2_DEV_MCP:
830 return (&sc->dpmcp_rman);
831 default:
832 break;
833 }
834
835 return (NULL);
836 }
837
838 #if defined(INTRNG) && !defined(IOMMU)
839
840 /**
841 * @internal
842 * @brief Allocates requested number of MSIs.
843 *
844 * NOTE: This function is a part of fallback solution when IOMMU isn't available.
845 * Total number of IRQs is limited to 32.
846 */
847 static int
dpaa2_mc_alloc_msi_impl(device_t mcdev,device_t child,int count,int maxcount,int * irqs)848 dpaa2_mc_alloc_msi_impl(device_t mcdev, device_t child, int count, int maxcount,
849 int *irqs)
850 {
851 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
852 int msi_irqs[DPAA2_MC_MSI_COUNT];
853 int error;
854
855 /* Pre-allocate a bunch of MSIs for MC to be used by its children. */
856 if (!sc->msi_allocated) {
857 error = intr_alloc_msi(mcdev, child, dpaa2_mc_get_xref(mcdev,
858 child), DPAA2_MC_MSI_COUNT, DPAA2_MC_MSI_COUNT, msi_irqs);
859 if (error) {
860 device_printf(mcdev, "failed to pre-allocate %d MSIs: "
861 "error=%d\n", DPAA2_MC_MSI_COUNT, error);
862 return (error);
863 }
864
865 mtx_assert(&sc->msi_lock, MA_NOTOWNED);
866 mtx_lock(&sc->msi_lock);
867 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) {
868 sc->msi[i].child = NULL;
869 sc->msi[i].irq = msi_irqs[i];
870 }
871 sc->msi_owner = child;
872 sc->msi_allocated = true;
873 mtx_unlock(&sc->msi_lock);
874 }
875
876 error = ENOENT;
877
878 /* Find the first free MSIs from the pre-allocated pool. */
879 mtx_assert(&sc->msi_lock, MA_NOTOWNED);
880 mtx_lock(&sc->msi_lock);
881 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) {
882 if (sc->msi[i].child != NULL)
883 continue;
884 error = 0;
885 for (int j = 0; j < count; j++) {
886 if (i + j >= DPAA2_MC_MSI_COUNT) {
887 device_printf(mcdev, "requested %d MSIs exceed "
888 "limit of %d available\n", count,
889 DPAA2_MC_MSI_COUNT);
890 error = E2BIG;
891 break;
892 }
893 sc->msi[i + j].child = child;
894 irqs[j] = sc->msi[i + j].irq;
895 }
896 break;
897 }
898 mtx_unlock(&sc->msi_lock);
899
900 return (error);
901 }
902
903 /**
904 * @internal
905 * @brief Marks IRQs as free in the pre-allocated pool of MSIs.
906 *
907 * NOTE: This function is a part of fallback solution when IOMMU isn't available.
908 * Total number of IRQs is limited to 32.
909 * NOTE: MSIs are kept allocated in the kernel as a part of the pool.
910 */
911 static int
dpaa2_mc_release_msi_impl(device_t mcdev,device_t child,int count,int * irqs)912 dpaa2_mc_release_msi_impl(device_t mcdev, device_t child, int count, int *irqs)
913 {
914 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
915
916 mtx_assert(&sc->msi_lock, MA_NOTOWNED);
917 mtx_lock(&sc->msi_lock);
918 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) {
919 if (sc->msi[i].child != child)
920 continue;
921 for (int j = 0; j < count; j++) {
922 if (sc->msi[i].irq == irqs[j]) {
923 sc->msi[i].child = NULL;
924 break;
925 }
926 }
927 }
928 mtx_unlock(&sc->msi_lock);
929
930 return (0);
931 }
932
933 /**
934 * @internal
935 * @brief Provides address to write to and data according to the given MSI from
936 * the pre-allocated pool.
937 *
938 * NOTE: This function is a part of fallback solution when IOMMU isn't available.
939 * Total number of IRQs is limited to 32.
940 */
941 static int
dpaa2_mc_map_msi_impl(device_t mcdev,device_t child,int irq,uint64_t * addr,uint32_t * data)942 dpaa2_mc_map_msi_impl(device_t mcdev, device_t child, int irq, uint64_t *addr,
943 uint32_t *data)
944 {
945 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
946 int error = EINVAL;
947
948 mtx_assert(&sc->msi_lock, MA_NOTOWNED);
949 mtx_lock(&sc->msi_lock);
950 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) {
951 if (sc->msi[i].child == child && sc->msi[i].irq == irq) {
952 error = 0;
953 break;
954 }
955 }
956 mtx_unlock(&sc->msi_lock);
957 if (error)
958 return (error);
959
960 return (intr_map_msi(mcdev, sc->msi_owner, dpaa2_mc_get_xref(mcdev,
961 sc->msi_owner), irq, addr, data));
962 }
963
964 #endif /* defined(INTRNG) && !defined(IOMMU) */
965
966 static device_method_t dpaa2_mc_methods[] = {
967 DEVMETHOD_END
968 };
969
970 DEFINE_CLASS_0(dpaa2_mc, dpaa2_mc_driver, dpaa2_mc_methods,
971 sizeof(struct dpaa2_mc_softc));
972