xref: /freebsd-13-stable/sys/dev/dpaa2/dpaa2_mc.c (revision 3bc80996974a61a4223eae4c1ccd47b6ee32a48a)
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