xref: /freebsd/sys/dev/bhnd/siba/siba.c (revision 20f932af2973afc7624ac40a843b85b48a3947c7)
14ad7e9b0SAdrian Chadd /*-
2caeff9a3SLandon J. Fuller  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3caeff9a3SLandon J. Fuller  * Copyright (c) 2017 The FreeBSD Foundation
44ad7e9b0SAdrian Chadd  * All rights reserved.
54ad7e9b0SAdrian Chadd  *
6caeff9a3SLandon J. Fuller  * Portions of this software were developed by Landon Fuller
7caeff9a3SLandon J. Fuller  * under sponsorship from the FreeBSD Foundation.
8caeff9a3SLandon J. Fuller  *
94ad7e9b0SAdrian Chadd  * Redistribution and use in source and binary forms, with or without
104ad7e9b0SAdrian Chadd  * modification, are permitted provided that the following conditions
114ad7e9b0SAdrian Chadd  * are met:
124ad7e9b0SAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
134ad7e9b0SAdrian Chadd  *    notice, this list of conditions and the following disclaimer,
144ad7e9b0SAdrian Chadd  *    without modification.
154ad7e9b0SAdrian Chadd  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
164ad7e9b0SAdrian Chadd  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
174ad7e9b0SAdrian Chadd  *    redistribution must be conditioned upon including a substantially
184ad7e9b0SAdrian Chadd  *    similar Disclaimer requirement for further binary redistribution.
194ad7e9b0SAdrian Chadd  *
204ad7e9b0SAdrian Chadd  * NO WARRANTY
214ad7e9b0SAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
224ad7e9b0SAdrian Chadd  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
234ad7e9b0SAdrian Chadd  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
244ad7e9b0SAdrian Chadd  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
254ad7e9b0SAdrian Chadd  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
264ad7e9b0SAdrian Chadd  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
274ad7e9b0SAdrian Chadd  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
284ad7e9b0SAdrian Chadd  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
294ad7e9b0SAdrian Chadd  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
304ad7e9b0SAdrian Chadd  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
314ad7e9b0SAdrian Chadd  * THE POSSIBILITY OF SUCH DAMAGES.
324ad7e9b0SAdrian Chadd  */
334ad7e9b0SAdrian Chadd 
344ad7e9b0SAdrian Chadd #include <sys/param.h>
354ad7e9b0SAdrian Chadd #include <sys/bus.h>
364ad7e9b0SAdrian Chadd #include <sys/kernel.h>
374ad7e9b0SAdrian Chadd #include <sys/malloc.h>
384ad7e9b0SAdrian Chadd #include <sys/module.h>
394e96bf3aSLandon J. Fuller #include <sys/refcount.h>
404ad7e9b0SAdrian Chadd #include <sys/systm.h>
414ad7e9b0SAdrian Chadd 
424ad7e9b0SAdrian Chadd #include <machine/bus.h>
434ad7e9b0SAdrian Chadd 
44802cb422SLandon J. Fuller #include <dev/bhnd/cores/chipc/chipc.h>
454e96bf3aSLandon J. Fuller #include <dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl.h>
464ad7e9b0SAdrian Chadd 
477c7c726bSLandon J. Fuller #include "siba_eromvar.h"
487c7c726bSLandon J. Fuller 
494ad7e9b0SAdrian Chadd #include "sibareg.h"
504ad7e9b0SAdrian Chadd #include "sibavar.h"
514ad7e9b0SAdrian Chadd 
527c7c726bSLandon J. Fuller /* RID used when allocating EROM resources */
537c7c726bSLandon J. Fuller #define	SIBA_EROM_RID	0
547c7c726bSLandon J. Fuller 
55111d7cb2SLandon J. Fuller static bhnd_erom_class_t *
siba_get_erom_class(driver_t * driver)56111d7cb2SLandon J. Fuller siba_get_erom_class(driver_t *driver)
57111d7cb2SLandon J. Fuller {
58111d7cb2SLandon J. Fuller 	return (&siba_erom_parser);
59111d7cb2SLandon J. Fuller }
60111d7cb2SLandon J. Fuller 
614ad7e9b0SAdrian Chadd int
siba_probe(device_t dev)624ad7e9b0SAdrian Chadd siba_probe(device_t dev)
634ad7e9b0SAdrian Chadd {
644ad7e9b0SAdrian Chadd 	device_set_desc(dev, "SIBA BHND bus");
654ad7e9b0SAdrian Chadd 	return (BUS_PROBE_DEFAULT);
664ad7e9b0SAdrian Chadd }
674ad7e9b0SAdrian Chadd 
68111d7cb2SLandon J. Fuller /**
69111d7cb2SLandon J. Fuller  * Default siba(4) bus driver implementation of DEVICE_ATTACH().
70111d7cb2SLandon J. Fuller  *
71111d7cb2SLandon J. Fuller  * This implementation initializes internal siba(4) state and performs
72111d7cb2SLandon J. Fuller  * bus enumeration, and must be called by subclassing drivers in
73111d7cb2SLandon J. Fuller  * DEVICE_ATTACH() before any other bus methods.
74111d7cb2SLandon J. Fuller  */
754ad7e9b0SAdrian Chadd int
siba_attach(device_t dev)764ad7e9b0SAdrian Chadd siba_attach(device_t dev)
774ad7e9b0SAdrian Chadd {
788ef24a0dSAdrian Chadd 	struct siba_softc	*sc;
794ad7e9b0SAdrian Chadd 	int			 error;
804ad7e9b0SAdrian Chadd 
818ef24a0dSAdrian Chadd 	sc = device_get_softc(dev);
828ef24a0dSAdrian Chadd 	sc->dev = dev;
834ad7e9b0SAdrian Chadd 
844e96bf3aSLandon J. Fuller 	SIBA_LOCK_INIT(sc);
854e96bf3aSLandon J. Fuller 
86111d7cb2SLandon J. Fuller 	/* Enumerate children */
87111d7cb2SLandon J. Fuller 	if ((error = siba_add_children(dev))) {
884e96bf3aSLandon J. Fuller 		SIBA_LOCK_DESTROY(sc);
894ad7e9b0SAdrian Chadd 		return (error);
904ad7e9b0SAdrian Chadd 	}
914ad7e9b0SAdrian Chadd 
92111d7cb2SLandon J. Fuller 	return (0);
934ad7e9b0SAdrian Chadd }
944ad7e9b0SAdrian Chadd 
954ad7e9b0SAdrian Chadd int
siba_detach(device_t dev)964ad7e9b0SAdrian Chadd siba_detach(device_t dev)
974ad7e9b0SAdrian Chadd {
984e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
994e96bf3aSLandon J. Fuller 	int			 error;
1004e96bf3aSLandon J. Fuller 
1014e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
1024e96bf3aSLandon J. Fuller 
1034e96bf3aSLandon J. Fuller 	if ((error = bhnd_generic_detach(dev)))
1044e96bf3aSLandon J. Fuller 		return (error);
1054e96bf3aSLandon J. Fuller 
1064e96bf3aSLandon J. Fuller 	SIBA_LOCK_DESTROY(sc);
1074e96bf3aSLandon J. Fuller 
1084e96bf3aSLandon J. Fuller 	return (0);
1094ad7e9b0SAdrian Chadd }
1104ad7e9b0SAdrian Chadd 
1118ef24a0dSAdrian Chadd int
siba_resume(device_t dev)1128ef24a0dSAdrian Chadd siba_resume(device_t dev)
1138ef24a0dSAdrian Chadd {
1148ef24a0dSAdrian Chadd 	return (bhnd_generic_resume(dev));
1158ef24a0dSAdrian Chadd }
1168ef24a0dSAdrian Chadd 
1178ef24a0dSAdrian Chadd int
siba_suspend(device_t dev)1188ef24a0dSAdrian Chadd siba_suspend(device_t dev)
1198ef24a0dSAdrian Chadd {
1208ef24a0dSAdrian Chadd 	return (bhnd_generic_suspend(dev));
1218ef24a0dSAdrian Chadd }
1228ef24a0dSAdrian Chadd 
1234ad7e9b0SAdrian Chadd static int
siba_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)1244ad7e9b0SAdrian Chadd siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
1254ad7e9b0SAdrian Chadd {
1264e96bf3aSLandon J. Fuller 	struct siba_softc		*sc;
1274ad7e9b0SAdrian Chadd 	const struct siba_devinfo	*dinfo;
1284ad7e9b0SAdrian Chadd 	const struct bhnd_core_info	*cfg;
1294ad7e9b0SAdrian Chadd 
1304e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
1314ad7e9b0SAdrian Chadd 	dinfo = device_get_ivars(child);
1324ad7e9b0SAdrian Chadd 	cfg = &dinfo->core_id.core_info;
1334ad7e9b0SAdrian Chadd 
1344ad7e9b0SAdrian Chadd 	switch (index) {
1354ad7e9b0SAdrian Chadd 	case BHND_IVAR_VENDOR:
1364ad7e9b0SAdrian Chadd 		*result = cfg->vendor;
1374ad7e9b0SAdrian Chadd 		return (0);
1384ad7e9b0SAdrian Chadd 	case BHND_IVAR_DEVICE:
1394ad7e9b0SAdrian Chadd 		*result = cfg->device;
1404ad7e9b0SAdrian Chadd 		return (0);
1414ad7e9b0SAdrian Chadd 	case BHND_IVAR_HWREV:
1424ad7e9b0SAdrian Chadd 		*result = cfg->hwrev;
1434ad7e9b0SAdrian Chadd 		return (0);
1444ad7e9b0SAdrian Chadd 	case BHND_IVAR_DEVICE_CLASS:
1454ad7e9b0SAdrian Chadd 		*result = bhnd_core_class(cfg);
1464ad7e9b0SAdrian Chadd 		return (0);
1474ad7e9b0SAdrian Chadd 	case BHND_IVAR_VENDOR_NAME:
1484ad7e9b0SAdrian Chadd 		*result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
1494ad7e9b0SAdrian Chadd 		return (0);
1504ad7e9b0SAdrian Chadd 	case BHND_IVAR_DEVICE_NAME:
1514ad7e9b0SAdrian Chadd 		*result = (uintptr_t) bhnd_core_name(cfg);
1524ad7e9b0SAdrian Chadd 		return (0);
1534ad7e9b0SAdrian Chadd 	case BHND_IVAR_CORE_INDEX:
1544ad7e9b0SAdrian Chadd 		*result = cfg->core_idx;
1554ad7e9b0SAdrian Chadd 		return (0);
1564ad7e9b0SAdrian Chadd 	case BHND_IVAR_CORE_UNIT:
1574ad7e9b0SAdrian Chadd 		*result = cfg->unit;
1584ad7e9b0SAdrian Chadd 		return (0);
1598a03f98aSLandon J. Fuller 	case BHND_IVAR_PMU_INFO:
1604e96bf3aSLandon J. Fuller 		SIBA_LOCK(sc);
1614e96bf3aSLandon J. Fuller 		switch (dinfo->pmu_state) {
1624e96bf3aSLandon J. Fuller 		case SIBA_PMU_NONE:
1634e96bf3aSLandon J. Fuller 			*result = (uintptr_t)NULL;
1644e96bf3aSLandon J. Fuller 			SIBA_UNLOCK(sc);
1658a03f98aSLandon J. Fuller 			return (0);
1664e96bf3aSLandon J. Fuller 
1674e96bf3aSLandon J. Fuller 		case SIBA_PMU_BHND:
1684e96bf3aSLandon J. Fuller 			*result = (uintptr_t)dinfo->pmu.bhnd_info;
1694e96bf3aSLandon J. Fuller 			SIBA_UNLOCK(sc);
1704e96bf3aSLandon J. Fuller 			return (0);
1714e96bf3aSLandon J. Fuller 
1724e96bf3aSLandon J. Fuller 		case SIBA_PMU_PWRCTL:
173802cb422SLandon J. Fuller 		case SIBA_PMU_FIXED:
1741c8edc1eSLandon J. Fuller 			*result = (uintptr_t)NULL;
1751c8edc1eSLandon J. Fuller 			SIBA_UNLOCK(sc);
1761c8edc1eSLandon J. Fuller 			return (0);
1774e96bf3aSLandon J. Fuller 		}
1784e96bf3aSLandon J. Fuller 
1794e96bf3aSLandon J. Fuller 		panic("invalid PMU state: %d", dinfo->pmu_state);
1804e96bf3aSLandon J. Fuller 		return (ENXIO);
1814e96bf3aSLandon J. Fuller 
1824ad7e9b0SAdrian Chadd 	default:
1834ad7e9b0SAdrian Chadd 		return (ENOENT);
1844ad7e9b0SAdrian Chadd 	}
1854ad7e9b0SAdrian Chadd }
1864ad7e9b0SAdrian Chadd 
1874ad7e9b0SAdrian Chadd static int
siba_write_ivar(device_t dev,device_t child,int index,uintptr_t value)1884ad7e9b0SAdrian Chadd siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
1894ad7e9b0SAdrian Chadd {
1904e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
1918a03f98aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
1928a03f98aSLandon J. Fuller 
1934e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
1948a03f98aSLandon J. Fuller 	dinfo = device_get_ivars(child);
1958a03f98aSLandon J. Fuller 
1964ad7e9b0SAdrian Chadd 	switch (index) {
1974ad7e9b0SAdrian Chadd 	case BHND_IVAR_VENDOR:
1984ad7e9b0SAdrian Chadd 	case BHND_IVAR_DEVICE:
1994ad7e9b0SAdrian Chadd 	case BHND_IVAR_HWREV:
2004ad7e9b0SAdrian Chadd 	case BHND_IVAR_DEVICE_CLASS:
2014ad7e9b0SAdrian Chadd 	case BHND_IVAR_VENDOR_NAME:
2024ad7e9b0SAdrian Chadd 	case BHND_IVAR_DEVICE_NAME:
2034ad7e9b0SAdrian Chadd 	case BHND_IVAR_CORE_INDEX:
2044ad7e9b0SAdrian Chadd 	case BHND_IVAR_CORE_UNIT:
2054ad7e9b0SAdrian Chadd 		return (EINVAL);
2068a03f98aSLandon J. Fuller 	case BHND_IVAR_PMU_INFO:
2074e96bf3aSLandon J. Fuller 		SIBA_LOCK(sc);
2084e96bf3aSLandon J. Fuller 		switch (dinfo->pmu_state) {
2094e96bf3aSLandon J. Fuller 		case SIBA_PMU_NONE:
2104e96bf3aSLandon J. Fuller 		case SIBA_PMU_BHND:
2114e96bf3aSLandon J. Fuller 			dinfo->pmu.bhnd_info = (void *)value;
2124e96bf3aSLandon J. Fuller 			dinfo->pmu_state = SIBA_PMU_BHND;
2134e96bf3aSLandon J. Fuller 			SIBA_UNLOCK(sc);
2148a03f98aSLandon J. Fuller 			return (0);
2154e96bf3aSLandon J. Fuller 
2164e96bf3aSLandon J. Fuller 		case SIBA_PMU_PWRCTL:
217802cb422SLandon J. Fuller 		case SIBA_PMU_FIXED:
218802cb422SLandon J. Fuller 			panic("bhnd_set_pmu_info() called with siba PMU state "
219802cb422SLandon J. Fuller 			    "%d", dinfo->pmu_state);
2204e96bf3aSLandon J. Fuller 			return (ENXIO);
2214e96bf3aSLandon J. Fuller 		}
2224e96bf3aSLandon J. Fuller 
2234e96bf3aSLandon J. Fuller 		panic("invalid PMU state: %d", dinfo->pmu_state);
2244e96bf3aSLandon J. Fuller 		return (ENXIO);
2254e96bf3aSLandon J. Fuller 
2264ad7e9b0SAdrian Chadd 	default:
2274ad7e9b0SAdrian Chadd 		return (ENOENT);
2284ad7e9b0SAdrian Chadd 	}
2294ad7e9b0SAdrian Chadd }
2304ad7e9b0SAdrian Chadd 
2314ad7e9b0SAdrian Chadd static struct resource_list *
siba_get_resource_list(device_t dev,device_t child)2324ad7e9b0SAdrian Chadd siba_get_resource_list(device_t dev, device_t child)
2334ad7e9b0SAdrian Chadd {
2344ad7e9b0SAdrian Chadd 	struct siba_devinfo *dinfo = device_get_ivars(child);
2354ad7e9b0SAdrian Chadd 	return (&dinfo->resources);
2364ad7e9b0SAdrian Chadd }
2374ad7e9b0SAdrian Chadd 
2384e96bf3aSLandon J. Fuller /* BHND_BUS_ALLOC_PMU() */
2394e96bf3aSLandon J. Fuller static int
siba_alloc_pmu(device_t dev,device_t child)2404e96bf3aSLandon J. Fuller siba_alloc_pmu(device_t dev, device_t child)
2414e96bf3aSLandon J. Fuller {
2424e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
2434e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
244802cb422SLandon J. Fuller 	device_t		 chipc;
2454e96bf3aSLandon J. Fuller 	device_t		 pwrctl;
246802cb422SLandon J. Fuller 	struct chipc_caps	 ccaps;
247802cb422SLandon J. Fuller 	siba_pmu_state		 pmu_state;
2484e96bf3aSLandon J. Fuller 	int			 error;
2494e96bf3aSLandon J. Fuller 
2504e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
2514e96bf3aSLandon J. Fuller 		return (EINVAL);
2524e96bf3aSLandon J. Fuller 
2534e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
2544e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
255802cb422SLandon J. Fuller 	pwrctl = NULL;
2564e96bf3aSLandon J. Fuller 
257802cb422SLandon J. Fuller 	/* Fetch ChipCommon capability flags */
258802cb422SLandon J. Fuller 	chipc = bhnd_retain_provider(child, BHND_SERVICE_CHIPC);
259802cb422SLandon J. Fuller 	if (chipc != NULL) {
260802cb422SLandon J. Fuller 		ccaps = *BHND_CHIPC_GET_CAPS(chipc);
261802cb422SLandon J. Fuller 		bhnd_release_provider(child, chipc, BHND_SERVICE_CHIPC);
262802cb422SLandon J. Fuller 	} else {
263802cb422SLandon J. Fuller 		memset(&ccaps, 0, sizeof(ccaps));
264802cb422SLandon J. Fuller 	}
265802cb422SLandon J. Fuller 
266802cb422SLandon J. Fuller 	/* Defer to bhnd(4)'s PMU implementation if ChipCommon exists and
267802cb422SLandon J. Fuller 	 * advertises PMU support */
268802cb422SLandon J. Fuller 	if (ccaps.pmu) {
2694e96bf3aSLandon J. Fuller 		if ((error = bhnd_generic_alloc_pmu(dev, child)))
2704e96bf3aSLandon J. Fuller 			return (error);
2714e96bf3aSLandon J. Fuller 
2724e96bf3aSLandon J. Fuller 		KASSERT(dinfo->pmu_state == SIBA_PMU_BHND,
2734e96bf3aSLandon J. Fuller 		    ("unexpected PMU state: %d", dinfo->pmu_state));
2744e96bf3aSLandon J. Fuller 
2754e96bf3aSLandon J. Fuller 		return (0);
2764e96bf3aSLandon J. Fuller 	}
2774e96bf3aSLandon J. Fuller 
278802cb422SLandon J. Fuller 	/*
279802cb422SLandon J. Fuller 	 * This is either a legacy PWRCTL chipset, or the device does not
280802cb422SLandon J. Fuller 	 * support dynamic clock control.
281802cb422SLandon J. Fuller 	 *
282802cb422SLandon J. Fuller 	 * We need to map all bhnd(4) bus PMU to PWRCTL or no-op operations.
283802cb422SLandon J. Fuller 	 */
284802cb422SLandon J. Fuller 	if (ccaps.pwr_ctrl) {
285802cb422SLandon J. Fuller 		pmu_state = SIBA_PMU_PWRCTL;
286802cb422SLandon J. Fuller 		pwrctl = bhnd_retain_provider(child, BHND_SERVICE_PWRCTL);
287802cb422SLandon J. Fuller 		if (pwrctl == NULL) {
288802cb422SLandon J. Fuller 			device_printf(dev, "PWRCTL not found\n");
289802cb422SLandon J. Fuller 			return (ENODEV);
290802cb422SLandon J. Fuller 		}
291802cb422SLandon J. Fuller 	} else {
292802cb422SLandon J. Fuller 		pmu_state = SIBA_PMU_FIXED;
293802cb422SLandon J. Fuller 		pwrctl = NULL;
294802cb422SLandon J. Fuller 	}
295802cb422SLandon J. Fuller 
2964e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
2974e96bf3aSLandon J. Fuller 
2984e96bf3aSLandon J. Fuller 	/* Per-core PMU state already allocated? */
2994e96bf3aSLandon J. Fuller 	if (dinfo->pmu_state != SIBA_PMU_NONE) {
3004e96bf3aSLandon J. Fuller 		panic("duplicate PMU allocation for %s",
3014e96bf3aSLandon J. Fuller 		    device_get_nameunit(child));
3024e96bf3aSLandon J. Fuller 	}
3034e96bf3aSLandon J. Fuller 
3044e96bf3aSLandon J. Fuller 	/* Update the child's PMU allocation state, and transfer ownership of
305802cb422SLandon J. Fuller 	 * the PWRCTL provider reference (if any) */
306802cb422SLandon J. Fuller 	dinfo->pmu_state = pmu_state;
3074e96bf3aSLandon J. Fuller 	dinfo->pmu.pwrctl = pwrctl;
3084e96bf3aSLandon J. Fuller 
3094e96bf3aSLandon J. Fuller 	SIBA_UNLOCK(sc);
3104e96bf3aSLandon J. Fuller 
3114e96bf3aSLandon J. Fuller 	return (0);
3124e96bf3aSLandon J. Fuller }
3134e96bf3aSLandon J. Fuller 
3144e96bf3aSLandon J. Fuller /* BHND_BUS_RELEASE_PMU() */
3154e96bf3aSLandon J. Fuller static int
siba_release_pmu(device_t dev,device_t child)3164e96bf3aSLandon J. Fuller siba_release_pmu(device_t dev, device_t child)
3174e96bf3aSLandon J. Fuller {
3184e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
3194e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
3204e96bf3aSLandon J. Fuller 	device_t		 pwrctl;
3214e96bf3aSLandon J. Fuller 	int			 error;
3224e96bf3aSLandon J. Fuller 
3234e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
3244e96bf3aSLandon J. Fuller 		return (EINVAL);
3254e96bf3aSLandon J. Fuller 
3264e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
3274e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
3284e96bf3aSLandon J. Fuller 
3294e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
3304e96bf3aSLandon J. Fuller 	switch(dinfo->pmu_state) {
3314e96bf3aSLandon J. Fuller 	case SIBA_PMU_NONE:
3324e96bf3aSLandon J. Fuller 		panic("pmu over-release for %s", device_get_nameunit(child));
3334e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
3344e96bf3aSLandon J. Fuller 		return (ENXIO);
3354e96bf3aSLandon J. Fuller 
3364e96bf3aSLandon J. Fuller 	case SIBA_PMU_BHND:
3374e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
3384e96bf3aSLandon J. Fuller 		return (bhnd_generic_release_pmu(dev, child));
3394e96bf3aSLandon J. Fuller 
3404e96bf3aSLandon J. Fuller 	case SIBA_PMU_PWRCTL:
3414e96bf3aSLandon J. Fuller 		/* Requesting BHND_CLOCK_DYN releases any outstanding clock
3424e96bf3aSLandon J. Fuller 		 * reservations */
3434e96bf3aSLandon J. Fuller 		pwrctl = dinfo->pmu.pwrctl;
3444e96bf3aSLandon J. Fuller 		error = bhnd_pwrctl_request_clock(pwrctl, child,
3454e96bf3aSLandon J. Fuller 		    BHND_CLOCK_DYN);
3464e96bf3aSLandon J. Fuller 		if (error) {
3474e96bf3aSLandon J. Fuller 			SIBA_UNLOCK(sc);
3484e96bf3aSLandon J. Fuller 			return (error);
3494e96bf3aSLandon J. Fuller 		}
3504e96bf3aSLandon J. Fuller 
3514e96bf3aSLandon J. Fuller 		/* Clean up the child's PMU state */
3524e96bf3aSLandon J. Fuller 		dinfo->pmu_state = SIBA_PMU_NONE;
3534e96bf3aSLandon J. Fuller 		dinfo->pmu.pwrctl = NULL;
3544e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
3554e96bf3aSLandon J. Fuller 
3564e96bf3aSLandon J. Fuller 		/* Release the provider reference */
3574e96bf3aSLandon J. Fuller 		bhnd_release_provider(child, pwrctl, BHND_SERVICE_PWRCTL);
3584e96bf3aSLandon J. Fuller 		return (0);
359802cb422SLandon J. Fuller 
360802cb422SLandon J. Fuller 	case SIBA_PMU_FIXED:
361802cb422SLandon J. Fuller 		/* Clean up the child's PMU state */
362802cb422SLandon J. Fuller 		KASSERT(dinfo->pmu.pwrctl == NULL,
363802cb422SLandon J. Fuller 		    ("PWRCTL reference with FIXED state"));
364802cb422SLandon J. Fuller 
365802cb422SLandon J. Fuller 		dinfo->pmu_state = SIBA_PMU_NONE;
366802cb422SLandon J. Fuller 		dinfo->pmu.pwrctl = NULL;
367802cb422SLandon J. Fuller 		SIBA_UNLOCK(sc);
3684e96bf3aSLandon J. Fuller 	}
3694e96bf3aSLandon J. Fuller 
3704e96bf3aSLandon J. Fuller 	panic("invalid PMU state: %d", dinfo->pmu_state);
3714e96bf3aSLandon J. Fuller }
3724e96bf3aSLandon J. Fuller 
3734e96bf3aSLandon J. Fuller /* BHND_BUS_GET_CLOCK_LATENCY() */
3744e96bf3aSLandon J. Fuller static int
siba_get_clock_latency(device_t dev,device_t child,bhnd_clock clock,u_int * latency)3754e96bf3aSLandon J. Fuller siba_get_clock_latency(device_t dev, device_t child, bhnd_clock clock,
3764e96bf3aSLandon J. Fuller     u_int *latency)
3774e96bf3aSLandon J. Fuller {
3784e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
3794e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
3804e96bf3aSLandon J. Fuller 	int			 error;
3814e96bf3aSLandon J. Fuller 
3824e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
3834e96bf3aSLandon J. Fuller 		return (EINVAL);
3844e96bf3aSLandon J. Fuller 
3854e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
3864e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
3874e96bf3aSLandon J. Fuller 
3884e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
3894e96bf3aSLandon J. Fuller 	switch(dinfo->pmu_state) {
3904e96bf3aSLandon J. Fuller 	case SIBA_PMU_NONE:
3914e96bf3aSLandon J. Fuller 		panic("no active PMU request state");
3924e96bf3aSLandon J. Fuller 
3934e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
3944e96bf3aSLandon J. Fuller 		return (ENXIO);
3954e96bf3aSLandon J. Fuller 
3964e96bf3aSLandon J. Fuller 	case SIBA_PMU_BHND:
3974e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
3984e96bf3aSLandon J. Fuller 		return (bhnd_generic_get_clock_latency(dev, child, clock,
3994e96bf3aSLandon J. Fuller 		    latency));
4004e96bf3aSLandon J. Fuller 
4014e96bf3aSLandon J. Fuller 	case SIBA_PMU_PWRCTL:
4024e96bf3aSLandon J. Fuller 		 error = bhnd_pwrctl_get_clock_latency(dinfo->pmu.pwrctl, clock,
4034e96bf3aSLandon J. Fuller 		    latency);
4044e96bf3aSLandon J. Fuller 		 SIBA_UNLOCK(sc);
4054e96bf3aSLandon J. Fuller 
4064e96bf3aSLandon J. Fuller 		 return (error);
407802cb422SLandon J. Fuller 
408802cb422SLandon J. Fuller 	case SIBA_PMU_FIXED:
409802cb422SLandon J. Fuller 		SIBA_UNLOCK(sc);
410802cb422SLandon J. Fuller 
411802cb422SLandon J. Fuller 		/* HT clock is always available, and incurs no transition
412802cb422SLandon J. Fuller 		 * delay. */
413802cb422SLandon J. Fuller 		switch (clock) {
414802cb422SLandon J. Fuller 		case BHND_CLOCK_HT:
415802cb422SLandon J. Fuller 			*latency = 0;
416802cb422SLandon J. Fuller 			return (0);
417802cb422SLandon J. Fuller 
418802cb422SLandon J. Fuller 		default:
419802cb422SLandon J. Fuller 			return (ENODEV);
420802cb422SLandon J. Fuller 		}
421802cb422SLandon J. Fuller 
422802cb422SLandon J. Fuller 		return (ENODEV);
4234e96bf3aSLandon J. Fuller 	}
4244e96bf3aSLandon J. Fuller 
4254e96bf3aSLandon J. Fuller 	panic("invalid PMU state: %d", dinfo->pmu_state);
4264e96bf3aSLandon J. Fuller }
4274e96bf3aSLandon J. Fuller 
4284e96bf3aSLandon J. Fuller /* BHND_BUS_GET_CLOCK_FREQ() */
4294e96bf3aSLandon J. Fuller static int
siba_get_clock_freq(device_t dev,device_t child,bhnd_clock clock,u_int * freq)4304e96bf3aSLandon J. Fuller siba_get_clock_freq(device_t dev, device_t child, bhnd_clock clock,
4314e96bf3aSLandon J. Fuller     u_int *freq)
4324e96bf3aSLandon J. Fuller {
4334e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
4344e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
4354e96bf3aSLandon J. Fuller 	int			 error;
4364e96bf3aSLandon J. Fuller 
4374e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
4384e96bf3aSLandon J. Fuller 		return (EINVAL);
4394e96bf3aSLandon J. Fuller 
4404e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
4414e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
4424e96bf3aSLandon J. Fuller 
4434e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
4444e96bf3aSLandon J. Fuller 	switch(dinfo->pmu_state) {
4454e96bf3aSLandon J. Fuller 	case SIBA_PMU_NONE:
4464e96bf3aSLandon J. Fuller 		panic("no active PMU request state");
4474e96bf3aSLandon J. Fuller 
4484e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
4494e96bf3aSLandon J. Fuller 		return (ENXIO);
4504e96bf3aSLandon J. Fuller 
4514e96bf3aSLandon J. Fuller 	case SIBA_PMU_BHND:
4524e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
4534e96bf3aSLandon J. Fuller 		return (bhnd_generic_get_clock_freq(dev, child, clock, freq));
4544e96bf3aSLandon J. Fuller 
4554e96bf3aSLandon J. Fuller 	case SIBA_PMU_PWRCTL:
4564e96bf3aSLandon J. Fuller 		error = bhnd_pwrctl_get_clock_freq(dinfo->pmu.pwrctl, clock,
4574e96bf3aSLandon J. Fuller 		    freq);
4584e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
4594e96bf3aSLandon J. Fuller 
4604e96bf3aSLandon J. Fuller 		return (error);
461802cb422SLandon J. Fuller 
462802cb422SLandon J. Fuller 	case SIBA_PMU_FIXED:
463802cb422SLandon J. Fuller 		SIBA_UNLOCK(sc);
464802cb422SLandon J. Fuller 
465802cb422SLandon J. Fuller 		return (ENODEV);
4664e96bf3aSLandon J. Fuller 	}
4674e96bf3aSLandon J. Fuller 
4684e96bf3aSLandon J. Fuller 	panic("invalid PMU state: %d", dinfo->pmu_state);
4694e96bf3aSLandon J. Fuller }
4704e96bf3aSLandon J. Fuller 
4714e96bf3aSLandon J. Fuller /* BHND_BUS_REQUEST_EXT_RSRC() */
4724e96bf3aSLandon J. Fuller static int
siba_request_ext_rsrc(device_t dev,device_t child,u_int rsrc)4734e96bf3aSLandon J. Fuller siba_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
4744e96bf3aSLandon J. Fuller {
4754e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
4764e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
4774e96bf3aSLandon J. Fuller 
4784e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
4794e96bf3aSLandon J. Fuller 		return (EINVAL);
4804e96bf3aSLandon J. Fuller 
4814e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
4824e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
4834e96bf3aSLandon J. Fuller 
4844e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
4854e96bf3aSLandon J. Fuller 	switch(dinfo->pmu_state) {
4864e96bf3aSLandon J. Fuller 	case SIBA_PMU_NONE:
4874e96bf3aSLandon J. Fuller 		panic("no active PMU request state");
4884e96bf3aSLandon J. Fuller 
4894e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
4904e96bf3aSLandon J. Fuller 		return (ENXIO);
4914e96bf3aSLandon J. Fuller 
4924e96bf3aSLandon J. Fuller 	case SIBA_PMU_BHND:
4934e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
4944e96bf3aSLandon J. Fuller 		return (bhnd_generic_request_ext_rsrc(dev, child, rsrc));
4954e96bf3aSLandon J. Fuller 
4964e96bf3aSLandon J. Fuller 	case SIBA_PMU_PWRCTL:
497802cb422SLandon J. Fuller 	case SIBA_PMU_FIXED:
4984e96bf3aSLandon J. Fuller 		/* HW does not support per-core external resources */
4994e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
5004e96bf3aSLandon J. Fuller 		return (ENODEV);
5014e96bf3aSLandon J. Fuller 	}
5024e96bf3aSLandon J. Fuller 
5034e96bf3aSLandon J. Fuller 	panic("invalid PMU state: %d", dinfo->pmu_state);
5044e96bf3aSLandon J. Fuller }
5054e96bf3aSLandon J. Fuller 
5064e96bf3aSLandon J. Fuller /* BHND_BUS_RELEASE_EXT_RSRC() */
5074e96bf3aSLandon J. Fuller static int
siba_release_ext_rsrc(device_t dev,device_t child,u_int rsrc)5084e96bf3aSLandon J. Fuller siba_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
5094e96bf3aSLandon J. Fuller {
5104e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
5114e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
5124e96bf3aSLandon J. Fuller 
5134e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
5144e96bf3aSLandon J. Fuller 		return (EINVAL);
5154e96bf3aSLandon J. Fuller 
5164e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
5174e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
5184e96bf3aSLandon J. Fuller 
5194e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
5204e96bf3aSLandon J. Fuller 	switch(dinfo->pmu_state) {
5214e96bf3aSLandon J. Fuller 	case SIBA_PMU_NONE:
5224e96bf3aSLandon J. Fuller 		panic("no active PMU request state");
5234e96bf3aSLandon J. Fuller 
5244e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
5254e96bf3aSLandon J. Fuller 		return (ENXIO);
5264e96bf3aSLandon J. Fuller 
5274e96bf3aSLandon J. Fuller 	case SIBA_PMU_BHND:
5284e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
5294e96bf3aSLandon J. Fuller 		return (bhnd_generic_release_ext_rsrc(dev, child, rsrc));
5304e96bf3aSLandon J. Fuller 
5314e96bf3aSLandon J. Fuller 	case SIBA_PMU_PWRCTL:
532802cb422SLandon J. Fuller 	case SIBA_PMU_FIXED:
5334e96bf3aSLandon J. Fuller 		/* HW does not support per-core external resources */
5344e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
5354e96bf3aSLandon J. Fuller 		return (ENODEV);
5364e96bf3aSLandon J. Fuller 	}
5374e96bf3aSLandon J. Fuller 
5384e96bf3aSLandon J. Fuller 	panic("invalid PMU state: %d", dinfo->pmu_state);
5394e96bf3aSLandon J. Fuller }
5404e96bf3aSLandon J. Fuller 
5414e96bf3aSLandon J. Fuller /* BHND_BUS_REQUEST_CLOCK() */
5424e96bf3aSLandon J. Fuller static int
siba_request_clock(device_t dev,device_t child,bhnd_clock clock)5434e96bf3aSLandon J. Fuller siba_request_clock(device_t dev, device_t child, bhnd_clock clock)
5444e96bf3aSLandon J. Fuller {
5454e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
5464e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
5474e96bf3aSLandon J. Fuller 	int			 error;
5484e96bf3aSLandon J. Fuller 
5494e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
5504e96bf3aSLandon J. Fuller 		return (EINVAL);
5514e96bf3aSLandon J. Fuller 
5524e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
5534e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
5544e96bf3aSLandon J. Fuller 
5554e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
5564e96bf3aSLandon J. Fuller 	switch(dinfo->pmu_state) {
5574e96bf3aSLandon J. Fuller 	case SIBA_PMU_NONE:
5584e96bf3aSLandon J. Fuller 		panic("no active PMU request state");
5594e96bf3aSLandon J. Fuller 
5604e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
5614e96bf3aSLandon J. Fuller 		return (ENXIO);
5624e96bf3aSLandon J. Fuller 
5634e96bf3aSLandon J. Fuller 	case SIBA_PMU_BHND:
5644e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
5654e96bf3aSLandon J. Fuller 		return (bhnd_generic_request_clock(dev, child, clock));
5664e96bf3aSLandon J. Fuller 
5674e96bf3aSLandon J. Fuller 	case SIBA_PMU_PWRCTL:
5684e96bf3aSLandon J. Fuller 		error = bhnd_pwrctl_request_clock(dinfo->pmu.pwrctl, child,
5694e96bf3aSLandon J. Fuller 		    clock);
5704e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
5714e96bf3aSLandon J. Fuller 
5724e96bf3aSLandon J. Fuller 		return (error);
573802cb422SLandon J. Fuller 
574802cb422SLandon J. Fuller 	case SIBA_PMU_FIXED:
575802cb422SLandon J. Fuller 		SIBA_UNLOCK(sc);
576802cb422SLandon J. Fuller 
577802cb422SLandon J. Fuller 		/* HT clock is always available, and fulfills any of the
578802cb422SLandon J. Fuller 		 * following clock requests */
579802cb422SLandon J. Fuller 		switch (clock) {
580802cb422SLandon J. Fuller 		case BHND_CLOCK_DYN:
581802cb422SLandon J. Fuller 		case BHND_CLOCK_ILP:
582802cb422SLandon J. Fuller 		case BHND_CLOCK_ALP:
583802cb422SLandon J. Fuller 		case BHND_CLOCK_HT:
584802cb422SLandon J. Fuller 			return (0);
585802cb422SLandon J. Fuller 
586802cb422SLandon J. Fuller 		default:
587802cb422SLandon J. Fuller 			return (ENODEV);
588802cb422SLandon J. Fuller 		}
5894e96bf3aSLandon J. Fuller 	}
5904e96bf3aSLandon J. Fuller 
5914e96bf3aSLandon J. Fuller 	panic("invalid PMU state: %d", dinfo->pmu_state);
5924e96bf3aSLandon J. Fuller }
5934e96bf3aSLandon J. Fuller 
5944e96bf3aSLandon J. Fuller /* BHND_BUS_ENABLE_CLOCKS() */
5954e96bf3aSLandon J. Fuller static int
siba_enable_clocks(device_t dev,device_t child,uint32_t clocks)5964e96bf3aSLandon J. Fuller siba_enable_clocks(device_t dev, device_t child, uint32_t clocks)
5974e96bf3aSLandon J. Fuller {
5984e96bf3aSLandon J. Fuller 	struct siba_softc	*sc;
5994e96bf3aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
6004e96bf3aSLandon J. Fuller 
6014e96bf3aSLandon J. Fuller 	if (device_get_parent(child) != dev)
6024e96bf3aSLandon J. Fuller 		return (EINVAL);
6034e96bf3aSLandon J. Fuller 
6044e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
6054e96bf3aSLandon J. Fuller 	dinfo = device_get_ivars(child);
6064e96bf3aSLandon J. Fuller 
6074e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
6084e96bf3aSLandon J. Fuller 	switch(dinfo->pmu_state) {
6094e96bf3aSLandon J. Fuller 	case SIBA_PMU_NONE:
6104e96bf3aSLandon J. Fuller 		panic("no active PMU request state");
6114e96bf3aSLandon J. Fuller 
6124e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
6134e96bf3aSLandon J. Fuller 		return (ENXIO);
6144e96bf3aSLandon J. Fuller 
6154e96bf3aSLandon J. Fuller 	case SIBA_PMU_BHND:
6164e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
6174e96bf3aSLandon J. Fuller 		return (bhnd_generic_enable_clocks(dev, child, clocks));
6184e96bf3aSLandon J. Fuller 
6194e96bf3aSLandon J. Fuller 	case SIBA_PMU_PWRCTL:
620802cb422SLandon J. Fuller 	case SIBA_PMU_FIXED:
6214e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
6224e96bf3aSLandon J. Fuller 
6234e96bf3aSLandon J. Fuller 		/* All (supported) clocks are already enabled by default */
6244e96bf3aSLandon J. Fuller 		clocks &= ~(BHND_CLOCK_DYN |
6254e96bf3aSLandon J. Fuller 			    BHND_CLOCK_ILP |
6264e96bf3aSLandon J. Fuller 			    BHND_CLOCK_ALP |
6274e96bf3aSLandon J. Fuller 			    BHND_CLOCK_HT);
6284e96bf3aSLandon J. Fuller 
6294e96bf3aSLandon J. Fuller 		if (clocks != 0) {
6304e96bf3aSLandon J. Fuller 			device_printf(dev, "%s requested unknown clocks: %#x\n",
6314e96bf3aSLandon J. Fuller 			    device_get_nameunit(child), clocks);
6324e96bf3aSLandon J. Fuller 			return (ENODEV);
6334e96bf3aSLandon J. Fuller 		}
6344e96bf3aSLandon J. Fuller 
6354e96bf3aSLandon J. Fuller 		return (0);
6364e96bf3aSLandon J. Fuller 	}
6374e96bf3aSLandon J. Fuller 
6384e96bf3aSLandon J. Fuller 	panic("invalid PMU state: %d", dinfo->pmu_state);
6394e96bf3aSLandon J. Fuller }
6404e96bf3aSLandon J. Fuller 
6414ad7e9b0SAdrian Chadd static int
siba_read_iost(device_t dev,device_t child,uint16_t * iost)6428a03f98aSLandon J. Fuller siba_read_iost(device_t dev, device_t child, uint16_t *iost)
6434ad7e9b0SAdrian Chadd {
6448a03f98aSLandon J. Fuller 	uint32_t	tmhigh;
6458a03f98aSLandon J. Fuller 	int		error;
6464ad7e9b0SAdrian Chadd 
6478a03f98aSLandon J. Fuller 	error = bhnd_read_config(child, SIBA_CFG0_TMSTATEHIGH, &tmhigh, 4);
6488a03f98aSLandon J. Fuller 	if (error)
6498a03f98aSLandon J. Fuller 		return (error);
6504ad7e9b0SAdrian Chadd 
6518a03f98aSLandon J. Fuller 	*iost = (SIBA_REG_GET(tmhigh, TMH_SISF));
6528a03f98aSLandon J. Fuller 	return (0);
6534ad7e9b0SAdrian Chadd }
6544ad7e9b0SAdrian Chadd 
6554ad7e9b0SAdrian Chadd static int
siba_read_ioctl(device_t dev,device_t child,uint16_t * ioctl)6568a03f98aSLandon J. Fuller siba_read_ioctl(device_t dev, device_t child, uint16_t *ioctl)
6578a03f98aSLandon J. Fuller {
6588a03f98aSLandon J. Fuller 	uint32_t	ts_low;
6598a03f98aSLandon J. Fuller 	int		error;
6608a03f98aSLandon J. Fuller 
6618a03f98aSLandon J. Fuller 	if ((error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4)))
6628a03f98aSLandon J. Fuller 		return (error);
6638a03f98aSLandon J. Fuller 
6648a03f98aSLandon J. Fuller 	*ioctl = (SIBA_REG_GET(ts_low, TML_SICF));
6658a03f98aSLandon J. Fuller 	return (0);
6668a03f98aSLandon J. Fuller }
6678a03f98aSLandon J. Fuller 
6688a03f98aSLandon J. Fuller static int
siba_write_ioctl(device_t dev,device_t child,uint16_t value,uint16_t mask)6698a03f98aSLandon J. Fuller siba_write_ioctl(device_t dev, device_t child, uint16_t value, uint16_t mask)
6704ad7e9b0SAdrian Chadd {
6714ad7e9b0SAdrian Chadd 	struct siba_devinfo	*dinfo;
6728a03f98aSLandon J. Fuller 	struct bhnd_resource	*r;
6738a03f98aSLandon J. Fuller 	uint32_t		 ts_low, ts_mask;
6744ad7e9b0SAdrian Chadd 
6754ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
6768a03f98aSLandon J. Fuller 		return (EINVAL);
6778a03f98aSLandon J. Fuller 
6788a03f98aSLandon J. Fuller 	/* Fetch CFG0 mapping */
6798a03f98aSLandon J. Fuller 	dinfo = device_get_ivars(child);
680caeff9a3SLandon J. Fuller 	if ((r = dinfo->cfg_res[0]) == NULL)
6818a03f98aSLandon J. Fuller 		return (ENODEV);
6828a03f98aSLandon J. Fuller 
6838a03f98aSLandon J. Fuller 	/* Mask and set TMSTATELOW core flag bits */
6848a03f98aSLandon J. Fuller 	ts_mask = (mask << SIBA_TML_SICF_SHIFT) & SIBA_TML_SICF_MASK;
6858a03f98aSLandon J. Fuller 	ts_low = (value << SIBA_TML_SICF_SHIFT) & ts_mask;
6868a03f98aSLandon J. Fuller 
687ac59515bSLandon J. Fuller 	siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
688ac59515bSLandon J. Fuller 	    ts_low, ts_mask);
689ac59515bSLandon J. Fuller 	return (0);
6908a03f98aSLandon J. Fuller }
6918a03f98aSLandon J. Fuller 
6928a03f98aSLandon J. Fuller static bool
siba_is_hw_suspended(device_t dev,device_t child)6938a03f98aSLandon J. Fuller siba_is_hw_suspended(device_t dev, device_t child)
6948a03f98aSLandon J. Fuller {
6958a03f98aSLandon J. Fuller 	uint32_t		ts_low;
6968a03f98aSLandon J. Fuller 	uint16_t		ioctl;
6978a03f98aSLandon J. Fuller 	int			error;
6988a03f98aSLandon J. Fuller 
6998a03f98aSLandon J. Fuller 	/* Fetch target state */
7008a03f98aSLandon J. Fuller 	error = bhnd_read_config(child, SIBA_CFG0_TMSTATELOW, &ts_low, 4);
7018a03f98aSLandon J. Fuller 	if (error) {
7028a03f98aSLandon J. Fuller 		device_printf(child, "error reading HW reset state: %d\n",
7038a03f98aSLandon J. Fuller 		    error);
7048a03f98aSLandon J. Fuller 		return (true);
7058a03f98aSLandon J. Fuller 	}
7068a03f98aSLandon J. Fuller 
7078a03f98aSLandon J. Fuller 	/* Is core held in RESET? */
7088a03f98aSLandon J. Fuller 	if (ts_low & SIBA_TML_RESET)
7098a03f98aSLandon J. Fuller 		return (true);
7108a03f98aSLandon J. Fuller 
711ac59515bSLandon J. Fuller 	/* Is target reject enabled? */
712ac59515bSLandon J. Fuller 	if (ts_low & SIBA_TML_REJ_MASK)
713ac59515bSLandon J. Fuller 		return (true);
714ac59515bSLandon J. Fuller 
7158a03f98aSLandon J. Fuller 	/* Is core clocked? */
7168a03f98aSLandon J. Fuller 	ioctl = SIBA_REG_GET(ts_low, TML_SICF);
7178a03f98aSLandon J. Fuller 	if (!(ioctl & BHND_IOCTL_CLK_EN))
7188a03f98aSLandon J. Fuller 		return (true);
7198a03f98aSLandon J. Fuller 
7208a03f98aSLandon J. Fuller 	return (false);
7218a03f98aSLandon J. Fuller }
7228a03f98aSLandon J. Fuller 
7238a03f98aSLandon J. Fuller static int
siba_reset_hw(device_t dev,device_t child,uint16_t ioctl,uint16_t reset_ioctl)724ac59515bSLandon J. Fuller siba_reset_hw(device_t dev, device_t child, uint16_t ioctl,
725ac59515bSLandon J. Fuller     uint16_t reset_ioctl)
7268a03f98aSLandon J. Fuller {
7278a03f98aSLandon J. Fuller 	struct siba_devinfo		*dinfo;
7288a03f98aSLandon J. Fuller 	struct bhnd_resource		*r;
7298a03f98aSLandon J. Fuller 	uint32_t			 ts_low, imstate;
730ac59515bSLandon J. Fuller 	uint16_t			 clkflags;
7318a03f98aSLandon J. Fuller 	int				 error;
7328a03f98aSLandon J. Fuller 
7338a03f98aSLandon J. Fuller 	if (device_get_parent(child) != dev)
7348a03f98aSLandon J. Fuller 		return (EINVAL);
7354ad7e9b0SAdrian Chadd 
7364ad7e9b0SAdrian Chadd 	dinfo = device_get_ivars(child);
7374ad7e9b0SAdrian Chadd 
7384ad7e9b0SAdrian Chadd 	/* Can't suspend the core without access to the CFG0 registers */
739caeff9a3SLandon J. Fuller 	if ((r = dinfo->cfg_res[0]) == NULL)
7404ad7e9b0SAdrian Chadd 		return (ENODEV);
7414ad7e9b0SAdrian Chadd 
742ac59515bSLandon J. Fuller 	/* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
743ac59515bSLandon J. Fuller 	clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
744ac59515bSLandon J. Fuller 	if (ioctl & clkflags)
7458a03f98aSLandon J. Fuller 		return (EINVAL);
7464ad7e9b0SAdrian Chadd 
7478a03f98aSLandon J. Fuller 	/* Place core into known RESET state */
748ac59515bSLandon J. Fuller 	if ((error = bhnd_suspend_hw(child, reset_ioctl)))
7498a03f98aSLandon J. Fuller 		return (error);
7508a03f98aSLandon J. Fuller 
751ac59515bSLandon J. Fuller 	/* Set RESET, clear REJ, set the caller's IOCTL flags, and
752ac59515bSLandon J. Fuller 	 * force clocks to ensure the signal propagates throughout the
753ac59515bSLandon J. Fuller 	 * core. */
754ac59515bSLandon J. Fuller 	ts_low = SIBA_TML_RESET |
755ac59515bSLandon J. Fuller 		 (ioctl << SIBA_TML_SICF_SHIFT) |
756ac59515bSLandon J. Fuller 		 (BHND_IOCTL_CLK_EN << SIBA_TML_SICF_SHIFT) |
757ac59515bSLandon J. Fuller 		 (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT);
758ac59515bSLandon J. Fuller 
759ac59515bSLandon J. Fuller 	siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
760ac59515bSLandon J. Fuller 	    ts_low, UINT32_MAX);
7618a03f98aSLandon J. Fuller 
7628a03f98aSLandon J. Fuller 	/* Clear any target errors */
7638a03f98aSLandon J. Fuller 	if (bhnd_bus_read_4(r, SIBA_CFG0_TMSTATEHIGH) & SIBA_TMH_SERR) {
764ac59515bSLandon J. Fuller 		siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATEHIGH,
765ac59515bSLandon J. Fuller 		    0x0, SIBA_TMH_SERR);
7664ad7e9b0SAdrian Chadd 	}
7674ad7e9b0SAdrian Chadd 
7688a03f98aSLandon J. Fuller 	/* Clear any initiator errors */
7698a03f98aSLandon J. Fuller 	imstate = bhnd_bus_read_4(r, SIBA_CFG0_IMSTATE);
7708a03f98aSLandon J. Fuller 	if (imstate & (SIBA_IM_IBE|SIBA_IM_TO)) {
771ac59515bSLandon J. Fuller 		siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE, 0x0,
772ac59515bSLandon J. Fuller 		    SIBA_IM_IBE|SIBA_IM_TO);
7738a03f98aSLandon J. Fuller 	}
7748a03f98aSLandon J. Fuller 
7758a03f98aSLandon J. Fuller 	/* Release from RESET while leaving clocks forced, ensuring the
7768a03f98aSLandon J. Fuller 	 * signal propagates throughout the core */
777ac59515bSLandon J. Fuller 	siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, 0x0,
778ac59515bSLandon J. Fuller 	    SIBA_TML_RESET);
7798a03f98aSLandon J. Fuller 
7808a03f98aSLandon J. Fuller 	/* The core should now be active; we can clear the BHND_IOCTL_CLK_FORCE
7818a03f98aSLandon J. Fuller 	 * bit and allow the core to manage clock gating. */
782ac59515bSLandon J. Fuller 	siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, 0x0,
783ac59515bSLandon J. Fuller 	    (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT));
7848a03f98aSLandon J. Fuller 
7858a03f98aSLandon J. Fuller 	return (0);
7868a03f98aSLandon J. Fuller }
7878a03f98aSLandon J. Fuller 
7888a03f98aSLandon J. Fuller static int
siba_suspend_hw(device_t dev,device_t child,uint16_t ioctl)789ac59515bSLandon J. Fuller siba_suspend_hw(device_t dev, device_t child, uint16_t ioctl)
790f90f4b65SLandon J. Fuller {
7914e96bf3aSLandon J. Fuller 	struct siba_softc		*sc;
792b24852c2SLandon J. Fuller 	struct siba_devinfo		*dinfo;
7938a03f98aSLandon J. Fuller 	struct bhnd_resource		*r;
794ac59515bSLandon J. Fuller 	uint32_t			 idl, ts_low, ts_mask;
795ac59515bSLandon J. Fuller 	uint16_t			 cflags, clkflags;
7968a03f98aSLandon J. Fuller 	int				 error;
797b24852c2SLandon J. Fuller 
798b24852c2SLandon J. Fuller 	if (device_get_parent(child) != dev)
7998a03f98aSLandon J. Fuller 		return (EINVAL);
800b24852c2SLandon J. Fuller 
8014e96bf3aSLandon J. Fuller 	sc = device_get_softc(dev);
802b24852c2SLandon J. Fuller 	dinfo = device_get_ivars(child);
803b24852c2SLandon J. Fuller 
8048a03f98aSLandon J. Fuller 	/* Can't suspend the core without access to the CFG0 registers */
805caeff9a3SLandon J. Fuller 	if ((r = dinfo->cfg_res[0]) == NULL)
8068a03f98aSLandon J. Fuller 		return (ENODEV);
807b24852c2SLandon J. Fuller 
808ac59515bSLandon J. Fuller 	/* We require exclusive control over BHND_IOCTL_CLK_(EN|FORCE) */
809ac59515bSLandon J. Fuller 	clkflags = BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE;
810ac59515bSLandon J. Fuller 	if (ioctl & clkflags)
811ac59515bSLandon J. Fuller 		return (EINVAL);
812ac59515bSLandon J. Fuller 
8138a03f98aSLandon J. Fuller 	/* Already in RESET? */
8148a03f98aSLandon J. Fuller 	ts_low = bhnd_bus_read_4(r, SIBA_CFG0_TMSTATELOW);
815ac59515bSLandon J. Fuller 	if (ts_low & SIBA_TML_RESET)
816ac59515bSLandon J. Fuller 		return (0);
8178a03f98aSLandon J. Fuller 
818ac59515bSLandon J. Fuller 	/* If clocks are already disabled, we can place the core directly
819ac59515bSLandon J. Fuller 	 * into RESET|REJ while setting the caller's IOCTL flags. */
820ac59515bSLandon J. Fuller 	cflags = SIBA_REG_GET(ts_low, TML_SICF);
821ac59515bSLandon J. Fuller 	if (!(cflags & BHND_IOCTL_CLK_EN)) {
822ac59515bSLandon J. Fuller 		ts_low = SIBA_TML_RESET | SIBA_TML_REJ |
823ac59515bSLandon J. Fuller 			 (ioctl << SIBA_TML_SICF_SHIFT);
824ac59515bSLandon J. Fuller 		ts_mask = SIBA_TML_RESET | SIBA_TML_REJ | SIBA_TML_SICF_MASK;
825ac59515bSLandon J. Fuller 
826ac59515bSLandon J. Fuller 		siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
827ac59515bSLandon J. Fuller 		    ts_low, ts_mask);
8288a03f98aSLandon J. Fuller 		return (0);
829b24852c2SLandon J. Fuller 	}
830b24852c2SLandon J. Fuller 
831ac59515bSLandon J. Fuller 	/* Reject further transactions reaching this core */
832ac59515bSLandon J. Fuller 	siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW,
8338a03f98aSLandon J. Fuller 	    SIBA_TML_REJ, SIBA_TML_REJ);
834ac59515bSLandon J. Fuller 
835ac59515bSLandon J. Fuller 	/* Wait for transaction busy flag to clear for all transactions
836ac59515bSLandon J. Fuller 	 * initiated by this core */
837ac59515bSLandon J. Fuller 	error = siba_wait_target_state(child, dinfo, SIBA_CFG0_TMSTATEHIGH,
838ac59515bSLandon J. Fuller 	    0x0, SIBA_TMH_BUSY, 100000);
8398a03f98aSLandon J. Fuller 	if (error)
8408a03f98aSLandon J. Fuller 		return (error);
8418a03f98aSLandon J. Fuller 
8428a03f98aSLandon J. Fuller 	/* If this is an initiator core, we need to reject initiator
8438a03f98aSLandon J. Fuller 	 * transactions too. */
8448a03f98aSLandon J. Fuller 	idl = bhnd_bus_read_4(r, SIBA_CFG0_IDLOW);
8458a03f98aSLandon J. Fuller 	if (idl & SIBA_IDL_INIT) {
846ac59515bSLandon J. Fuller 		/* Reject further initiator transactions */
847ac59515bSLandon J. Fuller 		siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
8488a03f98aSLandon J. Fuller 		    SIBA_IM_RJ, SIBA_IM_RJ);
849ac59515bSLandon J. Fuller 
850ac59515bSLandon J. Fuller 		/* Wait for initiator busy flag to clear */
851ac59515bSLandon J. Fuller 		error = siba_wait_target_state(child, dinfo, SIBA_CFG0_IMSTATE,
852ac59515bSLandon J. Fuller 		    0x0, SIBA_IM_BY, 100000);
8538a03f98aSLandon J. Fuller 		if (error)
8548a03f98aSLandon J. Fuller 			return (error);
8558a03f98aSLandon J. Fuller 	}
8568a03f98aSLandon J. Fuller 
857ac59515bSLandon J. Fuller 	/* Put the core into RESET, set the caller's IOCTL flags, and
858ac59515bSLandon J. Fuller 	 * force clocks to ensure the RESET signal propagates throughout the
859ac59515bSLandon J. Fuller 	 * core. */
860ac59515bSLandon J. Fuller 	ts_low = SIBA_TML_RESET |
861ac59515bSLandon J. Fuller 		 (ioctl << SIBA_TML_SICF_SHIFT) |
862ac59515bSLandon J. Fuller 		 (BHND_IOCTL_CLK_EN << SIBA_TML_SICF_SHIFT) |
863ac59515bSLandon J. Fuller 		 (BHND_IOCTL_CLK_FORCE << SIBA_TML_SICF_SHIFT);
864ac59515bSLandon J. Fuller 	ts_mask = SIBA_TML_RESET |
865ac59515bSLandon J. Fuller 		  SIBA_TML_SICF_MASK;
8668a03f98aSLandon J. Fuller 
867ac59515bSLandon J. Fuller 	siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, ts_low,
868ac59515bSLandon J. Fuller 	    ts_mask);
8698a03f98aSLandon J. Fuller 
8708a03f98aSLandon J. Fuller 	/* Give RESET ample time */
8718a03f98aSLandon J. Fuller 	DELAY(10);
8728a03f98aSLandon J. Fuller 
8738a03f98aSLandon J. Fuller 	/* Clear previously asserted initiator reject */
8748a03f98aSLandon J. Fuller 	if (idl & SIBA_IDL_INIT) {
875ac59515bSLandon J. Fuller 		siba_write_target_state(child, dinfo, SIBA_CFG0_IMSTATE, 0x0,
876ac59515bSLandon J. Fuller 		    SIBA_IM_RJ);
8778a03f98aSLandon J. Fuller 	}
8788a03f98aSLandon J. Fuller 
879ac59515bSLandon J. Fuller 	/* Disable all clocks, leaving RESET and REJ asserted */
880ac59515bSLandon J. Fuller 	siba_write_target_state(child, dinfo, SIBA_CFG0_TMSTATELOW, 0x0,
881ac59515bSLandon J. Fuller 	    (BHND_IOCTL_CLK_EN | BHND_IOCTL_CLK_FORCE) << SIBA_TML_SICF_SHIFT);
882ac59515bSLandon J. Fuller 
8834e96bf3aSLandon J. Fuller 	/*
884ac59515bSLandon J. Fuller 	 * Core is now in RESET.
8858a03f98aSLandon J. Fuller 	 *
8864e96bf3aSLandon J. Fuller 	 * If the core holds any PWRCTL clock reservations, we need to release
8874e96bf3aSLandon J. Fuller 	 * those now. This emulates the standard bhnd(4) PMU behavior of RESET
8884e96bf3aSLandon J. Fuller 	 * automatically clearing clkctl
8894e96bf3aSLandon J. Fuller 	 */
8904e96bf3aSLandon J. Fuller 	SIBA_LOCK(sc);
8914e96bf3aSLandon J. Fuller 	if (dinfo->pmu_state == SIBA_PMU_PWRCTL) {
8924e96bf3aSLandon J. Fuller 		error = bhnd_pwrctl_request_clock(dinfo->pmu.pwrctl, child,
8934e96bf3aSLandon J. Fuller 		    BHND_CLOCK_DYN);
8944e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
8954e96bf3aSLandon J. Fuller 
8964e96bf3aSLandon J. Fuller 		if (error) {
8974e96bf3aSLandon J. Fuller 			device_printf(child, "failed to release clock request: "
8984e96bf3aSLandon J. Fuller 			    "%d", error);
8998a03f98aSLandon J. Fuller 			return (error);
9008a03f98aSLandon J. Fuller 		}
9018a03f98aSLandon J. Fuller 
9028a03f98aSLandon J. Fuller 		return (0);
9034e96bf3aSLandon J. Fuller 	} else {
9044e96bf3aSLandon J. Fuller 		SIBA_UNLOCK(sc);
9054e96bf3aSLandon J. Fuller 		return (0);
9064e96bf3aSLandon J. Fuller 	}
9078a03f98aSLandon J. Fuller }
9088a03f98aSLandon J. Fuller 
9098a03f98aSLandon J. Fuller static int
siba_read_config(device_t dev,device_t child,bus_size_t offset,void * value,u_int width)9108a03f98aSLandon J. Fuller siba_read_config(device_t dev, device_t child, bus_size_t offset, void *value,
911f90f4b65SLandon J. Fuller     u_int width)
912f90f4b65SLandon J. Fuller {
913b24852c2SLandon J. Fuller 	struct siba_devinfo	*dinfo;
914b24852c2SLandon J. Fuller 	rman_res_t		 r_size;
915b24852c2SLandon J. Fuller 
916b24852c2SLandon J. Fuller 	/* Must be directly attached */
917b24852c2SLandon J. Fuller 	if (device_get_parent(child) != dev)
9188a03f98aSLandon J. Fuller 		return (EINVAL);
919b24852c2SLandon J. Fuller 
920b24852c2SLandon J. Fuller 	/* CFG0 registers must be available */
921b24852c2SLandon J. Fuller 	dinfo = device_get_ivars(child);
922caeff9a3SLandon J. Fuller 	if (dinfo->cfg_res[0] == NULL)
9238a03f98aSLandon J. Fuller 		return (ENODEV);
924b24852c2SLandon J. Fuller 
925b24852c2SLandon J. Fuller 	/* Offset must fall within CFG0 */
926caeff9a3SLandon J. Fuller 	r_size = rman_get_size(dinfo->cfg_res[0]->res);
927b24852c2SLandon J. Fuller 	if (r_size < offset || r_size - offset < width)
9288a03f98aSLandon J. Fuller 		return (EFAULT);
929b24852c2SLandon J. Fuller 
930b24852c2SLandon J. Fuller 	switch (width) {
931b24852c2SLandon J. Fuller 	case 1:
932caeff9a3SLandon J. Fuller 		*((uint8_t *)value) = bhnd_bus_read_1(dinfo->cfg_res[0],
933caeff9a3SLandon J. Fuller 		    offset);
9348a03f98aSLandon J. Fuller 		return (0);
935b24852c2SLandon J. Fuller 	case 2:
936caeff9a3SLandon J. Fuller 		*((uint16_t *)value) = bhnd_bus_read_2(dinfo->cfg_res[0],
937caeff9a3SLandon J. Fuller 		    offset);
9388a03f98aSLandon J. Fuller 		return (0);
939b24852c2SLandon J. Fuller 	case 4:
940caeff9a3SLandon J. Fuller 		*((uint32_t *)value) = bhnd_bus_read_4(dinfo->cfg_res[0],
941caeff9a3SLandon J. Fuller 		    offset);
9428a03f98aSLandon J. Fuller 		return (0);
9438a03f98aSLandon J. Fuller 	default:
9448a03f98aSLandon J. Fuller 		return (EINVAL);
9458a03f98aSLandon J. Fuller 	}
9468a03f98aSLandon J. Fuller }
9478a03f98aSLandon J. Fuller 
9488a03f98aSLandon J. Fuller static int
siba_write_config(device_t dev,device_t child,bus_size_t offset,const void * value,u_int width)9498a03f98aSLandon J. Fuller siba_write_config(device_t dev, device_t child, bus_size_t offset,
9508a03f98aSLandon J. Fuller     const void *value, u_int width)
9518a03f98aSLandon J. Fuller {
9528a03f98aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
9538a03f98aSLandon J. Fuller 	struct bhnd_resource	*r;
9548a03f98aSLandon J. Fuller 	rman_res_t		 r_size;
9558a03f98aSLandon J. Fuller 
9568a03f98aSLandon J. Fuller 	/* Must be directly attached */
9578a03f98aSLandon J. Fuller 	if (device_get_parent(child) != dev)
9588a03f98aSLandon J. Fuller 		return (EINVAL);
9598a03f98aSLandon J. Fuller 
9608a03f98aSLandon J. Fuller 	/* CFG0 registers must be available */
9618a03f98aSLandon J. Fuller 	dinfo = device_get_ivars(child);
962caeff9a3SLandon J. Fuller 	if ((r = dinfo->cfg_res[0]) == NULL)
9638a03f98aSLandon J. Fuller 		return (ENODEV);
9648a03f98aSLandon J. Fuller 
9658a03f98aSLandon J. Fuller 	/* Offset must fall within CFG0 */
9668a03f98aSLandon J. Fuller 	r_size = rman_get_size(r->res);
9678a03f98aSLandon J. Fuller 	if (r_size < offset || r_size - offset < width)
9688a03f98aSLandon J. Fuller 		return (EFAULT);
9698a03f98aSLandon J. Fuller 
9708a03f98aSLandon J. Fuller 	switch (width) {
9718a03f98aSLandon J. Fuller 	case 1:
9728a03f98aSLandon J. Fuller 		bhnd_bus_write_1(r, offset, *(const uint8_t *)value);
9738a03f98aSLandon J. Fuller 		return (0);
9748a03f98aSLandon J. Fuller 	case 2:
9758a03f98aSLandon J. Fuller 		bhnd_bus_write_2(r, offset, *(const uint8_t *)value);
9768a03f98aSLandon J. Fuller 		return (0);
9778a03f98aSLandon J. Fuller 	case 4:
9788a03f98aSLandon J. Fuller 		bhnd_bus_write_4(r, offset, *(const uint8_t *)value);
9798a03f98aSLandon J. Fuller 		return (0);
9808a03f98aSLandon J. Fuller 	default:
9818a03f98aSLandon J. Fuller 		return (EINVAL);
982b24852c2SLandon J. Fuller 	}
983f90f4b65SLandon J. Fuller }
9844ad7e9b0SAdrian Chadd 
9854ad7e9b0SAdrian Chadd static u_int
siba_get_port_count(device_t dev,device_t child,bhnd_port_type type)9864ad7e9b0SAdrian Chadd siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
9874ad7e9b0SAdrian Chadd {
9884ad7e9b0SAdrian Chadd 	struct siba_devinfo *dinfo;
9894ad7e9b0SAdrian Chadd 
9904ad7e9b0SAdrian Chadd 	/* delegate non-bus-attached devices to our parent */
9914ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
9924ad7e9b0SAdrian Chadd 		return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
9934ad7e9b0SAdrian Chadd 		    type));
9944ad7e9b0SAdrian Chadd 
9954ad7e9b0SAdrian Chadd 	dinfo = device_get_ivars(child);
996caeff9a3SLandon J. Fuller 	return (siba_port_count(&dinfo->core_id, type));
9974ad7e9b0SAdrian Chadd }
9984ad7e9b0SAdrian Chadd 
9994ad7e9b0SAdrian Chadd static u_int
siba_get_region_count(device_t dev,device_t child,bhnd_port_type type,u_int port)10004ad7e9b0SAdrian Chadd siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
100106018a8eSLandon J. Fuller     u_int port)
10024ad7e9b0SAdrian Chadd {
10034ad7e9b0SAdrian Chadd 	struct siba_devinfo	*dinfo;
10044ad7e9b0SAdrian Chadd 
10054ad7e9b0SAdrian Chadd 	/* delegate non-bus-attached devices to our parent */
10064ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
10074ad7e9b0SAdrian Chadd 		return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
100806018a8eSLandon J. Fuller 		    type, port));
10094ad7e9b0SAdrian Chadd 
10104ad7e9b0SAdrian Chadd 	dinfo = device_get_ivars(child);
1011caeff9a3SLandon J. Fuller 	return (siba_port_region_count(&dinfo->core_id, type, port));
10124ad7e9b0SAdrian Chadd }
10134ad7e9b0SAdrian Chadd 
10144ad7e9b0SAdrian Chadd static int
siba_get_port_rid(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num)10154ad7e9b0SAdrian Chadd siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
10164ad7e9b0SAdrian Chadd     u_int port_num, u_int region_num)
10174ad7e9b0SAdrian Chadd {
10184ad7e9b0SAdrian Chadd 	struct siba_devinfo	*dinfo;
10194ad7e9b0SAdrian Chadd 	struct siba_addrspace	*addrspace;
1020caeff9a3SLandon J. Fuller 	struct siba_cfg_block	*cfg;
10214ad7e9b0SAdrian Chadd 
10224ad7e9b0SAdrian Chadd 	/* delegate non-bus-attached devices to our parent */
10234ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
10244ad7e9b0SAdrian Chadd 		return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
10254ad7e9b0SAdrian Chadd 		    port_type, port_num, region_num));
10264ad7e9b0SAdrian Chadd 
10274ad7e9b0SAdrian Chadd 	dinfo = device_get_ivars(child);
10284ad7e9b0SAdrian Chadd 
1029caeff9a3SLandon J. Fuller 	/* Look for a matching addrspace entry */
1030caeff9a3SLandon J. Fuller 	addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
1031caeff9a3SLandon J. Fuller 	if (addrspace != NULL)
10324ad7e9b0SAdrian Chadd 		return (addrspace->sa_rid);
1033caeff9a3SLandon J. Fuller 
1034caeff9a3SLandon J. Fuller 	/* Try the config blocks */
1035caeff9a3SLandon J. Fuller 	cfg = siba_find_cfg_block(dinfo, port_type, port_num, region_num);
1036caeff9a3SLandon J. Fuller 	if (cfg != NULL)
1037caeff9a3SLandon J. Fuller 		return (cfg->cb_rid);
1038caeff9a3SLandon J. Fuller 
1039caeff9a3SLandon J. Fuller 	/* Not found */
1040caeff9a3SLandon J. Fuller 	return (-1);
10414ad7e9b0SAdrian Chadd }
10424ad7e9b0SAdrian Chadd 
10434ad7e9b0SAdrian Chadd static int
siba_decode_port_rid(device_t dev,device_t child,int type,int rid,bhnd_port_type * port_type,u_int * port_num,u_int * region_num)10444ad7e9b0SAdrian Chadd siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
10454ad7e9b0SAdrian Chadd     bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
10464ad7e9b0SAdrian Chadd {
10474ad7e9b0SAdrian Chadd 	struct siba_devinfo	*dinfo;
10484ad7e9b0SAdrian Chadd 
10494ad7e9b0SAdrian Chadd 	/* delegate non-bus-attached devices to our parent */
10504ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev)
10514ad7e9b0SAdrian Chadd 		return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
10524ad7e9b0SAdrian Chadd 		    type, rid, port_type, port_num, region_num));
10534ad7e9b0SAdrian Chadd 
10544ad7e9b0SAdrian Chadd 	dinfo = device_get_ivars(child);
10554ad7e9b0SAdrian Chadd 
10564ad7e9b0SAdrian Chadd 	/* Ports are always memory mapped */
10574ad7e9b0SAdrian Chadd 	if (type != SYS_RES_MEMORY)
10584ad7e9b0SAdrian Chadd 		return (EINVAL);
10594ad7e9b0SAdrian Chadd 
1060caeff9a3SLandon J. Fuller 	/* Look for a matching addrspace entry */
10617c7c726bSLandon J. Fuller 	for (u_int i = 0; i < dinfo->core_id.num_admatch; i++) {
106206018a8eSLandon J. Fuller 		if (dinfo->addrspace[i].sa_rid != rid)
10634ad7e9b0SAdrian Chadd 			continue;
10644ad7e9b0SAdrian Chadd 
106506018a8eSLandon J. Fuller 		*port_type = BHND_PORT_DEVICE;
1066caeff9a3SLandon J. Fuller 		*port_num = siba_addrspace_device_port(i);
1067caeff9a3SLandon J. Fuller 		*region_num = siba_addrspace_device_region(i);
1068caeff9a3SLandon J. Fuller 		return (0);
1069caeff9a3SLandon J. Fuller 	}
1070caeff9a3SLandon J. Fuller 
1071caeff9a3SLandon J. Fuller 	/* Try the config blocks */
1072caeff9a3SLandon J. Fuller 	for (u_int i = 0; i < dinfo->core_id.num_cfg_blocks; i++) {
1073caeff9a3SLandon J. Fuller 		if (dinfo->cfg[i].cb_rid != rid)
1074caeff9a3SLandon J. Fuller 			continue;
1075caeff9a3SLandon J. Fuller 
1076caeff9a3SLandon J. Fuller 		*port_type = BHND_PORT_AGENT;
1077caeff9a3SLandon J. Fuller 		*port_num = siba_cfg_agent_port(i);
1078caeff9a3SLandon J. Fuller 		*region_num = siba_cfg_agent_region(i);
107906018a8eSLandon J. Fuller 		return (0);
10804ad7e9b0SAdrian Chadd 	}
10814ad7e9b0SAdrian Chadd 
108206018a8eSLandon J. Fuller 	/* Not found */
10834ad7e9b0SAdrian Chadd 	return (ENOENT);
10844ad7e9b0SAdrian Chadd }
10854ad7e9b0SAdrian Chadd 
10864ad7e9b0SAdrian Chadd static int
siba_get_region_addr(device_t dev,device_t child,bhnd_port_type port_type,u_int port_num,u_int region_num,bhnd_addr_t * addr,bhnd_size_t * size)10874ad7e9b0SAdrian Chadd siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
10884ad7e9b0SAdrian Chadd     u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
10894ad7e9b0SAdrian Chadd {
10904ad7e9b0SAdrian Chadd 	struct siba_devinfo	*dinfo;
10914ad7e9b0SAdrian Chadd 	struct siba_addrspace	*addrspace;
1092caeff9a3SLandon J. Fuller 	struct siba_cfg_block	*cfg;
10934ad7e9b0SAdrian Chadd 
10944ad7e9b0SAdrian Chadd 	/* delegate non-bus-attached devices to our parent */
10954ad7e9b0SAdrian Chadd 	if (device_get_parent(child) != dev) {
10964ad7e9b0SAdrian Chadd 		return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
10974ad7e9b0SAdrian Chadd 		    port_type, port_num, region_num, addr, size));
10984ad7e9b0SAdrian Chadd 	}
10994ad7e9b0SAdrian Chadd 
11004ad7e9b0SAdrian Chadd 	dinfo = device_get_ivars(child);
11014ad7e9b0SAdrian Chadd 
1102caeff9a3SLandon J. Fuller 	/* Look for a matching addrspace */
1103caeff9a3SLandon J. Fuller 	addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
1104caeff9a3SLandon J. Fuller 	if (addrspace != NULL) {
11054ad7e9b0SAdrian Chadd 		*addr = addrspace->sa_base;
1106f4a3eb02SAdrian Chadd 		*size = addrspace->sa_size - addrspace->sa_bus_reserved;
11074ad7e9b0SAdrian Chadd 		return (0);
11084ad7e9b0SAdrian Chadd 	}
11094ad7e9b0SAdrian Chadd 
1110caeff9a3SLandon J. Fuller 	/* Look for a matching cfg block */
1111caeff9a3SLandon J. Fuller 	cfg = siba_find_cfg_block(dinfo, port_type, port_num, region_num);
1112caeff9a3SLandon J. Fuller 	if (cfg != NULL) {
1113caeff9a3SLandon J. Fuller 		*addr = cfg->cb_base;
1114caeff9a3SLandon J. Fuller 		*size = cfg->cb_size;
1115caeff9a3SLandon J. Fuller 		return (0);
1116caeff9a3SLandon J. Fuller 	}
1117caeff9a3SLandon J. Fuller 
1118caeff9a3SLandon J. Fuller 	/* Not found */
1119caeff9a3SLandon J. Fuller 	return (ENOENT);
1120caeff9a3SLandon J. Fuller }
1121caeff9a3SLandon J. Fuller 
1122824b48efSLandon J. Fuller /**
1123824b48efSLandon J. Fuller  * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
1124824b48efSLandon J. Fuller  */
1125caeff9a3SLandon J. Fuller u_int
siba_get_intr_count(device_t dev,device_t child)1126824b48efSLandon J. Fuller siba_get_intr_count(device_t dev, device_t child)
1127824b48efSLandon J. Fuller {
1128824b48efSLandon J. Fuller 	struct siba_devinfo	*dinfo;
1129824b48efSLandon J. Fuller 
1130824b48efSLandon J. Fuller 	/* delegate non-bus-attached devices to our parent */
1131824b48efSLandon J. Fuller 	if (device_get_parent(child) != dev)
1132824b48efSLandon J. Fuller 		return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
1133824b48efSLandon J. Fuller 
1134824b48efSLandon J. Fuller 	dinfo = device_get_ivars(child);
11357c7c726bSLandon J. Fuller 	if (!dinfo->core_id.intr_en) {
1136caeff9a3SLandon J. Fuller 		/* No interrupts */
1137824b48efSLandon J. Fuller 		return (0);
1138caeff9a3SLandon J. Fuller 	} else {
1139caeff9a3SLandon J. Fuller 		/* One assigned interrupt */
1140caeff9a3SLandon J. Fuller 		return (1);
1141caeff9a3SLandon J. Fuller 	}
1142824b48efSLandon J. Fuller }
1143824b48efSLandon J. Fuller 
1144824b48efSLandon J. Fuller /**
1145caeff9a3SLandon J. Fuller  * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_IVEC().
1146824b48efSLandon J. Fuller  */
1147824b48efSLandon J. Fuller int
siba_get_intr_ivec(device_t dev,device_t child,u_int intr,u_int * ivec)1148caeff9a3SLandon J. Fuller siba_get_intr_ivec(device_t dev, device_t child, u_int intr, u_int *ivec)
1149824b48efSLandon J. Fuller {
1150824b48efSLandon J. Fuller 	struct siba_devinfo	*dinfo;
1151824b48efSLandon J. Fuller 
1152824b48efSLandon J. Fuller 	/* delegate non-bus-attached devices to our parent */
1153824b48efSLandon J. Fuller 	if (device_get_parent(child) != dev)
1154caeff9a3SLandon J. Fuller 		return (BHND_BUS_GET_INTR_IVEC(device_get_parent(dev), child,
1155824b48efSLandon J. Fuller 		    intr, ivec));
1156824b48efSLandon J. Fuller 
1157824b48efSLandon J. Fuller 	/* Must be a valid interrupt ID */
1158824b48efSLandon J. Fuller 	if (intr >= siba_get_intr_count(dev, child))
1159824b48efSLandon J. Fuller 		return (ENXIO);
1160824b48efSLandon J. Fuller 
1161caeff9a3SLandon J. Fuller 	KASSERT(intr == 0, ("invalid ivec %u", intr));
1162824b48efSLandon J. Fuller 
1163caeff9a3SLandon J. Fuller 	dinfo = device_get_ivars(child);
1164caeff9a3SLandon J. Fuller 
11657c7c726bSLandon J. Fuller 	KASSERT(dinfo->core_id.intr_en,
11667c7c726bSLandon J. Fuller 	    ("core does not have an interrupt assigned"));
11674ad7e9b0SAdrian Chadd 
11687c7c726bSLandon J. Fuller 	*ivec = dinfo->core_id.intr_flag;
1169caeff9a3SLandon J. Fuller 	return (0);
1170caeff9a3SLandon J. Fuller }
1171caeff9a3SLandon J. Fuller 
1172111d7cb2SLandon J. Fuller /**
1173111d7cb2SLandon J. Fuller  * Map per-core configuration blocks for @p dinfo.
1174111d7cb2SLandon J. Fuller  *
1175111d7cb2SLandon J. Fuller  * @param dev The siba bus device.
1176111d7cb2SLandon J. Fuller  * @param dinfo The device info instance on which to map all per-core
1177111d7cb2SLandon J. Fuller  * configuration blocks.
1178111d7cb2SLandon J. Fuller  */
1179111d7cb2SLandon J. Fuller static int
siba_map_cfg_resources(device_t dev,struct siba_devinfo * dinfo)1180111d7cb2SLandon J. Fuller siba_map_cfg_resources(device_t dev, struct siba_devinfo *dinfo)
1181111d7cb2SLandon J. Fuller {
1182111d7cb2SLandon J. Fuller 	struct siba_addrspace	*addrspace;
1183111d7cb2SLandon J. Fuller 	rman_res_t		 r_start, r_count, r_end;
1184111d7cb2SLandon J. Fuller 	uint8_t			 num_cfg;
1185caeff9a3SLandon J. Fuller 	int			 rid;
1186111d7cb2SLandon J. Fuller 
1187111d7cb2SLandon J. Fuller 	num_cfg = dinfo->core_id.num_cfg_blocks;
1188111d7cb2SLandon J. Fuller 	if (num_cfg > SIBA_MAX_CFG) {
1189111d7cb2SLandon J. Fuller 		device_printf(dev, "config block count %hhu out of range\n",
1190111d7cb2SLandon J. Fuller 		    num_cfg);
1191111d7cb2SLandon J. Fuller 		return (ENXIO);
1192111d7cb2SLandon J. Fuller 	}
1193111d7cb2SLandon J. Fuller 
1194111d7cb2SLandon J. Fuller 	/* Fetch the core register address space */
1195111d7cb2SLandon J. Fuller 	addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
1196111d7cb2SLandon J. Fuller 	if (addrspace == NULL) {
1197111d7cb2SLandon J. Fuller 		device_printf(dev, "missing device registers\n");
1198111d7cb2SLandon J. Fuller 		return (ENXIO);
1199111d7cb2SLandon J. Fuller 	}
1200111d7cb2SLandon J. Fuller 
1201111d7cb2SLandon J. Fuller 	/*
1202111d7cb2SLandon J. Fuller 	 * Map the per-core configuration blocks
1203111d7cb2SLandon J. Fuller 	 */
1204111d7cb2SLandon J. Fuller 	for (uint8_t i = 0; i < num_cfg; i++) {
1205caeff9a3SLandon J. Fuller 		/* Add to child's resource list */
1206caeff9a3SLandon J. Fuller 		r_start = addrspace->sa_base + SIBA_CFG_OFFSET(i);
1207111d7cb2SLandon J. Fuller 		r_count = SIBA_CFG_SIZE;
1208111d7cb2SLandon J. Fuller 		r_end = r_start + r_count - 1;
1209111d7cb2SLandon J. Fuller 
1210caeff9a3SLandon J. Fuller 		rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
1211caeff9a3SLandon J. Fuller 		    r_start, r_end, r_count);
1212111d7cb2SLandon J. Fuller 
1213caeff9a3SLandon J. Fuller 		/* Initialize config block descriptor */
1214caeff9a3SLandon J. Fuller 		dinfo->cfg[i] = ((struct siba_cfg_block) {
1215caeff9a3SLandon J. Fuller 			.cb_base = r_start,
1216caeff9a3SLandon J. Fuller 			.cb_size = SIBA_CFG_SIZE,
1217caeff9a3SLandon J. Fuller 			.cb_rid = rid
1218caeff9a3SLandon J. Fuller 		});
1219caeff9a3SLandon J. Fuller 
1220caeff9a3SLandon J. Fuller 		/* Map the config resource for bus-level access */
1221caeff9a3SLandon J. Fuller 		dinfo->cfg_rid[i] = SIBA_CFG_RID(dinfo, i);
1222caeff9a3SLandon J. Fuller 		dinfo->cfg_res[i] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
1223caeff9a3SLandon J. Fuller 		    SYS_RES_MEMORY, &dinfo->cfg_rid[i], r_start, r_end,
1224caeff9a3SLandon J. Fuller 		    r_count, RF_ACTIVE|RF_SHAREABLE);
1225caeff9a3SLandon J. Fuller 
1226caeff9a3SLandon J. Fuller 		if (dinfo->cfg_res[i] == NULL) {
1227111d7cb2SLandon J. Fuller 			device_printf(dev, "failed to allocate SIBA_CFG%hhu\n",
1228111d7cb2SLandon J. Fuller 			    i);
1229111d7cb2SLandon J. Fuller 			return (ENXIO);
1230111d7cb2SLandon J. Fuller 		}
1231111d7cb2SLandon J. Fuller 	}
1232111d7cb2SLandon J. Fuller 
1233111d7cb2SLandon J. Fuller 	return (0);
1234111d7cb2SLandon J. Fuller }
1235111d7cb2SLandon J. Fuller 
12368a03f98aSLandon J. Fuller static device_t
siba_add_child(device_t dev,u_int order,const char * name,int unit)12378a03f98aSLandon J. Fuller siba_add_child(device_t dev, u_int order, const char *name, int unit)
1238688fc8c0SLandon J. Fuller {
12398a03f98aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
12408a03f98aSLandon J. Fuller 	device_t		 child;
12418a03f98aSLandon J. Fuller 
12428a03f98aSLandon J. Fuller 	child = device_add_child_ordered(dev, order, name, unit);
12438a03f98aSLandon J. Fuller 	if (child == NULL)
12448a03f98aSLandon J. Fuller 		return (NULL);
12458a03f98aSLandon J. Fuller 
12468a03f98aSLandon J. Fuller 	if ((dinfo = siba_alloc_dinfo(dev)) == NULL) {
12478a03f98aSLandon J. Fuller 		device_delete_child(dev, child);
12488a03f98aSLandon J. Fuller 		return (NULL);
12498a03f98aSLandon J. Fuller 	}
12508a03f98aSLandon J. Fuller 
12518a03f98aSLandon J. Fuller 	device_set_ivars(child, dinfo);
12528a03f98aSLandon J. Fuller 
12538a03f98aSLandon J. Fuller 	return (child);
1254688fc8c0SLandon J. Fuller }
1255688fc8c0SLandon J. Fuller 
1256688fc8c0SLandon J. Fuller static void
siba_child_deleted(device_t dev,device_t child)12578a03f98aSLandon J. Fuller siba_child_deleted(device_t dev, device_t child)
1258688fc8c0SLandon J. Fuller {
12598a03f98aSLandon J. Fuller 	struct siba_devinfo	*dinfo;
12608a03f98aSLandon J. Fuller 
12618a03f98aSLandon J. Fuller 	/* Call required bhnd(4) implementation */
12628a03f98aSLandon J. Fuller 	bhnd_generic_child_deleted(dev, child);
12638a03f98aSLandon J. Fuller 
12648a03f98aSLandon J. Fuller 	/* Free siba device info */
12658a03f98aSLandon J. Fuller 	if ((dinfo = device_get_ivars(child)) != NULL)
1266caeff9a3SLandon J. Fuller 		siba_free_dinfo(dev, child, dinfo);
12678a03f98aSLandon J. Fuller 
12688a03f98aSLandon J. Fuller 	device_set_ivars(child, NULL);
1269688fc8c0SLandon J. Fuller }
1270688fc8c0SLandon J. Fuller 
12714ad7e9b0SAdrian Chadd /**
12724ad7e9b0SAdrian Chadd  * Scan the core table and add all valid discovered cores to
12734ad7e9b0SAdrian Chadd  * the bus.
12744ad7e9b0SAdrian Chadd  *
12754ad7e9b0SAdrian Chadd  * @param dev The siba bus device.
12764ad7e9b0SAdrian Chadd  */
12774ad7e9b0SAdrian Chadd int
siba_add_children(device_t dev)1278111d7cb2SLandon J. Fuller siba_add_children(device_t dev)
12794ad7e9b0SAdrian Chadd {
12807c7c726bSLandon J. Fuller 	bhnd_erom_t			*erom;
12817c7c726bSLandon J. Fuller 	struct siba_erom		*siba_erom;
12827c7c726bSLandon J. Fuller 	struct bhnd_erom_io		*eio;
12837c7c726bSLandon J. Fuller 	const struct bhnd_chipid	*cid;
128489294a78SLandon J. Fuller 	struct siba_core_id		*cores;
128589294a78SLandon J. Fuller 	device_t			*children;
12864ad7e9b0SAdrian Chadd 	int				 error;
12874ad7e9b0SAdrian Chadd 
12887c7c726bSLandon J. Fuller 	cid = BHND_BUS_GET_CHIPID(dev, dev);
12894ad7e9b0SAdrian Chadd 
12907c7c726bSLandon J. Fuller 	/* Allocate our EROM parser */
12917c7c726bSLandon J. Fuller 	eio = bhnd_erom_iores_new(dev, SIBA_EROM_RID);
12927c7c726bSLandon J. Fuller 	erom = bhnd_erom_alloc(&siba_erom_parser, cid, eio);
12937c7c726bSLandon J. Fuller 	if (erom == NULL) {
12947c7c726bSLandon J. Fuller 		bhnd_erom_io_fini(eio);
12957c7c726bSLandon J. Fuller 		return (ENODEV);
12967c7c726bSLandon J. Fuller 	}
12974ad7e9b0SAdrian Chadd 
129889294a78SLandon J. Fuller 	/* Allocate our temporary core and device table */
12997c7c726bSLandon J. Fuller 	cores = malloc(sizeof(*cores) * cid->ncores, M_BHND, M_WAITOK);
13007c7c726bSLandon J. Fuller 	children = malloc(sizeof(*children) * cid->ncores, M_BHND,
130189294a78SLandon J. Fuller 	    M_WAITOK | M_ZERO);
13024ad7e9b0SAdrian Chadd 
130389294a78SLandon J. Fuller 	/*
130489294a78SLandon J. Fuller 	 * Add child devices for all discovered cores.
130589294a78SLandon J. Fuller 	 *
130689294a78SLandon J. Fuller 	 * On bridged devices, we'll exhaust our available register windows if
130789294a78SLandon J. Fuller 	 * we map config blocks on unpopulated/disabled cores. To avoid this, we
130889294a78SLandon J. Fuller 	 * defer mapping of the per-core siba(4) config blocks until all cores
130989294a78SLandon J. Fuller 	 * have been enumerated and otherwise configured.
131089294a78SLandon J. Fuller 	 */
13117c7c726bSLandon J. Fuller 	siba_erom = (struct siba_erom *)erom;
13127c7c726bSLandon J. Fuller 	for (u_int i = 0; i < cid->ncores; i++) {
131389294a78SLandon J. Fuller 		struct siba_devinfo	*dinfo;
1314caeff9a3SLandon J. Fuller 		device_t		 child;
13154ad7e9b0SAdrian Chadd 
13167c7c726bSLandon J. Fuller 		if ((error = siba_erom_get_core_id(siba_erom, i, &cores[i])))
131789294a78SLandon J. Fuller 			goto failed;
131889294a78SLandon J. Fuller 
131989294a78SLandon J. Fuller 		/* Add the child device */
1320a05a6804SWarner Losh 		child = BUS_ADD_CHILD(dev, 0, NULL, DEVICE_UNIT_ANY);
1321caeff9a3SLandon J. Fuller 		if (child == NULL) {
132289294a78SLandon J. Fuller 			error = ENXIO;
132389294a78SLandon J. Fuller 			goto failed;
13244ad7e9b0SAdrian Chadd 		}
13254ad7e9b0SAdrian Chadd 
1326caeff9a3SLandon J. Fuller 		children[i] = child;
1327caeff9a3SLandon J. Fuller 
1328688fc8c0SLandon J. Fuller 		/* Initialize per-device bus info */
1329caeff9a3SLandon J. Fuller 		if ((dinfo = device_get_ivars(child)) == NULL) {
13304ad7e9b0SAdrian Chadd 			error = ENXIO;
133189294a78SLandon J. Fuller 			goto failed;
13324ad7e9b0SAdrian Chadd 		}
13334ad7e9b0SAdrian Chadd 
13347c7c726bSLandon J. Fuller 		if ((error = siba_init_dinfo(dev, child, dinfo, &cores[i])))
133589294a78SLandon J. Fuller 			goto failed;
1336688fc8c0SLandon J. Fuller 
133789294a78SLandon J. Fuller 		/* If pins are floating or the hardware is otherwise
133889294a78SLandon J. Fuller 		 * unpopulated, the device shouldn't be used. */
1339caeff9a3SLandon J. Fuller 		if (bhnd_is_hw_disabled(child))
1340caeff9a3SLandon J. Fuller 			device_disable(child);
134189294a78SLandon J. Fuller 	}
134289294a78SLandon J. Fuller 
13437c7c726bSLandon J. Fuller 	/* Free EROM (and any bridge register windows it might hold) */
13447c7c726bSLandon J. Fuller 	bhnd_erom_free(erom);
13457c7c726bSLandon J. Fuller 	erom = NULL;
13467c7c726bSLandon J. Fuller 
134789294a78SLandon J. Fuller 	/* Map all valid core's config register blocks and perform interrupt
134889294a78SLandon J. Fuller 	 * assignment */
13497c7c726bSLandon J. Fuller 	for (u_int i = 0; i < cid->ncores; i++) {
135089294a78SLandon J. Fuller 		struct siba_devinfo	*dinfo;
135189294a78SLandon J. Fuller 		device_t		 child;
135289294a78SLandon J. Fuller 
135389294a78SLandon J. Fuller 		child = children[i];
135489294a78SLandon J. Fuller 
135589294a78SLandon J. Fuller 		/* Skip if core is disabled */
135689294a78SLandon J. Fuller 		if (bhnd_is_hw_disabled(child))
135789294a78SLandon J. Fuller 			continue;
135889294a78SLandon J. Fuller 
135989294a78SLandon J. Fuller 		dinfo = device_get_ivars(child);
136089294a78SLandon J. Fuller 
1361111d7cb2SLandon J. Fuller 		/* Map the core's config blocks */
1362111d7cb2SLandon J. Fuller 		if ((error = siba_map_cfg_resources(dev, dinfo)))
136389294a78SLandon J. Fuller 			goto failed;
1364111d7cb2SLandon J. Fuller 
1365f90f4b65SLandon J. Fuller 		/* Issue bus callback for fully initialized child. */
1366f90f4b65SLandon J. Fuller 		BHND_BUS_CHILD_ADDED(dev, child);
13674ad7e9b0SAdrian Chadd 	}
13684ad7e9b0SAdrian Chadd 
13694ad7e9b0SAdrian Chadd 	free(cores, M_BHND);
137089294a78SLandon J. Fuller 	free(children, M_BHND);
137189294a78SLandon J. Fuller 
137289294a78SLandon J. Fuller 	return (0);
137389294a78SLandon J. Fuller 
137489294a78SLandon J. Fuller failed:
1375*919f911eSJohn Baldwin 	device_delete_children(dev);
137689294a78SLandon J. Fuller 
137789294a78SLandon J. Fuller 	free(cores, M_BHND);
137889294a78SLandon J. Fuller 	free(children, M_BHND);
13797c7c726bSLandon J. Fuller 	if (erom != NULL)
13807c7c726bSLandon J. Fuller 		bhnd_erom_free(erom);
13814ad7e9b0SAdrian Chadd 
13824ad7e9b0SAdrian Chadd 	return (error);
13834ad7e9b0SAdrian Chadd }
13844ad7e9b0SAdrian Chadd 
13854ad7e9b0SAdrian Chadd static device_method_t siba_methods[] = {
13864ad7e9b0SAdrian Chadd 	/* Device interface */
13874ad7e9b0SAdrian Chadd 	DEVMETHOD(device_probe,			siba_probe),
13884ad7e9b0SAdrian Chadd 	DEVMETHOD(device_attach,		siba_attach),
13894ad7e9b0SAdrian Chadd 	DEVMETHOD(device_detach,		siba_detach),
13908ef24a0dSAdrian Chadd 	DEVMETHOD(device_resume,		siba_resume),
13918ef24a0dSAdrian Chadd 	DEVMETHOD(device_suspend,		siba_suspend),
13924ad7e9b0SAdrian Chadd 
13934ad7e9b0SAdrian Chadd 	/* Bus interface */
13948a03f98aSLandon J. Fuller 	DEVMETHOD(bus_add_child,		siba_add_child),
13958a03f98aSLandon J. Fuller 	DEVMETHOD(bus_child_deleted,		siba_child_deleted),
13964ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_read_ivar,		siba_read_ivar),
13974ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_write_ivar,		siba_write_ivar),
13984ad7e9b0SAdrian Chadd 	DEVMETHOD(bus_get_resource_list,	siba_get_resource_list),
13994ad7e9b0SAdrian Chadd 
14004ad7e9b0SAdrian Chadd 	/* BHND interface */
1401111d7cb2SLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_erom_class,	siba_get_erom_class),
14024e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_alloc_pmu,		siba_alloc_pmu),
14034e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_release_pmu,		siba_release_pmu),
14044e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_request_clock,	siba_request_clock),
14054e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_enable_clocks,	siba_enable_clocks),
14064e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_request_ext_rsrc,	siba_request_ext_rsrc),
14074e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_release_ext_rsrc,	siba_release_ext_rsrc),
14084e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_clock_freq,	siba_get_clock_freq),
14094e96bf3aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_clock_latency,	siba_get_clock_latency),
14108a03f98aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_read_ioctl,		siba_read_ioctl),
14118a03f98aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_write_ioctl,		siba_write_ioctl),
14128a03f98aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_read_iost,		siba_read_iost),
14138a03f98aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_is_hw_suspended,	siba_is_hw_suspended),
14148a03f98aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_reset_hw,		siba_reset_hw),
14158a03f98aSLandon J. Fuller 	DEVMETHOD(bhnd_bus_suspend_hw,		siba_suspend_hw),
1416f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_read_config,		siba_read_config),
1417f90f4b65SLandon J. Fuller 	DEVMETHOD(bhnd_bus_write_config,	siba_write_config),
14184ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_get_port_count,	siba_get_port_count),
14194ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_get_region_count,	siba_get_region_count),
14204ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_get_port_rid,	siba_get_port_rid),
14214ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_decode_port_rid,	siba_decode_port_rid),
14224ad7e9b0SAdrian Chadd 	DEVMETHOD(bhnd_bus_get_region_addr,	siba_get_region_addr),
1423824b48efSLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_intr_count,	siba_get_intr_count),
1424caeff9a3SLandon J. Fuller 	DEVMETHOD(bhnd_bus_get_intr_ivec,	siba_get_intr_ivec),
14254ad7e9b0SAdrian Chadd 
14264ad7e9b0SAdrian Chadd 	DEVMETHOD_END
14274ad7e9b0SAdrian Chadd };
14284ad7e9b0SAdrian Chadd 
14294ad7e9b0SAdrian Chadd DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
14304ad7e9b0SAdrian Chadd 
14314ad7e9b0SAdrian Chadd MODULE_VERSION(siba, 1);
14324ad7e9b0SAdrian Chadd MODULE_DEPEND(siba, bhnd, 1, 1, 1);
1433