xref: /freebsd/sys/dev/bhnd/bhnd.c (revision f8fd3fb51851136d6e74578405d3ba9b01f223b9)
14ad7e9b0SAdrian Chadd /*-
24ad7e9b0SAdrian Chadd  * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
34ad7e9b0SAdrian Chadd  * All rights reserved.
44ad7e9b0SAdrian Chadd  *
54ad7e9b0SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
64ad7e9b0SAdrian Chadd  * modification, are permitted provided that the following conditions
74ad7e9b0SAdrian Chadd  * are met:
84ad7e9b0SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
94ad7e9b0SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
104ad7e9b0SAdrian Chadd  *    without modification.
114ad7e9b0SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
124ad7e9b0SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
134ad7e9b0SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
144ad7e9b0SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
154ad7e9b0SAdrian Chadd  *
164ad7e9b0SAdrian Chadd  * NO WARRANTY
174ad7e9b0SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
184ad7e9b0SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
194ad7e9b0SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
204ad7e9b0SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
214ad7e9b0SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
224ad7e9b0SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
234ad7e9b0SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
244ad7e9b0SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
254ad7e9b0SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
264ad7e9b0SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
274ad7e9b0SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
284ad7e9b0SAdrian Chadd  */
294ad7e9b0SAdrian Chadd 
304ad7e9b0SAdrian Chadd #include <sys/cdefs.h>
314ad7e9b0SAdrian Chadd __FBSDID("$FreeBSD$");
324ad7e9b0SAdrian Chadd 
334ad7e9b0SAdrian Chadd /*
344ad7e9b0SAdrian Chadd  * Broadcom Home Networking Division (HND) Bus Driver.
354ad7e9b0SAdrian Chadd  *
364ad7e9b0SAdrian Chadd  * The Broadcom HND family of devices consists of both SoCs and host-connected
374ad7e9b0SAdrian Chadd  * networking chipsets containing a common family of Broadcom IP cores,
384ad7e9b0SAdrian Chadd  * including an integrated MIPS and/or ARM cores.
394ad7e9b0SAdrian Chadd  *
404ad7e9b0SAdrian Chadd  * HND devices expose a nearly identical interface whether accessible over a
414ad7e9b0SAdrian Chadd  * native SoC interconnect, or when connected via a host interface such as
424ad7e9b0SAdrian Chadd  * PCIe. As a result, the majority of hardware support code should be re-usable
434ad7e9b0SAdrian Chadd  * across host drivers for HND networking chipsets, as well as FreeBSD support
444ad7e9b0SAdrian Chadd  * for Broadcom MIPS/ARM HND SoCs.
454ad7e9b0SAdrian Chadd  *
464ad7e9b0SAdrian Chadd  * Earlier HND models used the siba(4) on-chip interconnect, while later models
474ad7e9b0SAdrian Chadd  * use bcma(4); the programming model is almost entirely independent
484ad7e9b0SAdrian Chadd  * of the actual underlying interconect.
494ad7e9b0SAdrian Chadd  */
504ad7e9b0SAdrian Chadd 
514ad7e9b0SAdrian Chadd #include <sys/param.h>
524ad7e9b0SAdrian Chadd #include <sys/kernel.h>
534ad7e9b0SAdrian Chadd #include <sys/bus.h>
544ad7e9b0SAdrian Chadd #include <sys/module.h>
554ad7e9b0SAdrian Chadd #include <sys/systm.h>
564ad7e9b0SAdrian Chadd 
574ad7e9b0SAdrian Chadd #include <machine/bus.h>
584ad7e9b0SAdrian Chadd #include <sys/rman.h>
594ad7e9b0SAdrian Chadd #include <machine/resource.h>
604ad7e9b0SAdrian Chadd 
614ad7e9b0SAdrian Chadd #include "bhnd.h"
624ad7e9b0SAdrian Chadd #include "bhndvar.h"
634ad7e9b0SAdrian Chadd 
644ad7e9b0SAdrian Chadd #include "bhnd_nvram_if.h"
654ad7e9b0SAdrian Chadd 
664ad7e9b0SAdrian Chadd MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures");
674ad7e9b0SAdrian Chadd 
684ad7e9b0SAdrian Chadd /**
694ad7e9b0SAdrian Chadd  * bhnd_generic_probe_nomatch() reporting configuration.
704ad7e9b0SAdrian Chadd  */
714ad7e9b0SAdrian Chadd static const struct bhnd_nomatch {
724ad7e9b0SAdrian Chadd 	uint16_t	vendor;		/**< core designer */
734ad7e9b0SAdrian Chadd 	uint16_t	device;		/**< core id */
744ad7e9b0SAdrian Chadd 	bool		if_verbose;	/**< print when bootverbose is set. */
754ad7e9b0SAdrian Chadd } bhnd_nomatch_table[] = {
764ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_OOB_ROUTER,		true	},
774ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_EROM,		true	},
784ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_PL301,		true	},
794ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_APB_BRIDGE,		true	},
804ad7e9b0SAdrian Chadd 	{ BHND_MFGID_ARM,	BHND_COREID_AXI_UNMAPPED,	false	},
814ad7e9b0SAdrian Chadd 
824ad7e9b0SAdrian Chadd 	{ BHND_MFGID_INVALID,	BHND_COREID_INVALID,		false	}
834ad7e9b0SAdrian Chadd };
844ad7e9b0SAdrian Chadd 
854ad7e9b0SAdrian Chadd static device_t	find_nvram_child(device_t dev);
864ad7e9b0SAdrian Chadd 
874ad7e9b0SAdrian Chadd static int	compare_ascending_probe_order(const void *lhs,
884ad7e9b0SAdrian Chadd 		    const void *rhs);
894ad7e9b0SAdrian Chadd static int	compare_descending_probe_order(const void *lhs,
904ad7e9b0SAdrian Chadd 		    const void *rhs);
914ad7e9b0SAdrian Chadd 
924ad7e9b0SAdrian Chadd /**
934ad7e9b0SAdrian Chadd  * Helper function for implementing DEVICE_ATTACH().
944ad7e9b0SAdrian Chadd  *
954ad7e9b0SAdrian Chadd  * This function can be used to implement DEVICE_ATTACH() for bhnd(4)
964ad7e9b0SAdrian Chadd  * bus implementations. It calls device_probe_and_attach() for each
974ad7e9b0SAdrian Chadd  * of the device's children, in order.
984ad7e9b0SAdrian Chadd  */
994ad7e9b0SAdrian Chadd int
1004ad7e9b0SAdrian Chadd bhnd_generic_attach(device_t dev)
1014ad7e9b0SAdrian Chadd {
1024ad7e9b0SAdrian Chadd 	device_t	*devs;
1034ad7e9b0SAdrian Chadd 	int		 ndevs;
1044ad7e9b0SAdrian Chadd 	int		 error;
1054ad7e9b0SAdrian Chadd 
1064ad7e9b0SAdrian Chadd 	if (device_is_attached(dev))
1074ad7e9b0SAdrian Chadd 		return (EBUSY);
1084ad7e9b0SAdrian Chadd 
1094ad7e9b0SAdrian Chadd 	if ((error = device_get_children(dev, &devs, &ndevs)))
1104ad7e9b0SAdrian Chadd 		return (error);
1114ad7e9b0SAdrian Chadd 
1124ad7e9b0SAdrian Chadd 	qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order);
1134ad7e9b0SAdrian Chadd 	for (int i = 0; i < ndevs; i++) {
1144ad7e9b0SAdrian Chadd 		device_t child = devs[i];
1154ad7e9b0SAdrian Chadd 		device_probe_and_attach(child);
1164ad7e9b0SAdrian Chadd 	}
1174ad7e9b0SAdrian Chadd 
1184ad7e9b0SAdrian Chadd 	free(devs, M_TEMP);
1194ad7e9b0SAdrian Chadd 	return (0);
1204ad7e9b0SAdrian Chadd }
1214ad7e9b0SAdrian Chadd 
1224ad7e9b0SAdrian Chadd /**
1234ad7e9b0SAdrian Chadd  * Helper function for implementing DEVICE_DETACH().
1244ad7e9b0SAdrian Chadd  *
1254ad7e9b0SAdrian Chadd  * This function can be used to implement DEVICE_DETACH() for bhnd(4)
1264ad7e9b0SAdrian Chadd  * bus implementations. It calls device_detach() for each
1274ad7e9b0SAdrian Chadd  * of the device's children, in reverse order, terminating if
1284ad7e9b0SAdrian Chadd  * any call to device_detach() fails.
1294ad7e9b0SAdrian Chadd  */
1304ad7e9b0SAdrian Chadd int
1314ad7e9b0SAdrian Chadd bhnd_generic_detach(device_t dev)
1324ad7e9b0SAdrian Chadd {
1334ad7e9b0SAdrian Chadd 	device_t	*devs;
1344ad7e9b0SAdrian Chadd 	int		 ndevs;
1354ad7e9b0SAdrian Chadd 	int		 error;
1364ad7e9b0SAdrian Chadd 
1374ad7e9b0SAdrian Chadd 	if (!device_is_attached(dev))
1384ad7e9b0SAdrian Chadd 		return (EBUSY);
1394ad7e9b0SAdrian Chadd 
1404ad7e9b0SAdrian Chadd 	if ((error = device_get_children(dev, &devs, &ndevs)))
1414ad7e9b0SAdrian Chadd 		return (error);
1424ad7e9b0SAdrian Chadd 
1434ad7e9b0SAdrian Chadd 	/* Detach in the reverse of attach order */
1444ad7e9b0SAdrian Chadd 	qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order);
1454ad7e9b0SAdrian Chadd 	for (int i = 0; i < ndevs; i++) {
1464ad7e9b0SAdrian Chadd 		device_t child = devs[i];
1474ad7e9b0SAdrian Chadd 
1484ad7e9b0SAdrian Chadd 		/* Terminate on first error */
1494ad7e9b0SAdrian Chadd 		if ((error = device_detach(child)))
1504ad7e9b0SAdrian Chadd 			goto cleanup;
1514ad7e9b0SAdrian Chadd 	}
1524ad7e9b0SAdrian Chadd 
1534ad7e9b0SAdrian Chadd cleanup:
1544ad7e9b0SAdrian Chadd 	free(devs, M_TEMP);
1554ad7e9b0SAdrian Chadd 	return (error);
1564ad7e9b0SAdrian Chadd }
1574ad7e9b0SAdrian Chadd 
1584ad7e9b0SAdrian Chadd /**
1594ad7e9b0SAdrian Chadd  * Helper function for implementing DEVICE_SHUTDOWN().
1604ad7e9b0SAdrian Chadd  *
1614ad7e9b0SAdrian Chadd  * This function can be used to implement DEVICE_SHUTDOWN() for bhnd(4)
1624ad7e9b0SAdrian Chadd  * bus implementations. It calls device_shutdown() for each
1634ad7e9b0SAdrian Chadd  * of the device's children, in reverse order, terminating if
1644ad7e9b0SAdrian Chadd  * any call to device_shutdown() fails.
1654ad7e9b0SAdrian Chadd  */
1664ad7e9b0SAdrian Chadd int
1674ad7e9b0SAdrian Chadd bhnd_generic_shutdown(device_t dev)
1684ad7e9b0SAdrian Chadd {
1694ad7e9b0SAdrian Chadd 	device_t	*devs;
1704ad7e9b0SAdrian Chadd 	int		 ndevs;
1714ad7e9b0SAdrian Chadd 	int		 error;
1724ad7e9b0SAdrian Chadd 
1734ad7e9b0SAdrian Chadd 	if (!device_is_attached(dev))
1744ad7e9b0SAdrian Chadd 		return (EBUSY);
1754ad7e9b0SAdrian Chadd 
1764ad7e9b0SAdrian Chadd 	if ((error = device_get_children(dev, &devs, &ndevs)))
1774ad7e9b0SAdrian Chadd 		return (error);
1784ad7e9b0SAdrian Chadd 
1794ad7e9b0SAdrian Chadd 	/* Shutdown in the reverse of attach order */
1804ad7e9b0SAdrian Chadd 	qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order);
1814ad7e9b0SAdrian Chadd 	for (int i = 0; i < ndevs; i++) {
1824ad7e9b0SAdrian Chadd 		device_t child = devs[i];
1834ad7e9b0SAdrian Chadd 
1844ad7e9b0SAdrian Chadd 		/* Terminate on first error */
1854ad7e9b0SAdrian Chadd 		if ((error = device_shutdown(child)))
1864ad7e9b0SAdrian Chadd 			goto cleanup;
1874ad7e9b0SAdrian Chadd 	}
1884ad7e9b0SAdrian Chadd 
1894ad7e9b0SAdrian Chadd cleanup:
1904ad7e9b0SAdrian Chadd 	free(devs, M_TEMP);
1914ad7e9b0SAdrian Chadd 	return (error);
1924ad7e9b0SAdrian Chadd }
1934ad7e9b0SAdrian Chadd 
1944ad7e9b0SAdrian Chadd /**
1954ad7e9b0SAdrian Chadd  * Helper function for implementing DEVICE_RESUME().
1964ad7e9b0SAdrian Chadd  *
1974ad7e9b0SAdrian Chadd  * This function can be used to implement DEVICE_RESUME() for bhnd(4)
1984ad7e9b0SAdrian Chadd  * bus implementations. It calls BUS_RESUME_CHILD() for each
1994ad7e9b0SAdrian Chadd  * of the device's children, in order, terminating if
2004ad7e9b0SAdrian Chadd  * any call to BUS_RESUME_CHILD() fails.
2014ad7e9b0SAdrian Chadd  */
2024ad7e9b0SAdrian Chadd int
2034ad7e9b0SAdrian Chadd bhnd_generic_resume(device_t dev)
2044ad7e9b0SAdrian Chadd {
2054ad7e9b0SAdrian Chadd 	device_t	*devs;
2064ad7e9b0SAdrian Chadd 	int		 ndevs;
2074ad7e9b0SAdrian Chadd 	int		 error;
2084ad7e9b0SAdrian Chadd 
2094ad7e9b0SAdrian Chadd 	if (!device_is_attached(dev))
2104ad7e9b0SAdrian Chadd 		return (EBUSY);
2114ad7e9b0SAdrian Chadd 
2124ad7e9b0SAdrian Chadd 	if ((error = device_get_children(dev, &devs, &ndevs)))
2134ad7e9b0SAdrian Chadd 		return (error);
2144ad7e9b0SAdrian Chadd 
2154ad7e9b0SAdrian Chadd 	qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order);
2164ad7e9b0SAdrian Chadd 	for (int i = 0; i < ndevs; i++) {
2174ad7e9b0SAdrian Chadd 		device_t child = devs[i];
2184ad7e9b0SAdrian Chadd 
2194ad7e9b0SAdrian Chadd 		/* Terminate on first error */
2204ad7e9b0SAdrian Chadd 		if ((error = BUS_RESUME_CHILD(device_get_parent(child), child)))
2214ad7e9b0SAdrian Chadd 			goto cleanup;
2224ad7e9b0SAdrian Chadd 	}
2234ad7e9b0SAdrian Chadd 
2244ad7e9b0SAdrian Chadd cleanup:
2254ad7e9b0SAdrian Chadd 	free(devs, M_TEMP);
2264ad7e9b0SAdrian Chadd 	return (error);
2274ad7e9b0SAdrian Chadd }
2284ad7e9b0SAdrian Chadd 
2294ad7e9b0SAdrian Chadd /**
2304ad7e9b0SAdrian Chadd  * Helper function for implementing DEVICE_SUSPEND().
2314ad7e9b0SAdrian Chadd  *
2324ad7e9b0SAdrian Chadd  * This function can be used to implement DEVICE_SUSPEND() for bhnd(4)
2334ad7e9b0SAdrian Chadd  * bus implementations. It calls BUS_SUSPEND_CHILD() for each
2344ad7e9b0SAdrian Chadd  * of the device's children, in reverse order. If any call to
2354ad7e9b0SAdrian Chadd  * BUS_SUSPEND_CHILD() fails, the suspend operation is terminated and
2364ad7e9b0SAdrian Chadd  * any devices that were suspended are resumed immediately by calling
2374ad7e9b0SAdrian Chadd  * their BUS_RESUME_CHILD() methods.
2384ad7e9b0SAdrian Chadd  */
2394ad7e9b0SAdrian Chadd int
2404ad7e9b0SAdrian Chadd bhnd_generic_suspend(device_t dev)
2414ad7e9b0SAdrian Chadd {
2424ad7e9b0SAdrian Chadd 	device_t	*devs;
2434ad7e9b0SAdrian Chadd 	int		 ndevs;
2444ad7e9b0SAdrian Chadd 	int		 error;
2454ad7e9b0SAdrian Chadd 
2464ad7e9b0SAdrian Chadd 	if (!device_is_attached(dev))
2474ad7e9b0SAdrian Chadd 		return (EBUSY);
2484ad7e9b0SAdrian Chadd 
2494ad7e9b0SAdrian Chadd 	if ((error = device_get_children(dev, &devs, &ndevs)))
2504ad7e9b0SAdrian Chadd 		return (error);
2514ad7e9b0SAdrian Chadd 
2524ad7e9b0SAdrian Chadd 	/* Suspend in the reverse of attach order */
2534ad7e9b0SAdrian Chadd 	qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order);
2544ad7e9b0SAdrian Chadd 	for (int i = 0; i < ndevs; i++) {
2554ad7e9b0SAdrian Chadd 		device_t child = devs[i];
2564ad7e9b0SAdrian Chadd 		error = BUS_SUSPEND_CHILD(device_get_parent(child), child);
2574ad7e9b0SAdrian Chadd 
2584ad7e9b0SAdrian Chadd 		/* On error, resume suspended devices and then terminate */
2594ad7e9b0SAdrian Chadd 		if (error) {
2604ad7e9b0SAdrian Chadd 			for (int j = 0; j < i; j++) {
2614ad7e9b0SAdrian Chadd 				BUS_RESUME_CHILD(device_get_parent(devs[j]),
2624ad7e9b0SAdrian Chadd 				    devs[j]);
2634ad7e9b0SAdrian Chadd 			}
2644ad7e9b0SAdrian Chadd 
2654ad7e9b0SAdrian Chadd 			goto cleanup;
2664ad7e9b0SAdrian Chadd 		}
2674ad7e9b0SAdrian Chadd 	}
2684ad7e9b0SAdrian Chadd 
2694ad7e9b0SAdrian Chadd cleanup:
2704ad7e9b0SAdrian Chadd 	free(devs, M_TEMP);
2714ad7e9b0SAdrian Chadd 	return (error);
2724ad7e9b0SAdrian Chadd }
2734ad7e9b0SAdrian Chadd 
2744ad7e9b0SAdrian Chadd /*
2754ad7e9b0SAdrian Chadd  * Ascending comparison of bhnd device's probe order.
2764ad7e9b0SAdrian Chadd  */
2774ad7e9b0SAdrian Chadd static int
2784ad7e9b0SAdrian Chadd compare_ascending_probe_order(const void *lhs, const void *rhs)
2794ad7e9b0SAdrian Chadd {
2804ad7e9b0SAdrian Chadd 	device_t	ldev, rdev;
2814ad7e9b0SAdrian Chadd 	int		lorder, rorder;
2824ad7e9b0SAdrian Chadd 
2834ad7e9b0SAdrian Chadd 	ldev = (*(const device_t *) lhs);
2844ad7e9b0SAdrian Chadd 	rdev = (*(const device_t *) rhs);
2854ad7e9b0SAdrian Chadd 
2864ad7e9b0SAdrian Chadd 	lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev);
2874ad7e9b0SAdrian Chadd 	rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev);
2884ad7e9b0SAdrian Chadd 
2894ad7e9b0SAdrian Chadd 	if (lorder < rorder) {
2904ad7e9b0SAdrian Chadd 		return (-1);
2914ad7e9b0SAdrian Chadd 	} else if (lorder > rorder) {
2924ad7e9b0SAdrian Chadd 		return (1);
2934ad7e9b0SAdrian Chadd 	} else {
2944ad7e9b0SAdrian Chadd 		return (0);
2954ad7e9b0SAdrian Chadd 	}
2964ad7e9b0SAdrian Chadd }
2974ad7e9b0SAdrian Chadd 
2984ad7e9b0SAdrian Chadd /*
2994ad7e9b0SAdrian Chadd  * Descending comparison of bhnd device's probe order.
3004ad7e9b0SAdrian Chadd  */
3014ad7e9b0SAdrian Chadd static int
3024ad7e9b0SAdrian Chadd compare_descending_probe_order(const void *lhs, const void *rhs)
3034ad7e9b0SAdrian Chadd {
3044ad7e9b0SAdrian Chadd 	return (compare_ascending_probe_order(rhs, lhs));
3054ad7e9b0SAdrian Chadd }
3064ad7e9b0SAdrian Chadd 
3074ad7e9b0SAdrian Chadd /**
3084ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_GET_PROBE_ORDER().
3094ad7e9b0SAdrian Chadd  *
3104ad7e9b0SAdrian Chadd  * This implementation determines probe ordering based on the device's class
3114ad7e9b0SAdrian Chadd  * and other properties, including whether the device is serving as a host
3124ad7e9b0SAdrian Chadd  * bridge.
3134ad7e9b0SAdrian Chadd  */
3144ad7e9b0SAdrian Chadd int
3154ad7e9b0SAdrian Chadd bhnd_generic_get_probe_order(device_t dev, device_t child)
3164ad7e9b0SAdrian Chadd {
3174ad7e9b0SAdrian Chadd 	switch (bhnd_get_class(child)) {
3184ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_CC:
3194ad7e9b0SAdrian Chadd 		return (BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST);
3204ad7e9b0SAdrian Chadd 
3214ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_CC_B:
3224ad7e9b0SAdrian Chadd 		/* fall through */
3234ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_PMU:
3244ad7e9b0SAdrian Chadd 		return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY);
3254ad7e9b0SAdrian Chadd 
3264ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_SOC_ROUTER:
3274ad7e9b0SAdrian Chadd 		return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE);
3284ad7e9b0SAdrian Chadd 
3294ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_SOC_BRIDGE:
3304ad7e9b0SAdrian Chadd 		return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST);
3314ad7e9b0SAdrian Chadd 
3324ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_CPU:
3334ad7e9b0SAdrian Chadd 		return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST);
3344ad7e9b0SAdrian Chadd 
3354ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_RAM:
3364ad7e9b0SAdrian Chadd 		/* fall through */
3374ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_MEMC:
3384ad7e9b0SAdrian Chadd 		return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY);
3394ad7e9b0SAdrian Chadd 
3404ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_NVRAM:
3414ad7e9b0SAdrian Chadd 		return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY);
3424ad7e9b0SAdrian Chadd 
3434ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_PCI:
3444ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_PCIE:
3454ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_PCCARD:
3464ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_ENET:
3474ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_ENET_MAC:
3484ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_ENET_PHY:
3494ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_WLAN:
3504ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_WLAN_MAC:
3514ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_WLAN_PHY:
3524ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_EROM:
3534ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_OTHER:
3544ad7e9b0SAdrian Chadd 	case BHND_DEVCLASS_INVALID:
3554ad7e9b0SAdrian Chadd 		if (bhnd_is_hostb_device(child))
3564ad7e9b0SAdrian Chadd 			return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY);
3574ad7e9b0SAdrian Chadd 
3584ad7e9b0SAdrian Chadd 		return (BHND_PROBE_DEFAULT);
3594ad7e9b0SAdrian Chadd 	}
3604ad7e9b0SAdrian Chadd }
3614ad7e9b0SAdrian Chadd 
3624ad7e9b0SAdrian Chadd /**
3634ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_IS_REGION_VALID().
3644ad7e9b0SAdrian Chadd  *
3654ad7e9b0SAdrian Chadd  * This implementation assumes that port and region numbers are 0-indexed and
3664ad7e9b0SAdrian Chadd  * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and
3674ad7e9b0SAdrian Chadd  * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall
3684ad7e9b0SAdrian Chadd  * within the defined range.
3694ad7e9b0SAdrian Chadd  */
3704ad7e9b0SAdrian Chadd bool
3714ad7e9b0SAdrian Chadd bhnd_generic_is_region_valid(device_t dev, device_t child,
3724ad7e9b0SAdrian Chadd     bhnd_port_type type, u_int port, u_int region)
3734ad7e9b0SAdrian Chadd {
3744ad7e9b0SAdrian Chadd 	if (port >= bhnd_get_port_count(child, type))
3754ad7e9b0SAdrian Chadd 		return (false);
3764ad7e9b0SAdrian Chadd 
3774ad7e9b0SAdrian Chadd 	if (region >= bhnd_get_region_count(child, type, port))
3784ad7e9b0SAdrian Chadd 		return (false);
3794ad7e9b0SAdrian Chadd 
3804ad7e9b0SAdrian Chadd 	return (true);
3814ad7e9b0SAdrian Chadd }
3824ad7e9b0SAdrian Chadd 
3834ad7e9b0SAdrian Chadd /**
3844ad7e9b0SAdrian Chadd  * Find an NVRAM child device on @p dev, if any.
3854ad7e9b0SAdrian Chadd  *
3864ad7e9b0SAdrian Chadd  * @retval device_t An NVRAM device.
3874ad7e9b0SAdrian Chadd  * @retval NULL If no NVRAM device is found.
3884ad7e9b0SAdrian Chadd  */
3894ad7e9b0SAdrian Chadd static device_t
3904ad7e9b0SAdrian Chadd find_nvram_child(device_t dev)
3914ad7e9b0SAdrian Chadd {
3924ad7e9b0SAdrian Chadd 	device_t chipc, nvram;
3934ad7e9b0SAdrian Chadd 
3944ad7e9b0SAdrian Chadd 	/* Look for a directly-attached NVRAM child */
3954ad7e9b0SAdrian Chadd 	nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass),
3964ad7e9b0SAdrian Chadd 	    -1);
3974ad7e9b0SAdrian Chadd 	if (nvram == NULL)
3984ad7e9b0SAdrian Chadd 		return (NULL);
3994ad7e9b0SAdrian Chadd 
4004ad7e9b0SAdrian Chadd 	/* Further checks require a bhnd(4) bus */
4014ad7e9b0SAdrian Chadd 	if (device_get_devclass(dev) != bhnd_devclass)
4024ad7e9b0SAdrian Chadd 		return (NULL);
4034ad7e9b0SAdrian Chadd 
4044ad7e9b0SAdrian Chadd 	/* Look for a ChipCommon-attached OTP device */
4054ad7e9b0SAdrian Chadd 	if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
4064ad7e9b0SAdrian Chadd 		/* Recursively search the ChipCommon device */
4074ad7e9b0SAdrian Chadd 		if ((nvram = find_nvram_child(chipc)) != NULL)
4084ad7e9b0SAdrian Chadd 			return (nvram);
4094ad7e9b0SAdrian Chadd 	}
4104ad7e9b0SAdrian Chadd 
4114ad7e9b0SAdrian Chadd 	/* Not found */
4124ad7e9b0SAdrian Chadd 	return (NULL);
4134ad7e9b0SAdrian Chadd }
4144ad7e9b0SAdrian Chadd 
4154ad7e9b0SAdrian Chadd /**
4164ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_READ_NVRAM_VAR().
4174ad7e9b0SAdrian Chadd  *
4184ad7e9b0SAdrian Chadd  * This implementation searches @p dev for a valid NVRAM device. If no NVRAM
4194ad7e9b0SAdrian Chadd  * child device is found on @p dev, the request is delegated to the
4204ad7e9b0SAdrian Chadd  * BHND_BUS_READ_NVRAM_VAR() method on the parent
4214ad7e9b0SAdrian Chadd  * of @p dev.
4224ad7e9b0SAdrian Chadd  */
4234ad7e9b0SAdrian Chadd int
4244ad7e9b0SAdrian Chadd bhnd_generic_read_nvram_var(device_t dev, device_t child, const char *name,
4254ad7e9b0SAdrian Chadd     void *buf, size_t *size)
4264ad7e9b0SAdrian Chadd {
4274ad7e9b0SAdrian Chadd 	device_t nvram;
4284ad7e9b0SAdrian Chadd 
4294ad7e9b0SAdrian Chadd 	/* Try to find an NVRAM device applicable to @p child */
4304ad7e9b0SAdrian Chadd 	if ((nvram = find_nvram_child(dev)) == NULL)
4314ad7e9b0SAdrian Chadd 		return (BHND_BUS_READ_NVRAM_VAR(device_get_parent(dev), child,
4324ad7e9b0SAdrian Chadd 		    name, buf, size));
4334ad7e9b0SAdrian Chadd 
4344ad7e9b0SAdrian Chadd 	return BHND_NVRAM_GETVAR(nvram, name, buf, size);
4354ad7e9b0SAdrian Chadd }
4364ad7e9b0SAdrian Chadd 
4374ad7e9b0SAdrian Chadd /**
4384ad7e9b0SAdrian Chadd  * Helper function for implementing BUS_PRINT_CHILD().
4394ad7e9b0SAdrian Chadd  *
4404ad7e9b0SAdrian Chadd  * This implementation requests the device's struct resource_list via
4414ad7e9b0SAdrian Chadd  * BUS_GET_RESOURCE_LIST.
4424ad7e9b0SAdrian Chadd  */
4434ad7e9b0SAdrian Chadd int
4444ad7e9b0SAdrian Chadd bhnd_generic_print_child(device_t dev, device_t child)
4454ad7e9b0SAdrian Chadd {
4464ad7e9b0SAdrian Chadd 	struct resource_list	*rl;
4474ad7e9b0SAdrian Chadd 	int			retval = 0;
4484ad7e9b0SAdrian Chadd 
4494ad7e9b0SAdrian Chadd 	retval += bus_print_child_header(dev, child);
4504ad7e9b0SAdrian Chadd 
4514ad7e9b0SAdrian Chadd 	rl = BUS_GET_RESOURCE_LIST(dev, child);
4524ad7e9b0SAdrian Chadd 	if (rl != NULL) {
4534ad7e9b0SAdrian Chadd 		retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
454*f8fd3fb5SJustin Hibbits 		    "%#jx");
4554ad7e9b0SAdrian Chadd 	}
4564ad7e9b0SAdrian Chadd 
4574ad7e9b0SAdrian Chadd 	retval += printf(" at core %u", bhnd_get_core_index(child));
4584ad7e9b0SAdrian Chadd 
4594ad7e9b0SAdrian Chadd 	retval += bus_print_child_domain(dev, child);
4604ad7e9b0SAdrian Chadd 	retval += bus_print_child_footer(dev, child);
4614ad7e9b0SAdrian Chadd 
4624ad7e9b0SAdrian Chadd 	return (retval);
4634ad7e9b0SAdrian Chadd }
4644ad7e9b0SAdrian Chadd 
4654ad7e9b0SAdrian Chadd /**
4664ad7e9b0SAdrian Chadd  * Helper function for implementing BUS_PRINT_CHILD().
4674ad7e9b0SAdrian Chadd  *
4684ad7e9b0SAdrian Chadd  * This implementation requests the device's struct resource_list via
4694ad7e9b0SAdrian Chadd  * BUS_GET_RESOURCE_LIST.
4704ad7e9b0SAdrian Chadd  */
4714ad7e9b0SAdrian Chadd void
4724ad7e9b0SAdrian Chadd bhnd_generic_probe_nomatch(device_t dev, device_t child)
4734ad7e9b0SAdrian Chadd {
4744ad7e9b0SAdrian Chadd 	struct resource_list		*rl;
4754ad7e9b0SAdrian Chadd 	const struct bhnd_nomatch	*nm;
4764ad7e9b0SAdrian Chadd 	bool				 report;
4774ad7e9b0SAdrian Chadd 
4784ad7e9b0SAdrian Chadd 	/* Fetch reporting configuration for this device */
4794ad7e9b0SAdrian Chadd 	report = true;
4804ad7e9b0SAdrian Chadd 	for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) {
4814ad7e9b0SAdrian Chadd 		if (nm->vendor != bhnd_get_vendor(child))
4824ad7e9b0SAdrian Chadd 			continue;
4834ad7e9b0SAdrian Chadd 
4844ad7e9b0SAdrian Chadd 		if (nm->device != bhnd_get_device(child))
4854ad7e9b0SAdrian Chadd 			continue;
4864ad7e9b0SAdrian Chadd 
4874ad7e9b0SAdrian Chadd 		report = false;
4884ad7e9b0SAdrian Chadd 		if (bootverbose && nm->if_verbose)
4894ad7e9b0SAdrian Chadd 			report = true;
4904ad7e9b0SAdrian Chadd 		break;
4914ad7e9b0SAdrian Chadd 	}
4924ad7e9b0SAdrian Chadd 
4934ad7e9b0SAdrian Chadd 	if (!report)
4944ad7e9b0SAdrian Chadd 		return;
4954ad7e9b0SAdrian Chadd 
4964ad7e9b0SAdrian Chadd 	/* Print the non-matched device info */
4974ad7e9b0SAdrian Chadd 	device_printf(dev, "<%s %s>", bhnd_get_vendor_name(child),
4984ad7e9b0SAdrian Chadd 		bhnd_get_device_name(child));
4994ad7e9b0SAdrian Chadd 
5004ad7e9b0SAdrian Chadd 	rl = BUS_GET_RESOURCE_LIST(dev, child);
5014ad7e9b0SAdrian Chadd 	if (rl != NULL)
502*f8fd3fb5SJustin Hibbits 		resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
5034ad7e9b0SAdrian Chadd 
5044ad7e9b0SAdrian Chadd 	printf(" at core %u (no driver attached)\n",
5054ad7e9b0SAdrian Chadd 	    bhnd_get_core_index(child));
5064ad7e9b0SAdrian Chadd }
5074ad7e9b0SAdrian Chadd 
5084ad7e9b0SAdrian Chadd /**
5094ad7e9b0SAdrian Chadd  * Default implementation of BUS_CHILD_PNPINFO_STR().
5104ad7e9b0SAdrian Chadd  */
5114ad7e9b0SAdrian Chadd static int
5124ad7e9b0SAdrian Chadd bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf,
5134ad7e9b0SAdrian Chadd     size_t buflen)
5144ad7e9b0SAdrian Chadd {
5154ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev) {
5164ad7e9b0SAdrian Chadd 		return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child,
5174ad7e9b0SAdrian Chadd 		    buf, buflen));
5184ad7e9b0SAdrian Chadd 	}
5194ad7e9b0SAdrian Chadd 
5204ad7e9b0SAdrian Chadd 	snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx",
5214ad7e9b0SAdrian Chadd 	    bhnd_get_vendor(child), bhnd_get_device(child),
5224ad7e9b0SAdrian Chadd 	    bhnd_get_hwrev(child));
5234ad7e9b0SAdrian Chadd 
5244ad7e9b0SAdrian Chadd 	return (0);
5254ad7e9b0SAdrian Chadd }
5264ad7e9b0SAdrian Chadd 
5274ad7e9b0SAdrian Chadd /**
5284ad7e9b0SAdrian Chadd  * Default implementation of implementing BUS_PRINT_CHILD().
5294ad7e9b0SAdrian Chadd  */
5304ad7e9b0SAdrian Chadd static int
5314ad7e9b0SAdrian Chadd bhnd_child_location_str(device_t dev, device_t child, char *buf,
5324ad7e9b0SAdrian Chadd     size_t buflen)
5334ad7e9b0SAdrian Chadd {
5344ad7e9b0SAdrian Chadd 	bhnd_addr_t	addr;
5354ad7e9b0SAdrian Chadd 	bhnd_size_t	size;
5364ad7e9b0SAdrian Chadd 
5374ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev) {
5384ad7e9b0SAdrian Chadd 		return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child,
5394ad7e9b0SAdrian Chadd 		    buf, buflen));
5404ad7e9b0SAdrian Chadd 	}
5414ad7e9b0SAdrian Chadd 
5424ad7e9b0SAdrian Chadd 
5434ad7e9b0SAdrian Chadd 	if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) {
5444ad7e9b0SAdrian Chadd 		/* No device default port/region */
5454ad7e9b0SAdrian Chadd 		if (buflen > 0)
5464ad7e9b0SAdrian Chadd 			*buf = '\0';
5474ad7e9b0SAdrian Chadd 		return (0);
5484ad7e9b0SAdrian Chadd 	}
5494ad7e9b0SAdrian Chadd 
5504ad7e9b0SAdrian Chadd 	snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr);
5514ad7e9b0SAdrian Chadd 	return (0);
5524ad7e9b0SAdrian Chadd }
5534ad7e9b0SAdrian Chadd 
5544ad7e9b0SAdrian Chadd /**
5554ad7e9b0SAdrian Chadd  * Helper function for implementing BUS_SUSPEND_CHILD().
5564ad7e9b0SAdrian Chadd  *
5574ad7e9b0SAdrian Chadd  * TODO: Power management
5584ad7e9b0SAdrian Chadd  *
5594ad7e9b0SAdrian Chadd  * If @p child is not a direct child of @p dev, suspension is delegated to
5604ad7e9b0SAdrian Chadd  * the @p dev parent.
5614ad7e9b0SAdrian Chadd  */
5624ad7e9b0SAdrian Chadd int
5634ad7e9b0SAdrian Chadd bhnd_generic_suspend_child(device_t dev, device_t child)
5644ad7e9b0SAdrian Chadd {
5654ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
5664ad7e9b0SAdrian Chadd 		BUS_SUSPEND_CHILD(device_get_parent(dev), child);
5674ad7e9b0SAdrian Chadd 
5684ad7e9b0SAdrian Chadd 	return bus_generic_suspend_child(dev, child);
5694ad7e9b0SAdrian Chadd }
5704ad7e9b0SAdrian Chadd 
5714ad7e9b0SAdrian Chadd /**
5724ad7e9b0SAdrian Chadd  * Helper function for implementing BUS_RESUME_CHILD().
5734ad7e9b0SAdrian Chadd  *
5744ad7e9b0SAdrian Chadd  * TODO: Power management
5754ad7e9b0SAdrian Chadd  *
5764ad7e9b0SAdrian Chadd  * If @p child is not a direct child of @p dev, suspension is delegated to
5774ad7e9b0SAdrian Chadd  * the @p dev parent.
5784ad7e9b0SAdrian Chadd  */
5794ad7e9b0SAdrian Chadd int
5804ad7e9b0SAdrian Chadd bhnd_generic_resume_child(device_t dev, device_t child)
5814ad7e9b0SAdrian Chadd {
5824ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
5834ad7e9b0SAdrian Chadd 		BUS_RESUME_CHILD(device_get_parent(dev), child);
5844ad7e9b0SAdrian Chadd 
5854ad7e9b0SAdrian Chadd 	return bus_generic_resume_child(dev, child);
5864ad7e9b0SAdrian Chadd }
5874ad7e9b0SAdrian Chadd 
5884ad7e9b0SAdrian Chadd /**
5894ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE().
5904ad7e9b0SAdrian Chadd  *
5914ad7e9b0SAdrian Chadd  * If a parent device is available, this implementation delegates the
5924ad7e9b0SAdrian Chadd  * request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev.
5934ad7e9b0SAdrian Chadd  *
5944ad7e9b0SAdrian Chadd  * If no parent device is available (i.e. on a the bus root), false
5954ad7e9b0SAdrian Chadd  * is returned.
5964ad7e9b0SAdrian Chadd  */
5974ad7e9b0SAdrian Chadd bool
5984ad7e9b0SAdrian Chadd bhnd_generic_is_hostb_device(device_t dev, device_t child) {
5994ad7e9b0SAdrian Chadd 	if (device_get_parent(dev) != NULL)
6004ad7e9b0SAdrian Chadd 		return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev),
6014ad7e9b0SAdrian Chadd 		    child));
6024ad7e9b0SAdrian Chadd 
6034ad7e9b0SAdrian Chadd 	return (false);
6044ad7e9b0SAdrian Chadd }
6054ad7e9b0SAdrian Chadd 
6064ad7e9b0SAdrian Chadd /**
6074ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_IS_HW_DISABLED().
6084ad7e9b0SAdrian Chadd  *
6094ad7e9b0SAdrian Chadd  * If a parent device is available, this implementation delegates the
6104ad7e9b0SAdrian Chadd  * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
6114ad7e9b0SAdrian Chadd  *
6124ad7e9b0SAdrian Chadd  * If no parent device is available (i.e. on a the bus root), the hardware
6134ad7e9b0SAdrian Chadd  * is assumed to be usable and false is returned.
6144ad7e9b0SAdrian Chadd  */
6154ad7e9b0SAdrian Chadd bool
6164ad7e9b0SAdrian Chadd bhnd_generic_is_hw_disabled(device_t dev, device_t child)
6174ad7e9b0SAdrian Chadd {
6184ad7e9b0SAdrian Chadd 	if (device_get_parent(dev) != NULL)
6194ad7e9b0SAdrian Chadd 		return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
6204ad7e9b0SAdrian Chadd 
6214ad7e9b0SAdrian Chadd 	return (false);
6224ad7e9b0SAdrian Chadd }
6234ad7e9b0SAdrian Chadd 
6244ad7e9b0SAdrian Chadd /**
6254ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_GET_CHIPID().
6264ad7e9b0SAdrian Chadd  *
6274ad7e9b0SAdrian Chadd  * This implementation delegates the request to the BHND_BUS_GET_CHIPID()
6284ad7e9b0SAdrian Chadd  * method on the parent of @p dev.
6294ad7e9b0SAdrian Chadd  */
6304ad7e9b0SAdrian Chadd const struct bhnd_chipid *
6314ad7e9b0SAdrian Chadd bhnd_generic_get_chipid(device_t dev, device_t child) {
6324ad7e9b0SAdrian Chadd 	return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
6334ad7e9b0SAdrian Chadd }
6344ad7e9b0SAdrian Chadd 
6354ad7e9b0SAdrian Chadd /**
6364ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
6374ad7e9b0SAdrian Chadd  *
6384ad7e9b0SAdrian Chadd  * This simple implementation of BHND_BUS_ALLOC_RESOURCE() determines
6394ad7e9b0SAdrian Chadd  * any default values via BUS_GET_RESOURCE_LIST(), and calls
6404ad7e9b0SAdrian Chadd  * BHND_BUS_ALLOC_RESOURCE() method of the parent of @p dev.
6414ad7e9b0SAdrian Chadd  *
6424ad7e9b0SAdrian Chadd  * If no parent device is available, the request is instead delegated to
6434ad7e9b0SAdrian Chadd  * BUS_ALLOC_RESOURCE().
6444ad7e9b0SAdrian Chadd  */
6454ad7e9b0SAdrian Chadd struct bhnd_resource *
6464ad7e9b0SAdrian Chadd bhnd_generic_alloc_bhnd_resource(device_t dev, device_t child, int type,
6474ad7e9b0SAdrian Chadd 	int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
6484ad7e9b0SAdrian Chadd 	u_int flags)
6494ad7e9b0SAdrian Chadd {
6504ad7e9b0SAdrian Chadd 	struct bhnd_resource		*r;
6514ad7e9b0SAdrian Chadd 	struct resource_list		*rl;
6524ad7e9b0SAdrian Chadd 	struct resource_list_entry	*rle;
6534ad7e9b0SAdrian Chadd 	bool				 isdefault;
6544ad7e9b0SAdrian Chadd 	bool				 passthrough;
6554ad7e9b0SAdrian Chadd 
6564ad7e9b0SAdrian Chadd 	passthrough = (device_get_parent(child) != dev);
65782ed3cb0SJustin Hibbits 	isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
6584ad7e9b0SAdrian Chadd 
6594ad7e9b0SAdrian Chadd 	/* the default RID must always be the first device port/region. */
6604ad7e9b0SAdrian Chadd 	if (!passthrough && *rid == 0) {
6614ad7e9b0SAdrian Chadd 		int rid0 = bhnd_get_port_rid(child, BHND_PORT_DEVICE, 0, 0);
6624ad7e9b0SAdrian Chadd 		KASSERT(*rid == rid0,
6634ad7e9b0SAdrian Chadd 		    ("rid 0 does not map to the first device port (%d)", rid0));
6644ad7e9b0SAdrian Chadd 	}
6654ad7e9b0SAdrian Chadd 
6664ad7e9b0SAdrian Chadd 	/* Determine locally-known defaults before delegating the request. */
6674ad7e9b0SAdrian Chadd 	if (!passthrough && isdefault) {
6684ad7e9b0SAdrian Chadd 		/* fetch resource list from child's bus */
6694ad7e9b0SAdrian Chadd 		rl = BUS_GET_RESOURCE_LIST(dev, child);
6704ad7e9b0SAdrian Chadd 		if (rl == NULL)
6714ad7e9b0SAdrian Chadd 			return (NULL); /* no resource list */
6724ad7e9b0SAdrian Chadd 
6734ad7e9b0SAdrian Chadd 		/* look for matching type/rid pair */
6744ad7e9b0SAdrian Chadd 		rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child),
6754ad7e9b0SAdrian Chadd 		    type, *rid);
6764ad7e9b0SAdrian Chadd 		if (rle == NULL)
6774ad7e9b0SAdrian Chadd 			return (NULL);
6784ad7e9b0SAdrian Chadd 
6794ad7e9b0SAdrian Chadd 		/* set default values */
6804ad7e9b0SAdrian Chadd 		start = rle->start;
6814ad7e9b0SAdrian Chadd 		end = rle->end;
6824ad7e9b0SAdrian Chadd 		count = ulmax(count, rle->count);
6834ad7e9b0SAdrian Chadd 	}
6844ad7e9b0SAdrian Chadd 
6854ad7e9b0SAdrian Chadd 	/* Try to delegate to our parent. */
6864ad7e9b0SAdrian Chadd 	if (device_get_parent(dev) != NULL) {
6874ad7e9b0SAdrian Chadd 		return (BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
6884ad7e9b0SAdrian Chadd 		    type, rid, start, end, count, flags));
6894ad7e9b0SAdrian Chadd 	}
6904ad7e9b0SAdrian Chadd 
6914ad7e9b0SAdrian Chadd 	/* If this is the bus root, use a real bus-allocated resource */
6924ad7e9b0SAdrian Chadd 	r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
6934ad7e9b0SAdrian Chadd 	if (r == NULL)
6944ad7e9b0SAdrian Chadd 		return NULL;
6954ad7e9b0SAdrian Chadd 
6964ad7e9b0SAdrian Chadd 	/* Allocate the bus resource, marking it as 'direct' (not requiring
6974ad7e9b0SAdrian Chadd 	 * any bus window remapping to perform I/O) */
6984ad7e9b0SAdrian Chadd 	r->direct = true;
6994ad7e9b0SAdrian Chadd 	r->res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end,
7004ad7e9b0SAdrian Chadd 	    count, flags);
7014ad7e9b0SAdrian Chadd 
7024ad7e9b0SAdrian Chadd 	if (r->res == NULL) {
7034ad7e9b0SAdrian Chadd 		free(r, M_BHND);
7044ad7e9b0SAdrian Chadd 		return NULL;
7054ad7e9b0SAdrian Chadd 	}
7064ad7e9b0SAdrian Chadd 
7074ad7e9b0SAdrian Chadd 	return (r);
7084ad7e9b0SAdrian Chadd }
7094ad7e9b0SAdrian Chadd 
7104ad7e9b0SAdrian Chadd /**
7114ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
7124ad7e9b0SAdrian Chadd  *
7134ad7e9b0SAdrian Chadd  * This simple implementation of BHND_BUS_RELEASE_RESOURCE() simply calls the
7144ad7e9b0SAdrian Chadd  * BHND_BUS_RELEASE_RESOURCE() method of the parent of @p dev.
7154ad7e9b0SAdrian Chadd  *
7164ad7e9b0SAdrian Chadd  * If no parent device is available, the request is delegated to
7174ad7e9b0SAdrian Chadd  * BUS_RELEASE_RESOURCE().
7184ad7e9b0SAdrian Chadd  */
7194ad7e9b0SAdrian Chadd int
7204ad7e9b0SAdrian Chadd bhnd_generic_release_bhnd_resource(device_t dev, device_t child, int type,
7214ad7e9b0SAdrian Chadd     int rid, struct bhnd_resource *r)
7224ad7e9b0SAdrian Chadd {
7234ad7e9b0SAdrian Chadd 	int error;
7244ad7e9b0SAdrian Chadd 
7254ad7e9b0SAdrian Chadd 	/* Try to delegate to the parent. */
7264ad7e9b0SAdrian Chadd 	if (device_get_parent(dev) != NULL)
7274ad7e9b0SAdrian Chadd 		return (BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
7284ad7e9b0SAdrian Chadd 		    type, rid, r));
7294ad7e9b0SAdrian Chadd 
7304ad7e9b0SAdrian Chadd 	/* Release the resource directly */
7314ad7e9b0SAdrian Chadd 	if (!r->direct) {
7324ad7e9b0SAdrian Chadd 		panic("bhnd indirect resource released without "
7334ad7e9b0SAdrian Chadd 		    "bhnd parent bus");
7344ad7e9b0SAdrian Chadd 	}
7354ad7e9b0SAdrian Chadd 
7364ad7e9b0SAdrian Chadd 	error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res);
7374ad7e9b0SAdrian Chadd 	if (error)
7384ad7e9b0SAdrian Chadd 		return (error);
7394ad7e9b0SAdrian Chadd 
7404ad7e9b0SAdrian Chadd 	free(r, M_BHND);
7414ad7e9b0SAdrian Chadd 	return (0);
7424ad7e9b0SAdrian Chadd }
7434ad7e9b0SAdrian Chadd 
7444ad7e9b0SAdrian Chadd /**
7454ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
7464ad7e9b0SAdrian Chadd  *
7474ad7e9b0SAdrian Chadd  * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
7484ad7e9b0SAdrian Chadd  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
7494ad7e9b0SAdrian Chadd  *
7504ad7e9b0SAdrian Chadd  * If no parent device is available, the request is delegated to
7514ad7e9b0SAdrian Chadd  * BUS_ACTIVATE_RESOURCE().
7524ad7e9b0SAdrian Chadd  */
7534ad7e9b0SAdrian Chadd int
7544ad7e9b0SAdrian Chadd bhnd_generic_activate_bhnd_resource(device_t dev, device_t child, int type,
7554ad7e9b0SAdrian Chadd 	int rid, struct bhnd_resource *r)
7564ad7e9b0SAdrian Chadd {
7574ad7e9b0SAdrian Chadd 	/* Try to delegate to the parent */
7584ad7e9b0SAdrian Chadd 	if (device_get_parent(dev) != NULL)
7594ad7e9b0SAdrian Chadd 		return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
7604ad7e9b0SAdrian Chadd 		    child, type, rid, r));
7614ad7e9b0SAdrian Chadd 
7624ad7e9b0SAdrian Chadd 	/* Activate the resource directly */
7634ad7e9b0SAdrian Chadd 	if (!r->direct) {
7644ad7e9b0SAdrian Chadd 		panic("bhnd indirect resource released without "
7654ad7e9b0SAdrian Chadd 		    "bhnd parent bus");
7664ad7e9b0SAdrian Chadd 	}
7674ad7e9b0SAdrian Chadd 
7684ad7e9b0SAdrian Chadd 	return (BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res));
7694ad7e9b0SAdrian Chadd };
7704ad7e9b0SAdrian Chadd 
7714ad7e9b0SAdrian Chadd /**
7724ad7e9b0SAdrian Chadd  * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
7734ad7e9b0SAdrian Chadd  *
7744ad7e9b0SAdrian Chadd  * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
7754ad7e9b0SAdrian Chadd  * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
7764ad7e9b0SAdrian Chadd  *
7774ad7e9b0SAdrian Chadd  * If no parent device is available, the request is delegated to
7784ad7e9b0SAdrian Chadd  * BUS_DEACTIVATE_RESOURCE().
7794ad7e9b0SAdrian Chadd  */
7804ad7e9b0SAdrian Chadd int
7814ad7e9b0SAdrian Chadd bhnd_generic_deactivate_bhnd_resource(device_t dev, device_t child, int type,
7824ad7e9b0SAdrian Chadd 	int rid, struct bhnd_resource *r)
7834ad7e9b0SAdrian Chadd {
7844ad7e9b0SAdrian Chadd 	if (device_get_parent(dev) != NULL)
7854ad7e9b0SAdrian Chadd 		return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
7864ad7e9b0SAdrian Chadd 		    child, type, rid, r));
7874ad7e9b0SAdrian Chadd 
7884ad7e9b0SAdrian Chadd 	/* De-activate the resource directly */
7894ad7e9b0SAdrian Chadd 	if (!r->direct) {
7904ad7e9b0SAdrian Chadd 		panic("bhnd indirect resource released without "
7914ad7e9b0SAdrian Chadd 		    "bhnd parent bus");
7924ad7e9b0SAdrian Chadd 	}
7934ad7e9b0SAdrian Chadd 
7944ad7e9b0SAdrian Chadd 	return (BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res));
7954ad7e9b0SAdrian Chadd };
7964ad7e9b0SAdrian Chadd 
7974ad7e9b0SAdrian Chadd /*
7984ad7e9b0SAdrian Chadd  * Delegate all indirect I/O to the parent device. When inherited by
7994ad7e9b0SAdrian Chadd  * non-bridged bus implementations, resources will never be marked as
8004ad7e9b0SAdrian Chadd  * indirect, and these methods should never be called.
8014ad7e9b0SAdrian Chadd  */
8024ad7e9b0SAdrian Chadd 
8034ad7e9b0SAdrian Chadd static uint8_t
8044ad7e9b0SAdrian Chadd bhnd_read_1(device_t dev, device_t child, struct bhnd_resource *r,
8054ad7e9b0SAdrian Chadd     bus_size_t offset)
8064ad7e9b0SAdrian Chadd {
8074ad7e9b0SAdrian Chadd 	return (BHND_BUS_READ_1(device_get_parent(dev), child, r, offset));
8084ad7e9b0SAdrian Chadd }
8094ad7e9b0SAdrian Chadd 
8104ad7e9b0SAdrian Chadd static uint16_t
8114ad7e9b0SAdrian Chadd bhnd_read_2(device_t dev, device_t child, struct bhnd_resource *r,
8124ad7e9b0SAdrian Chadd     bus_size_t offset)
8134ad7e9b0SAdrian Chadd {
8144ad7e9b0SAdrian Chadd 	return (BHND_BUS_READ_2(device_get_parent(dev), child, r, offset));
8154ad7e9b0SAdrian Chadd }
8164ad7e9b0SAdrian Chadd 
8174ad7e9b0SAdrian Chadd static uint32_t
8184ad7e9b0SAdrian Chadd bhnd_read_4(device_t dev, device_t child, struct bhnd_resource *r,
8194ad7e9b0SAdrian Chadd     bus_size_t offset)
8204ad7e9b0SAdrian Chadd {
8214ad7e9b0SAdrian Chadd 	return (BHND_BUS_READ_4(device_get_parent(dev), child, r, offset));
8224ad7e9b0SAdrian Chadd }
8234ad7e9b0SAdrian Chadd 
8244ad7e9b0SAdrian Chadd static void
8254ad7e9b0SAdrian Chadd bhnd_write_1(device_t dev, device_t child, struct bhnd_resource *r,
8264ad7e9b0SAdrian Chadd     bus_size_t offset, uint8_t value)
8274ad7e9b0SAdrian Chadd {
8284ad7e9b0SAdrian Chadd 	BHND_BUS_WRITE_1(device_get_parent(dev), child, r, offset, value);
8294ad7e9b0SAdrian Chadd }
8304ad7e9b0SAdrian Chadd 
8314ad7e9b0SAdrian Chadd static void
8324ad7e9b0SAdrian Chadd bhnd_write_2(device_t dev, device_t child, struct bhnd_resource *r,
8334ad7e9b0SAdrian Chadd     bus_size_t offset, uint16_t value)
8344ad7e9b0SAdrian Chadd {
8354ad7e9b0SAdrian Chadd 	BHND_BUS_WRITE_2(device_get_parent(dev), child, r, offset, value);
8364ad7e9b0SAdrian Chadd }
8374ad7e9b0SAdrian Chadd 
8384ad7e9b0SAdrian Chadd static void
8394ad7e9b0SAdrian Chadd bhnd_write_4(device_t dev, device_t child, struct bhnd_resource *r,
8404ad7e9b0SAdrian Chadd     bus_size_t offset, uint32_t value)
8414ad7e9b0SAdrian Chadd {
8424ad7e9b0SAdrian Chadd 	BHND_BUS_WRITE_4(device_get_parent(dev), child, r, offset, value);
8434ad7e9b0SAdrian Chadd }
8444ad7e9b0SAdrian Chadd 
8454ad7e9b0SAdrian Chadd static void
8464ad7e9b0SAdrian Chadd bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r,
8474ad7e9b0SAdrian Chadd     bus_size_t offset, bus_size_t length, int flags)
8484ad7e9b0SAdrian Chadd {
8494ad7e9b0SAdrian Chadd 	BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length,
8504ad7e9b0SAdrian Chadd 	    flags);
8514ad7e9b0SAdrian Chadd }
8524ad7e9b0SAdrian Chadd 
8534ad7e9b0SAdrian Chadd static device_method_t bhnd_methods[] = {
8544ad7e9b0SAdrian Chadd 	/* Device interface */ \
8554ad7e9b0SAdrian Chadd 	DEVMETHOD(device_attach,		bhnd_generic_attach),
8564ad7e9b0SAdrian Chadd 	DEVMETHOD(device_detach,		bhnd_generic_detach),
8574ad7e9b0SAdrian Chadd 	DEVMETHOD(device_shutdown,		bhnd_generic_shutdown),
8584ad7e9b0SAdrian Chadd 	DEVMETHOD(device_suspend,		bhnd_generic_suspend),
8594ad7e9b0SAdrian Chadd 	DEVMETHOD(device_resume,		bhnd_generic_resume),
8604ad7e9b0SAdrian Chadd 
8614ad7e9b0SAdrian Chadd 	/* Bus interface */
8624ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_probe_nomatch,		bhnd_generic_probe_nomatch),
8634ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_print_child,		bhnd_generic_print_child),
8644ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_child_pnpinfo_str,	bhnd_child_pnpinfo_str),
8654ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_child_location_str,	bhnd_child_location_str),
8664ad7e9b0SAdrian Chadd 
8674ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_suspend_child,		bhnd_generic_suspend_child),
8684ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_resume_child,		bhnd_generic_resume_child),
8694ad7e9b0SAdrian Chadd 
8704ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
8714ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
8724ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_delete_resource,		bus_generic_rl_delete_resource),
8734ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_alloc_resource,		bus_generic_rl_alloc_resource),
8744ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_adjust_resource,		bus_generic_adjust_resource),
8754ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_release_resource,		bus_generic_rl_release_resource),
8764ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
8774ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
8784ad7e9b0SAdrian Chadd 
8794ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
8804ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
8814ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_config_intr,		bus_generic_config_intr),
8824ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_bind_intr,		bus_generic_bind_intr),
8834ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_describe_intr,		bus_generic_describe_intr),
8844ad7e9b0SAdrian Chadd 
8854ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_get_dma_tag,		bus_generic_get_dma_tag),
8864ad7e9b0SAdrian Chadd 
8874ad7e9b0SAdrian Chadd 	/* BHND interface */
8884ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_alloc_resource,	bhnd_generic_alloc_bhnd_resource),
8894ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_release_resource,	bhnd_generic_release_bhnd_resource),
8904ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_activate_resource,	bhnd_generic_activate_bhnd_resource),
8914ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_activate_resource,	bhnd_generic_deactivate_bhnd_resource),
8924ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_get_chipid,		bhnd_generic_get_chipid),
8934ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_get_probe_order,	bhnd_generic_get_probe_order),
8944ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_read_1,		bhnd_read_1),
8954ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_read_2,		bhnd_read_2),
8964ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_read_4,		bhnd_read_4),
8974ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_write_1,		bhnd_write_1),
8984ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_write_2,		bhnd_write_2),
8994ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_write_4,		bhnd_write_4),
9004ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_barrier,		bhnd_barrier),
9014ad7e9b0SAdrian Chadd 
9024ad7e9b0SAdrian Chadd 	DEVMETHOD_END
9034ad7e9b0SAdrian Chadd };
9044ad7e9b0SAdrian Chadd 
9054ad7e9b0SAdrian Chadd devclass_t bhnd_devclass;	/**< bhnd bus. */
9064ad7e9b0SAdrian Chadd devclass_t bhnd_hostb_devclass;	/**< bhnd bus host bridge. */
9074ad7e9b0SAdrian Chadd devclass_t bhnd_nvram_devclass;	/**< bhnd NVRAM device */
9084ad7e9b0SAdrian Chadd 
9094ad7e9b0SAdrian Chadd DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc));
9104ad7e9b0SAdrian Chadd MODULE_VERSION(bhnd, 1);
911