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