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/lock.h>
45 #include <sys/module.h>
46 #include <sys/malloc.h>
47 #include <sys/mutex.h>
48 #include <sys/queue.h>
49
50 #include <vm/vm.h>
51
52 #include <machine/bus.h>
53 #include <machine/resource.h>
54
55 #ifdef DEV_ACPI
56 #include <contrib/dev/acpica/include/acpi.h>
57 #include <dev/acpica/acpivar.h>
58 #endif
59
60 #ifdef FDT
61 #include <dev/ofw/openfirm.h>
62 #include <dev/ofw/ofw_bus.h>
63 #include <dev/ofw/ofw_bus_subr.h>
64 #include <dev/ofw/ofw_pci.h>
65 #endif
66
67 #include "pcib_if.h"
68 #include "pci_if.h"
69
70 #include "dpaa2_mc.h"
71
72 /* Macros to read/write MC registers */
73 #define mcreg_read_4(_sc, _r) bus_read_4(&(_sc)->map[1], (_r))
74 #define mcreg_write_4(_sc, _r, _v) bus_write_4(&(_sc)->map[1], (_r), (_v))
75
76 #define IORT_DEVICE_NAME "MCE"
77
78 /* MC Registers */
79 #define MC_REG_GCR1 0x0000u
80 #define MC_REG_GCR2 0x0004u /* TODO: Does it exist? */
81 #define MC_REG_GSR 0x0008u
82 #define MC_REG_FAPR 0x0028u
83
84 /* General Control Register 1 (GCR1) */
85 #define GCR1_P1_STOP 0x80000000u
86 #define GCR1_P2_STOP 0x40000000u
87
88 /* General Status Register (GSR) */
89 #define GSR_HW_ERR(v) (((v) & 0x80000000u) >> 31)
90 #define GSR_CAT_ERR(v) (((v) & 0x40000000u) >> 30)
91 #define GSR_DPL_OFFSET(v) (((v) & 0x3FFFFF00u) >> 8)
92 #define GSR_MCS(v) (((v) & 0xFFu) >> 0)
93
94 /* Timeouts to wait for the MC status. */
95 #define MC_STAT_TIMEOUT 1000u /* us */
96 #define MC_STAT_ATTEMPTS 100u
97
98 /**
99 * @brief Structure to describe a DPAA2 device as a managed resource.
100 */
101 struct dpaa2_mc_devinfo {
102 STAILQ_ENTRY(dpaa2_mc_devinfo) link;
103 device_t dpaa2_dev;
104 uint32_t flags;
105 uint32_t owners;
106 };
107
108 MALLOC_DEFINE(M_DPAA2_MC, "dpaa2_mc", "DPAA2 Management Complex");
109
110 static struct resource_spec dpaa2_mc_spec[] = {
111 { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_UNMAPPED },
112 { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_UNMAPPED | RF_OPTIONAL },
113 RESOURCE_SPEC_END
114 };
115
116 static u_int dpaa2_mc_get_xref(device_t, device_t);
117 static u_int dpaa2_mc_map_id(device_t, device_t, uintptr_t *);
118
119 static int dpaa2_mc_alloc_msi_impl(device_t, device_t, int, int, int *);
120 static int dpaa2_mc_release_msi_impl(device_t, device_t, int, int *);
121 static int dpaa2_mc_map_msi_impl(device_t, device_t, int, uint64_t *,
122 uint32_t *);
123
124 /*
125 * For device interface.
126 */
127
128 int
dpaa2_mc_attach(device_t dev)129 dpaa2_mc_attach(device_t dev)
130 {
131 struct dpaa2_mc_softc *sc;
132 struct resource_map_request req;
133 uint32_t val;
134 int error;
135
136 sc = device_get_softc(dev);
137 sc->dev = dev;
138 sc->msi_allocated = false;
139 sc->msi_owner = NULL;
140
141 error = bus_alloc_resources(sc->dev, dpaa2_mc_spec, sc->res);
142 if (error) {
143 device_printf(dev, "%s: failed to allocate resources\n",
144 __func__);
145 return (ENXIO);
146 }
147
148 if (sc->res[1]) {
149 resource_init_map_request(&req);
150 req.memattr = VM_MEMATTR_DEVICE;
151 error = bus_map_resource(sc->dev, SYS_RES_MEMORY, sc->res[1],
152 &req, &sc->map[1]);
153 if (error) {
154 device_printf(dev, "%s: failed to map control "
155 "registers\n", __func__);
156 dpaa2_mc_detach(dev);
157 return (ENXIO);
158 }
159
160 if (bootverbose)
161 device_printf(dev,
162 "GCR1=0x%x, GCR2=0x%x, GSR=0x%x, FAPR=0x%x\n",
163 mcreg_read_4(sc, MC_REG_GCR1),
164 mcreg_read_4(sc, MC_REG_GCR2),
165 mcreg_read_4(sc, MC_REG_GSR),
166 mcreg_read_4(sc, MC_REG_FAPR));
167
168 /* Reset P1_STOP and P2_STOP bits to resume MC processor. */
169 val = mcreg_read_4(sc, MC_REG_GCR1) &
170 ~(GCR1_P1_STOP | GCR1_P2_STOP);
171 mcreg_write_4(sc, MC_REG_GCR1, val);
172
173 /* Poll MC status. */
174 if (bootverbose)
175 device_printf(dev, "polling MC status...\n");
176 for (int i = 0; i < MC_STAT_ATTEMPTS; i++) {
177 val = mcreg_read_4(sc, MC_REG_GSR);
178 if (GSR_MCS(val) != 0u)
179 break;
180 DELAY(MC_STAT_TIMEOUT);
181 }
182
183 if (bootverbose)
184 device_printf(dev,
185 "GCR1=0x%x, GCR2=0x%x, GSR=0x%x, FAPR=0x%x\n",
186 mcreg_read_4(sc, MC_REG_GCR1),
187 mcreg_read_4(sc, MC_REG_GCR2),
188 mcreg_read_4(sc, MC_REG_GSR),
189 mcreg_read_4(sc, MC_REG_FAPR));
190 }
191
192 /* At least 64 bytes of the command portal should be available. */
193 if (rman_get_size(sc->res[0]) < DPAA2_MCP_MEM_WIDTH) {
194 device_printf(dev, "%s: MC portal memory region too small: "
195 "%jd\n", __func__, rman_get_size(sc->res[0]));
196 dpaa2_mc_detach(dev);
197 return (ENXIO);
198 }
199
200 /* Map MC portal memory resource. */
201 resource_init_map_request(&req);
202 req.memattr = VM_MEMATTR_DEVICE;
203 error = bus_map_resource(sc->dev, SYS_RES_MEMORY, sc->res[0],
204 &req, &sc->map[0]);
205 if (error) {
206 device_printf(dev, "Failed to map MC portal memory\n");
207 dpaa2_mc_detach(dev);
208 return (ENXIO);
209 }
210
211 /* Initialize a resource manager for the DPAA2 I/O objects. */
212 sc->dpio_rman.rm_type = RMAN_ARRAY;
213 sc->dpio_rman.rm_descr = "DPAA2 DPIO objects";
214 error = rman_init(&sc->dpio_rman);
215 if (error) {
216 device_printf(dev, "Failed to initialize a resource manager for "
217 "the DPAA2 I/O objects: error=%d\n", error);
218 dpaa2_mc_detach(dev);
219 return (ENXIO);
220 }
221
222 /* Initialize a resource manager for the DPAA2 buffer pools. */
223 sc->dpbp_rman.rm_type = RMAN_ARRAY;
224 sc->dpbp_rman.rm_descr = "DPAA2 DPBP objects";
225 error = rman_init(&sc->dpbp_rman);
226 if (error) {
227 device_printf(dev, "Failed to initialize a resource manager for "
228 "the DPAA2 buffer pools: error=%d\n", error);
229 dpaa2_mc_detach(dev);
230 return (ENXIO);
231 }
232
233 /* Initialize a resource manager for the DPAA2 concentrators. */
234 sc->dpcon_rman.rm_type = RMAN_ARRAY;
235 sc->dpcon_rman.rm_descr = "DPAA2 DPCON objects";
236 error = rman_init(&sc->dpcon_rman);
237 if (error) {
238 device_printf(dev, "Failed to initialize a resource manager for "
239 "the DPAA2 concentrators: error=%d\n", error);
240 dpaa2_mc_detach(dev);
241 return (ENXIO);
242 }
243
244 /* Initialize a resource manager for the DPAA2 MC portals. */
245 sc->dpmcp_rman.rm_type = RMAN_ARRAY;
246 sc->dpmcp_rman.rm_descr = "DPAA2 DPMCP objects";
247 error = rman_init(&sc->dpmcp_rman);
248 if (error) {
249 device_printf(dev, "Failed to initialize a resource manager for "
250 "the DPAA2 MC portals: error=%d\n", error);
251 dpaa2_mc_detach(dev);
252 return (ENXIO);
253 }
254
255 /* Initialize a list of non-allocatable DPAA2 devices. */
256 mtx_init(&sc->mdev_lock, "MC portal mdev lock", NULL, MTX_DEF);
257 STAILQ_INIT(&sc->mdev_list);
258
259 mtx_init(&sc->msi_lock, "MC MSI lock", NULL, MTX_DEF);
260
261 /*
262 * Add a root resource container as the only child of the bus. All of
263 * the direct descendant containers will be attached to the root one
264 * instead of the MC device.
265 */
266 sc->rcdev = device_add_child(dev, "dpaa2_rc", 0);
267 if (sc->rcdev == NULL) {
268 dpaa2_mc_detach(dev);
269 return (ENXIO);
270 }
271 bus_generic_probe(dev);
272 bus_generic_attach(dev);
273
274 return (0);
275 }
276
277 int
dpaa2_mc_detach(device_t dev)278 dpaa2_mc_detach(device_t dev)
279 {
280 struct dpaa2_mc_softc *sc;
281 struct dpaa2_devinfo *dinfo = NULL;
282 int error;
283
284 error = bus_generic_detach(dev);
285 if (error != 0)
286 return (error);
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 return (device_delete_children(dev));
298 }
299
300 /*
301 * For bus interface.
302 */
303
304 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)305 dpaa2_mc_alloc_resource(device_t mcdev, device_t child, int type, int *rid,
306 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
307 {
308 struct resource *res;
309 struct rman *rm;
310 int error;
311
312 rm = dpaa2_mc_rman(mcdev, type, flags);
313 if (rm == NULL)
314 return (bus_generic_alloc_resource(mcdev, child, type, rid,
315 start, end, count, flags));
316
317 /*
318 * Skip managing DPAA2-specific resource. It must be provided to MC by
319 * calling DPAA2_MC_MANAGE_DEV() beforehand.
320 */
321 if (type <= DPAA2_DEV_MC) {
322 error = rman_manage_region(rm, start, end);
323 if (error) {
324 device_printf(mcdev, "rman_manage_region() failed: "
325 "start=%#jx, end=%#jx, error=%d\n", start, end,
326 error);
327 goto fail;
328 }
329 }
330
331 res = bus_generic_rman_alloc_resource(mcdev, child, type, rid, start,
332 end, count, flags);
333 if (res == NULL)
334 goto fail;
335 return (res);
336 fail:
337 device_printf(mcdev, "%s() failed: type=%d, rid=%d, start=%#jx, "
338 "end=%#jx, count=%#jx, flags=%x\n", __func__, type, *rid, start, end,
339 count, flags);
340 return (NULL);
341 }
342
343 int
dpaa2_mc_adjust_resource(device_t mcdev,device_t child,int type,struct resource * r,rman_res_t start,rman_res_t end)344 dpaa2_mc_adjust_resource(device_t mcdev, device_t child, int type,
345 struct resource *r, rman_res_t start, rman_res_t end)
346 {
347 struct rman *rm;
348
349 rm = dpaa2_mc_rman(mcdev, type, rman_get_flags(r));
350 if (rm)
351 return (bus_generic_rman_adjust_resource(mcdev, child, type, r,
352 start, end));
353 return (bus_generic_adjust_resource(mcdev, child, type, r, start, end));
354 }
355
356 int
dpaa2_mc_release_resource(device_t mcdev,device_t child,int type,int rid,struct resource * r)357 dpaa2_mc_release_resource(device_t mcdev, device_t child, int type, int rid,
358 struct resource *r)
359 {
360 struct rman *rm;
361
362 rm = dpaa2_mc_rman(mcdev, type, rman_get_flags(r));
363 if (rm)
364 return (bus_generic_rman_release_resource(mcdev, child, type,
365 rid, r));
366 return (bus_generic_release_resource(mcdev, child, type, rid, r));
367 }
368
369 int
dpaa2_mc_activate_resource(device_t mcdev,device_t child,int type,int rid,struct resource * r)370 dpaa2_mc_activate_resource(device_t mcdev, device_t child, int type, int rid,
371 struct resource *r)
372 {
373 struct rman *rm;
374
375 rm = dpaa2_mc_rman(mcdev, type, rman_get_flags(r));
376 if (rm)
377 return (bus_generic_rman_activate_resource(mcdev, child, type,
378 rid, r));
379 return (bus_generic_activate_resource(mcdev, child, type, rid, r));
380 }
381
382 int
dpaa2_mc_deactivate_resource(device_t mcdev,device_t child,int type,int rid,struct resource * r)383 dpaa2_mc_deactivate_resource(device_t mcdev, device_t child, int type, int rid,
384 struct resource *r)
385 {
386 struct rman *rm;
387
388 rm = dpaa2_mc_rman(mcdev, type, rman_get_flags(r));
389 if (rm)
390 return (bus_generic_rman_deactivate_resource(mcdev, child, type,
391 rid, r));
392 return (bus_generic_deactivate_resource(mcdev, child, type, rid, r));
393 }
394
395 /*
396 * For pseudo-pcib interface.
397 */
398
399 int
dpaa2_mc_alloc_msi(device_t mcdev,device_t child,int count,int maxcount,int * irqs)400 dpaa2_mc_alloc_msi(device_t mcdev, device_t child, int count, int maxcount,
401 int *irqs)
402 {
403 #if defined(INTRNG)
404 return (dpaa2_mc_alloc_msi_impl(mcdev, child, count, maxcount, irqs));
405 #else
406 return (ENXIO);
407 #endif
408 }
409
410 int
dpaa2_mc_release_msi(device_t mcdev,device_t child,int count,int * irqs)411 dpaa2_mc_release_msi(device_t mcdev, device_t child, int count, int *irqs)
412 {
413 #if defined(INTRNG)
414 return (dpaa2_mc_release_msi_impl(mcdev, child, count, irqs));
415 #else
416 return (ENXIO);
417 #endif
418 }
419
420 int
dpaa2_mc_map_msi(device_t mcdev,device_t child,int irq,uint64_t * addr,uint32_t * data)421 dpaa2_mc_map_msi(device_t mcdev, device_t child, int irq, uint64_t *addr,
422 uint32_t *data)
423 {
424 #if defined(INTRNG)
425 return (dpaa2_mc_map_msi_impl(mcdev, child, irq, addr, data));
426 #else
427 return (ENXIO);
428 #endif
429 }
430
431 int
dpaa2_mc_get_id(device_t mcdev,device_t child,enum pci_id_type type,uintptr_t * id)432 dpaa2_mc_get_id(device_t mcdev, device_t child, enum pci_id_type type,
433 uintptr_t *id)
434 {
435 struct dpaa2_devinfo *dinfo;
436
437 dinfo = device_get_ivars(child);
438
439 if (strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
440 return (ENXIO);
441
442 if (type == PCI_ID_MSI)
443 return (dpaa2_mc_map_id(mcdev, child, id));
444
445 *id = dinfo->icid;
446 return (0);
447 }
448
449 /*
450 * For DPAA2 Management Complex bus driver interface.
451 */
452
453 int
dpaa2_mc_manage_dev(device_t mcdev,device_t dpaa2_dev,uint32_t flags)454 dpaa2_mc_manage_dev(device_t mcdev, device_t dpaa2_dev, uint32_t flags)
455 {
456 struct dpaa2_mc_softc *sc;
457 struct dpaa2_devinfo *dinfo;
458 struct dpaa2_mc_devinfo *di;
459 struct rman *rm;
460 int error;
461
462 sc = device_get_softc(mcdev);
463 dinfo = device_get_ivars(dpaa2_dev);
464
465 if (!sc || !dinfo || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
466 return (EINVAL);
467
468 di = malloc(sizeof(*di), M_DPAA2_MC, M_WAITOK | M_ZERO);
469 di->dpaa2_dev = dpaa2_dev;
470 di->flags = flags;
471 di->owners = 0;
472
473 /* Append a new managed DPAA2 device to the queue. */
474 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
475 mtx_lock(&sc->mdev_lock);
476 STAILQ_INSERT_TAIL(&sc->mdev_list, di, link);
477 mtx_unlock(&sc->mdev_lock);
478
479 if (flags & DPAA2_MC_DEV_ALLOCATABLE) {
480 /* Select rman based on a type of the DPAA2 device. */
481 rm = dpaa2_mc_rman(mcdev, dinfo->dtype, 0);
482 if (!rm)
483 return (ENOENT);
484 /* Manage DPAA2 device as an allocatable resource. */
485 error = rman_manage_region(rm, (rman_res_t) dpaa2_dev,
486 (rman_res_t) dpaa2_dev);
487 if (error)
488 return (error);
489 }
490
491 return (0);
492 }
493
494 int
dpaa2_mc_get_free_dev(device_t mcdev,device_t * dpaa2_dev,enum dpaa2_dev_type devtype)495 dpaa2_mc_get_free_dev(device_t mcdev, device_t *dpaa2_dev,
496 enum dpaa2_dev_type devtype)
497 {
498 struct rman *rm;
499 rman_res_t start, end;
500 int error;
501
502 if (strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
503 return (EINVAL);
504
505 /* Select resource manager based on a type of the DPAA2 device. */
506 rm = dpaa2_mc_rman(mcdev, devtype, 0);
507 if (!rm)
508 return (ENOENT);
509 /* Find first free DPAA2 device of the given type. */
510 error = rman_first_free_region(rm, &start, &end);
511 if (error)
512 return (error);
513
514 KASSERT(start == end, ("start != end, but should be the same pointer "
515 "to the DPAA2 device: start=%jx, end=%jx", start, end));
516
517 *dpaa2_dev = (device_t) start;
518
519 return (0);
520 }
521
522 int
dpaa2_mc_get_dev(device_t mcdev,device_t * dpaa2_dev,enum dpaa2_dev_type devtype,uint32_t obj_id)523 dpaa2_mc_get_dev(device_t mcdev, device_t *dpaa2_dev,
524 enum dpaa2_dev_type devtype, uint32_t obj_id)
525 {
526 struct dpaa2_mc_softc *sc;
527 struct dpaa2_devinfo *dinfo;
528 struct dpaa2_mc_devinfo *di;
529 int error = ENOENT;
530
531 sc = device_get_softc(mcdev);
532
533 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
534 return (EINVAL);
535
536 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
537 mtx_lock(&sc->mdev_lock);
538
539 STAILQ_FOREACH(di, &sc->mdev_list, link) {
540 dinfo = device_get_ivars(di->dpaa2_dev);
541 if (dinfo->dtype == devtype && dinfo->id == obj_id) {
542 *dpaa2_dev = di->dpaa2_dev;
543 error = 0;
544 break;
545 }
546 }
547
548 mtx_unlock(&sc->mdev_lock);
549
550 return (error);
551 }
552
553 int
dpaa2_mc_get_shared_dev(device_t mcdev,device_t * dpaa2_dev,enum dpaa2_dev_type devtype)554 dpaa2_mc_get_shared_dev(device_t mcdev, device_t *dpaa2_dev,
555 enum dpaa2_dev_type devtype)
556 {
557 struct dpaa2_mc_softc *sc;
558 struct dpaa2_devinfo *dinfo;
559 struct dpaa2_mc_devinfo *di;
560 device_t dev = NULL;
561 uint32_t owners = UINT32_MAX;
562 int error = ENOENT;
563
564 sc = device_get_softc(mcdev);
565
566 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
567 return (EINVAL);
568
569 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
570 mtx_lock(&sc->mdev_lock);
571
572 STAILQ_FOREACH(di, &sc->mdev_list, link) {
573 dinfo = device_get_ivars(di->dpaa2_dev);
574
575 if ((dinfo->dtype == devtype) &&
576 (di->flags & DPAA2_MC_DEV_SHAREABLE) &&
577 (di->owners < owners)) {
578 dev = di->dpaa2_dev;
579 owners = di->owners;
580 }
581 }
582 if (dev) {
583 *dpaa2_dev = dev;
584 error = 0;
585 }
586
587 mtx_unlock(&sc->mdev_lock);
588
589 return (error);
590 }
591
592 int
dpaa2_mc_reserve_dev(device_t mcdev,device_t dpaa2_dev,enum dpaa2_dev_type devtype)593 dpaa2_mc_reserve_dev(device_t mcdev, device_t dpaa2_dev,
594 enum dpaa2_dev_type devtype)
595 {
596 struct dpaa2_mc_softc *sc;
597 struct dpaa2_mc_devinfo *di;
598 int error = ENOENT;
599
600 sc = device_get_softc(mcdev);
601
602 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
603 return (EINVAL);
604
605 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
606 mtx_lock(&sc->mdev_lock);
607
608 STAILQ_FOREACH(di, &sc->mdev_list, link) {
609 if (di->dpaa2_dev == dpaa2_dev &&
610 (di->flags & DPAA2_MC_DEV_SHAREABLE)) {
611 di->owners++;
612 error = 0;
613 break;
614 }
615 }
616
617 mtx_unlock(&sc->mdev_lock);
618
619 return (error);
620 }
621
622 int
dpaa2_mc_release_dev(device_t mcdev,device_t dpaa2_dev,enum dpaa2_dev_type devtype)623 dpaa2_mc_release_dev(device_t mcdev, device_t dpaa2_dev,
624 enum dpaa2_dev_type devtype)
625 {
626 struct dpaa2_mc_softc *sc;
627 struct dpaa2_mc_devinfo *di;
628 int error = ENOENT;
629
630 sc = device_get_softc(mcdev);
631
632 if (!sc || strcmp(device_get_name(mcdev), "dpaa2_mc") != 0)
633 return (EINVAL);
634
635 mtx_assert(&sc->mdev_lock, MA_NOTOWNED);
636 mtx_lock(&sc->mdev_lock);
637
638 STAILQ_FOREACH(di, &sc->mdev_list, link) {
639 if (di->dpaa2_dev == dpaa2_dev &&
640 (di->flags & DPAA2_MC_DEV_SHAREABLE)) {
641 di->owners -= di->owners > 0 ? 1 : 0;
642 error = 0;
643 break;
644 }
645 }
646
647 mtx_unlock(&sc->mdev_lock);
648
649 return (error);
650 }
651
652 /**
653 * @internal
654 */
655 static u_int
dpaa2_mc_get_xref(device_t mcdev,device_t child)656 dpaa2_mc_get_xref(device_t mcdev, device_t child)
657 {
658 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
659 struct dpaa2_devinfo *dinfo = device_get_ivars(child);
660 #ifdef DEV_ACPI
661 u_int xref, devid;
662 #endif
663 #ifdef FDT
664 phandle_t msi_parent;
665 #endif
666 int error;
667
668 if (sc && dinfo) {
669 #ifdef DEV_ACPI
670 if (sc->acpi_based) {
671 /*
672 * NOTE: The first named component from the IORT table
673 * with the given name (as a substring) will be used.
674 */
675 error = acpi_iort_map_named_msi(IORT_DEVICE_NAME,
676 dinfo->icid, &xref, &devid);
677 if (error)
678 return (0);
679 return (xref);
680 }
681 #endif
682 #ifdef FDT
683 if (!sc->acpi_based) {
684 /* FDT-based driver. */
685 error = ofw_bus_msimap(sc->ofw_node, dinfo->icid,
686 &msi_parent, NULL);
687 if (error)
688 return (0);
689 return ((u_int) msi_parent);
690 }
691 #endif
692 }
693 return (0);
694 }
695
696 /**
697 * @internal
698 */
699 static u_int
dpaa2_mc_map_id(device_t mcdev,device_t child,uintptr_t * id)700 dpaa2_mc_map_id(device_t mcdev, device_t child, uintptr_t *id)
701 {
702 struct dpaa2_devinfo *dinfo;
703 #ifdef DEV_ACPI
704 u_int xref, devid;
705 int error;
706 #endif
707
708 dinfo = device_get_ivars(child);
709 if (dinfo) {
710 /*
711 * The first named components from IORT table with the given
712 * name (as a substring) will be used.
713 */
714 #ifdef DEV_ACPI
715 error = acpi_iort_map_named_msi(IORT_DEVICE_NAME, dinfo->icid,
716 &xref, &devid);
717 if (error == 0)
718 *id = devid;
719 else
720 #endif
721 *id = dinfo->icid; /* RID not in IORT, likely FW bug */
722
723 return (0);
724 }
725 return (ENXIO);
726 }
727
728 /**
729 * @internal
730 * @brief Obtain a resource manager based on the given type of the resource.
731 */
732 struct rman *
dpaa2_mc_rman(device_t mcdev,int type,u_int flags)733 dpaa2_mc_rman(device_t mcdev, int type, u_int flags)
734 {
735 struct dpaa2_mc_softc *sc;
736
737 sc = device_get_softc(mcdev);
738
739 switch (type) {
740 case DPAA2_DEV_IO:
741 return (&sc->dpio_rman);
742 case DPAA2_DEV_BP:
743 return (&sc->dpbp_rman);
744 case DPAA2_DEV_CON:
745 return (&sc->dpcon_rman);
746 case DPAA2_DEV_MCP:
747 return (&sc->dpmcp_rman);
748 default:
749 break;
750 }
751
752 return (NULL);
753 }
754
755 #if defined(INTRNG) && !defined(IOMMU)
756
757 /**
758 * @internal
759 * @brief Allocates requested number of MSIs.
760 *
761 * NOTE: This function is a part of fallback solution when IOMMU isn't available.
762 * Total number of IRQs is limited to 32.
763 */
764 static int
dpaa2_mc_alloc_msi_impl(device_t mcdev,device_t child,int count,int maxcount,int * irqs)765 dpaa2_mc_alloc_msi_impl(device_t mcdev, device_t child, int count, int maxcount,
766 int *irqs)
767 {
768 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
769 int msi_irqs[DPAA2_MC_MSI_COUNT];
770 int error;
771
772 /* Pre-allocate a bunch of MSIs for MC to be used by its children. */
773 if (!sc->msi_allocated) {
774 error = intr_alloc_msi(mcdev, child, dpaa2_mc_get_xref(mcdev,
775 child), DPAA2_MC_MSI_COUNT, DPAA2_MC_MSI_COUNT, msi_irqs);
776 if (error) {
777 device_printf(mcdev, "failed to pre-allocate %d MSIs: "
778 "error=%d\n", DPAA2_MC_MSI_COUNT, error);
779 return (error);
780 }
781
782 mtx_assert(&sc->msi_lock, MA_NOTOWNED);
783 mtx_lock(&sc->msi_lock);
784 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) {
785 sc->msi[i].child = NULL;
786 sc->msi[i].irq = msi_irqs[i];
787 }
788 sc->msi_owner = child;
789 sc->msi_allocated = true;
790 mtx_unlock(&sc->msi_lock);
791 }
792
793 error = ENOENT;
794
795 /* Find the first free MSIs from the pre-allocated pool. */
796 mtx_assert(&sc->msi_lock, MA_NOTOWNED);
797 mtx_lock(&sc->msi_lock);
798 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) {
799 if (sc->msi[i].child != NULL)
800 continue;
801 error = 0;
802 for (int j = 0; j < count; j++) {
803 if (i + j >= DPAA2_MC_MSI_COUNT) {
804 device_printf(mcdev, "requested %d MSIs exceed "
805 "limit of %d available\n", count,
806 DPAA2_MC_MSI_COUNT);
807 error = E2BIG;
808 break;
809 }
810 sc->msi[i + j].child = child;
811 irqs[j] = sc->msi[i + j].irq;
812 }
813 break;
814 }
815 mtx_unlock(&sc->msi_lock);
816
817 return (error);
818 }
819
820 /**
821 * @internal
822 * @brief Marks IRQs as free in the pre-allocated pool of MSIs.
823 *
824 * NOTE: This function is a part of fallback solution when IOMMU isn't available.
825 * Total number of IRQs is limited to 32.
826 * NOTE: MSIs are kept allocated in the kernel as a part of the pool.
827 */
828 static int
dpaa2_mc_release_msi_impl(device_t mcdev,device_t child,int count,int * irqs)829 dpaa2_mc_release_msi_impl(device_t mcdev, device_t child, int count, int *irqs)
830 {
831 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
832
833 mtx_assert(&sc->msi_lock, MA_NOTOWNED);
834 mtx_lock(&sc->msi_lock);
835 for (int i = 0; i < DPAA2_MC_MSI_COUNT; i++) {
836 if (sc->msi[i].child != child)
837 continue;
838 for (int j = 0; j < count; j++) {
839 if (sc->msi[i].irq == irqs[j]) {
840 sc->msi[i].child = NULL;
841 break;
842 }
843 }
844 }
845 mtx_unlock(&sc->msi_lock);
846
847 return (0);
848 }
849
850 /**
851 * @internal
852 * @brief Provides address to write to and data according to the given MSI from
853 * the pre-allocated pool.
854 *
855 * NOTE: This function is a part of fallback solution when IOMMU isn't available.
856 * Total number of IRQs is limited to 32.
857 */
858 static int
dpaa2_mc_map_msi_impl(device_t mcdev,device_t child,int irq,uint64_t * addr,uint32_t * data)859 dpaa2_mc_map_msi_impl(device_t mcdev, device_t child, int irq, uint64_t *addr,
860 uint32_t *data)
861 {
862 struct dpaa2_mc_softc *sc = device_get_softc(mcdev);
863 int error = EINVAL;
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 if (sc->msi[i].child == child && sc->msi[i].irq == irq) {
869 error = 0;
870 break;
871 }
872 }
873 mtx_unlock(&sc->msi_lock);
874 if (error)
875 return (error);
876
877 return (intr_map_msi(mcdev, sc->msi_owner, dpaa2_mc_get_xref(mcdev,
878 sc->msi_owner), irq, addr, data));
879 }
880
881 #endif /* defined(INTRNG) && !defined(IOMMU) */
882
883 static device_method_t dpaa2_mc_methods[] = {
884 DEVMETHOD_END
885 };
886
887 DEFINE_CLASS_0(dpaa2_mc, dpaa2_mc_driver, dpaa2_mc_methods,
888 sizeof(struct dpaa2_mc_softc));
889