xref: /freebsd/sys/dev/bhnd/siba/siba_subr.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
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/limits.h>
384ad7e9b0SAdrian Chadd #include <sys/systm.h>
394ad7e9b0SAdrian Chadd 
404ad7e9b0SAdrian Chadd #include <machine/bus.h>
414ad7e9b0SAdrian Chadd #include <machine/resource.h>
424ad7e9b0SAdrian Chadd 
434ad7e9b0SAdrian Chadd #include <dev/bhnd/bhndvar.h>
444ad7e9b0SAdrian Chadd 
454ad7e9b0SAdrian Chadd #include "sibareg.h"
464ad7e9b0SAdrian Chadd #include "sibavar.h"
474ad7e9b0SAdrian Chadd 
48*7c7c726bSLandon J. Fuller static int	siba_register_interrupts(device_t dev, device_t child,
49*7c7c726bSLandon J. Fuller 		    struct siba_devinfo *dinfo);
50*7c7c726bSLandon J. Fuller static int	siba_append_dinfo_region(struct siba_devinfo *dinfo,
51*7c7c726bSLandon J. Fuller 		     uint8_t addridx, uint32_t base, uint32_t size,
52*7c7c726bSLandon J. Fuller 		     uint32_t bus_reserved);
53*7c7c726bSLandon J. Fuller 
544ad7e9b0SAdrian Chadd /**
554ad7e9b0SAdrian Chadd  * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
564ad7e9b0SAdrian Chadd  * code.
574ad7e9b0SAdrian Chadd  *
584ad7e9b0SAdrian Chadd  * @param ocp_vendor An OCP vendor code.
594ad7e9b0SAdrian Chadd  * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
604ad7e9b0SAdrian Chadd  * BHND_MFGID_INVALID if the OCP vendor is unknown.
614ad7e9b0SAdrian Chadd  */
624ad7e9b0SAdrian Chadd uint16_t
siba_get_bhnd_mfgid(uint16_t ocp_vendor)634ad7e9b0SAdrian Chadd siba_get_bhnd_mfgid(uint16_t ocp_vendor)
644ad7e9b0SAdrian Chadd {
654ad7e9b0SAdrian Chadd 	switch (ocp_vendor) {
664ad7e9b0SAdrian Chadd 	case OCP_VENDOR_BCM:
674ad7e9b0SAdrian Chadd 		return (BHND_MFGID_BCM);
684ad7e9b0SAdrian Chadd 	default:
694ad7e9b0SAdrian Chadd 		return (BHND_MFGID_INVALID);
704ad7e9b0SAdrian Chadd 	}
714ad7e9b0SAdrian Chadd }
724ad7e9b0SAdrian Chadd 
734ad7e9b0SAdrian Chadd /**
74688fc8c0SLandon J. Fuller  * Allocate and return a new empty device info structure.
754ad7e9b0SAdrian Chadd  *
76688fc8c0SLandon J. Fuller  * @param bus The requesting bus device.
77688fc8c0SLandon J. Fuller  *
78688fc8c0SLandon J. Fuller  * @retval NULL if allocation failed.
794ad7e9b0SAdrian Chadd  */
804ad7e9b0SAdrian Chadd struct siba_devinfo *
siba_alloc_dinfo(device_t bus)81688fc8c0SLandon J. Fuller siba_alloc_dinfo(device_t bus)
824ad7e9b0SAdrian Chadd {
834ad7e9b0SAdrian Chadd 	struct siba_devinfo *dinfo;
844ad7e9b0SAdrian Chadd 
85688fc8c0SLandon J. Fuller 	dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT|M_ZERO);
864ad7e9b0SAdrian Chadd 	if (dinfo == NULL)
874ad7e9b0SAdrian Chadd 		return NULL;
884ad7e9b0SAdrian Chadd 
894ad7e9b0SAdrian Chadd 	for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
90caeff9a3SLandon J. Fuller 		dinfo->cfg[i] = ((struct siba_cfg_block){
91caeff9a3SLandon J. Fuller 			.cb_base = 0,
92caeff9a3SLandon J. Fuller 			.cb_size = 0,
93caeff9a3SLandon J. Fuller 			.cb_rid = -1,
94caeff9a3SLandon J. Fuller 		});
95caeff9a3SLandon J. Fuller 		dinfo->cfg_res[i] = NULL;
964ad7e9b0SAdrian Chadd 		dinfo->cfg_rid[i] = -1;
974ad7e9b0SAdrian Chadd 	}
984ad7e9b0SAdrian Chadd 
994ad7e9b0SAdrian Chadd 	resource_list_init(&dinfo->resources);
1004ad7e9b0SAdrian Chadd 
1014e96bf3aSLandon J. Fuller 	dinfo->pmu_state = SIBA_PMU_NONE;
102*7c7c726bSLandon J. Fuller 
103*7c7c726bSLandon J. Fuller 	dinfo->intr = (struct siba_intr) {
104*7c7c726bSLandon J. Fuller 		.mapped = false,
105*7c7c726bSLandon J. Fuller 		.rid = -1
106*7c7c726bSLandon J. Fuller 	};
107caeff9a3SLandon J. Fuller 
1084ad7e9b0SAdrian Chadd 	return dinfo;
1094ad7e9b0SAdrian Chadd }
1104ad7e9b0SAdrian Chadd 
1114ad7e9b0SAdrian Chadd /**
112688fc8c0SLandon J. Fuller  * Initialize a device info structure previously allocated via
113688fc8c0SLandon J. Fuller  * siba_alloc_dinfo, copying the provided core id.
114688fc8c0SLandon J. Fuller  *
115688fc8c0SLandon J. Fuller  * @param dev The requesting bus device.
116*7c7c726bSLandon J. Fuller  * @param child The siba child device.
117688fc8c0SLandon J. Fuller  * @param dinfo The device info instance.
118688fc8c0SLandon J. Fuller  * @param core Device core info.
119688fc8c0SLandon J. Fuller  *
120688fc8c0SLandon J. Fuller  * @retval 0 success
121688fc8c0SLandon J. Fuller  * @retval non-zero initialization failed.
122688fc8c0SLandon J. Fuller  */
123688fc8c0SLandon J. Fuller int
siba_init_dinfo(device_t dev,device_t child,struct siba_devinfo * dinfo,const struct siba_core_id * core_id)124*7c7c726bSLandon J. Fuller siba_init_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo,
125688fc8c0SLandon J. Fuller     const struct siba_core_id *core_id)
126688fc8c0SLandon J. Fuller {
127*7c7c726bSLandon J. Fuller 	int error;
128*7c7c726bSLandon J. Fuller 
129688fc8c0SLandon J. Fuller 	dinfo->core_id = *core_id;
130*7c7c726bSLandon J. Fuller 
131*7c7c726bSLandon J. Fuller 	/* Register all address space mappings */
132*7c7c726bSLandon J. Fuller 	for (uint8_t i = 0; i < core_id->num_admatch; i++) {
133*7c7c726bSLandon J. Fuller 		uint32_t bus_reserved;
134*7c7c726bSLandon J. Fuller 
135*7c7c726bSLandon J. Fuller 		/* If this is the device's core/enumeration addrespace,
136*7c7c726bSLandon J. Fuller 		 * reserve the Sonics configuration register blocks for the
137*7c7c726bSLandon J. Fuller 		 * use of our bus. */
138*7c7c726bSLandon J. Fuller 		bus_reserved = 0;
139*7c7c726bSLandon J. Fuller 		if (i == SIBA_CORE_ADDRSPACE)
140*7c7c726bSLandon J. Fuller 			bus_reserved = core_id->num_cfg_blocks * SIBA_CFG_SIZE;
141*7c7c726bSLandon J. Fuller 
142*7c7c726bSLandon J. Fuller 		/* Append the region info */
143*7c7c726bSLandon J. Fuller 		error = siba_append_dinfo_region(dinfo, i,
144*7c7c726bSLandon J. Fuller 		    core_id->admatch[i].am_base, core_id->admatch[i].am_size,
145*7c7c726bSLandon J. Fuller 		    bus_reserved);
146*7c7c726bSLandon J. Fuller 		if (error)
147*7c7c726bSLandon J. Fuller 			return (error);
148*7c7c726bSLandon J. Fuller 	}
149*7c7c726bSLandon J. Fuller 
150*7c7c726bSLandon J. Fuller 	/* Register all interrupt(s) */
151*7c7c726bSLandon J. Fuller 	if ((error = siba_register_interrupts(dev, child, dinfo)))
152*7c7c726bSLandon J. Fuller 		return (error);
153*7c7c726bSLandon J. Fuller 
154*7c7c726bSLandon J. Fuller 	return (0);
155*7c7c726bSLandon J. Fuller }
156*7c7c726bSLandon J. Fuller 
157*7c7c726bSLandon J. Fuller /**
158*7c7c726bSLandon J. Fuller  * Register and map all interrupts for @p dinfo.
159*7c7c726bSLandon J. Fuller  *
160*7c7c726bSLandon J. Fuller  * @param dev The siba bus device.
161*7c7c726bSLandon J. Fuller  * @param child The siba child device.
162*7c7c726bSLandon J. Fuller  * @param dinfo The device info instance on which to register all interrupt
163*7c7c726bSLandon J. Fuller  * entries.
164*7c7c726bSLandon J. Fuller  */
165*7c7c726bSLandon J. Fuller static int
siba_register_interrupts(device_t dev,device_t child,struct siba_devinfo * dinfo)166*7c7c726bSLandon J. Fuller siba_register_interrupts(device_t dev, device_t child,
167*7c7c726bSLandon J. Fuller      struct siba_devinfo *dinfo)
168*7c7c726bSLandon J. Fuller {
169*7c7c726bSLandon J. Fuller 	int error;
170*7c7c726bSLandon J. Fuller 
171*7c7c726bSLandon J. Fuller 	/* Is backplane interrupt distribution enabled for this core? */
172*7c7c726bSLandon J. Fuller 	if (!dinfo->core_id.intr_en)
173*7c7c726bSLandon J. Fuller 		return (0);
174*7c7c726bSLandon J. Fuller 
175*7c7c726bSLandon J. Fuller 	/* Have one interrupt */
176*7c7c726bSLandon J. Fuller 	dinfo->intr.mapped = false;
177*7c7c726bSLandon J. Fuller 	dinfo->intr.irq = 0;
178*7c7c726bSLandon J. Fuller 	dinfo->intr.rid = -1;
179*7c7c726bSLandon J. Fuller 
180*7c7c726bSLandon J. Fuller 	/* Map the interrupt */
181*7c7c726bSLandon J. Fuller 	error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */,
182*7c7c726bSLandon J. Fuller 	    &dinfo->intr.irq);
183*7c7c726bSLandon J. Fuller 	if (error) {
184*7c7c726bSLandon J. Fuller 		device_printf(dev, "failed mapping interrupt line for core %u: "
185*7c7c726bSLandon J. Fuller 		    "%d\n", dinfo->core_id.core_info.core_idx, error);
186*7c7c726bSLandon J. Fuller 		return (error);
187*7c7c726bSLandon J. Fuller 	}
188*7c7c726bSLandon J. Fuller 	dinfo->intr.mapped = true;
189*7c7c726bSLandon J. Fuller 
190*7c7c726bSLandon J. Fuller 	/* Update the resource list */
191*7c7c726bSLandon J. Fuller 	dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ,
192*7c7c726bSLandon J. Fuller 	    dinfo->intr.irq, dinfo->intr.irq, 1);
193*7c7c726bSLandon J. Fuller 
194688fc8c0SLandon J. Fuller 	return (0);
195688fc8c0SLandon J. Fuller }
196688fc8c0SLandon J. Fuller 
197688fc8c0SLandon J. Fuller /**
198caeff9a3SLandon J. Fuller  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
199caeff9a3SLandon J. Fuller  * number.
2004ad7e9b0SAdrian Chadd  *
20106018a8eSLandon J. Fuller  * @param addrspace Address space index.
2024ad7e9b0SAdrian Chadd  */
20306018a8eSLandon J. Fuller u_int
siba_addrspace_device_port(u_int addrspace)204caeff9a3SLandon J. Fuller siba_addrspace_device_port(u_int addrspace)
2054ad7e9b0SAdrian Chadd {
20606018a8eSLandon J. Fuller 	/* The first addrspace is always mapped to device0; the remainder
20706018a8eSLandon J. Fuller 	 * are mapped to device1 */
20806018a8eSLandon J. Fuller 	if (addrspace == 0)
20906018a8eSLandon J. Fuller 		return (0);
21006018a8eSLandon J. Fuller 	else
21106018a8eSLandon J. Fuller 		return (1);
2124ad7e9b0SAdrian Chadd }
2134ad7e9b0SAdrian Chadd 
2144ad7e9b0SAdrian Chadd /**
215caeff9a3SLandon J. Fuller  * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port
216caeff9a3SLandon J. Fuller  * region number.
2174ad7e9b0SAdrian Chadd  *
21806018a8eSLandon J. Fuller  * @param addrspace Address space index.
21906018a8eSLandon J. Fuller  */
22006018a8eSLandon J. Fuller u_int
siba_addrspace_device_region(u_int addrspace)221caeff9a3SLandon J. Fuller siba_addrspace_device_region(u_int addrspace)
22206018a8eSLandon J. Fuller {
22306018a8eSLandon J. Fuller 	/* The first addrspace is always mapped to device0.0; the remainder
22406018a8eSLandon J. Fuller 	 * are mapped to device1.0 + (n - 1) */
22506018a8eSLandon J. Fuller 	if (addrspace == 0)
22606018a8eSLandon J. Fuller 		return (0);
22706018a8eSLandon J. Fuller 	else
22806018a8eSLandon J. Fuller 		return (addrspace - 1);
22906018a8eSLandon J. Fuller }
23006018a8eSLandon J. Fuller 
23106018a8eSLandon J. Fuller /**
232caeff9a3SLandon J. Fuller  * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
233caeff9a3SLandon J. Fuller  * number.
23406018a8eSLandon J. Fuller  *
235caeff9a3SLandon J. Fuller  * @param cfg Config block index.
23606018a8eSLandon J. Fuller  */
23706018a8eSLandon J. Fuller u_int
siba_cfg_agent_port(u_int cfg)238caeff9a3SLandon J. Fuller siba_cfg_agent_port(u_int cfg)
23906018a8eSLandon J. Fuller {
240caeff9a3SLandon J. Fuller 	/* Always agent0 */
24106018a8eSLandon J. Fuller 	return (0);
24206018a8eSLandon J. Fuller }
24306018a8eSLandon J. Fuller 
24406018a8eSLandon J. Fuller /**
245caeff9a3SLandon J. Fuller  * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port
246caeff9a3SLandon J. Fuller  * region number.
24706018a8eSLandon J. Fuller  *
248caeff9a3SLandon J. Fuller  * @param cfg Config block index.
249caeff9a3SLandon J. Fuller  */
250caeff9a3SLandon J. Fuller u_int
siba_cfg_agent_region(u_int cfg)251caeff9a3SLandon J. Fuller siba_cfg_agent_region(u_int cfg)
252caeff9a3SLandon J. Fuller {
253caeff9a3SLandon J. Fuller 	/* Always agent0.<idx> */
254caeff9a3SLandon J. Fuller 	return (cfg);
255caeff9a3SLandon J. Fuller }
256caeff9a3SLandon J. Fuller 
257caeff9a3SLandon J. Fuller /**
258caeff9a3SLandon J. Fuller  * Return the number of bhnd(4) ports to advertise for the given
259caeff9a3SLandon J. Fuller  * @p core_id and @p port_type.
26006018a8eSLandon J. Fuller  *
261caeff9a3SLandon J. Fuller  * Refer to the siba_addrspace_index() and siba_cfg_index() functions for
262caeff9a3SLandon J. Fuller  * information on siba's mapping of bhnd(4) port and region identifiers.
263caeff9a3SLandon J. Fuller  *
264caeff9a3SLandon J. Fuller  * @param core_id The siba core info.
265caeff9a3SLandon J. Fuller  * @param port_type The bhnd(4) port type.
266caeff9a3SLandon J. Fuller  */
267caeff9a3SLandon J. Fuller u_int
siba_port_count(struct siba_core_id * core_id,bhnd_port_type port_type)268caeff9a3SLandon J. Fuller siba_port_count(struct siba_core_id *core_id, bhnd_port_type port_type)
269caeff9a3SLandon J. Fuller {
270caeff9a3SLandon J. Fuller 	switch (port_type) {
271caeff9a3SLandon J. Fuller 	case BHND_PORT_DEVICE:
272caeff9a3SLandon J. Fuller 		/* 0, 1, or 2 ports */
273*7c7c726bSLandon J. Fuller 		return (min(core_id->num_admatch, 2));
274caeff9a3SLandon J. Fuller 
275caeff9a3SLandon J. Fuller 	case BHND_PORT_AGENT:
276caeff9a3SLandon J. Fuller 		/* One agent port maps all configuration blocks */
277caeff9a3SLandon J. Fuller 		if (core_id->num_cfg_blocks > 0)
278caeff9a3SLandon J. Fuller 			return (1);
279caeff9a3SLandon J. Fuller 
280caeff9a3SLandon J. Fuller 		/* Do not advertise an agent port if there are no configuration
281caeff9a3SLandon J. Fuller 		 * register blocks */
282caeff9a3SLandon J. Fuller 		return (0);
283caeff9a3SLandon J. Fuller 
284caeff9a3SLandon J. Fuller 	default:
285caeff9a3SLandon J. Fuller 		return (0);
286caeff9a3SLandon J. Fuller 	}
287caeff9a3SLandon J. Fuller }
288caeff9a3SLandon J. Fuller 
289caeff9a3SLandon J. Fuller /**
290caeff9a3SLandon J. Fuller  * Return true if @p port of @p port_type is defined by @p core_id, false
291caeff9a3SLandon J. Fuller  * otherwise.
292caeff9a3SLandon J. Fuller  *
293caeff9a3SLandon J. Fuller  * @param core_id The siba core info.
294caeff9a3SLandon J. Fuller  * @param port_type The bhnd(4) port type.
29506018a8eSLandon J. Fuller  * @param port The bhnd(4) port number.
29606018a8eSLandon J. Fuller  */
29706018a8eSLandon J. Fuller bool
siba_is_port_valid(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port)298caeff9a3SLandon J. Fuller siba_is_port_valid(struct siba_core_id *core_id, bhnd_port_type port_type,
299caeff9a3SLandon J. Fuller     u_int port)
30006018a8eSLandon J. Fuller {
30106018a8eSLandon J. Fuller 	/* Verify the index against the port count */
302caeff9a3SLandon J. Fuller 	if (siba_port_count(core_id, port_type) <= port)
30306018a8eSLandon J. Fuller 		return (false);
30406018a8eSLandon J. Fuller 
30506018a8eSLandon J. Fuller 	return (true);
30606018a8eSLandon J. Fuller }
30706018a8eSLandon J. Fuller 
30806018a8eSLandon J. Fuller /**
309caeff9a3SLandon J. Fuller  * Return the number of bhnd(4) regions to advertise for @p core_id on the
310caeff9a3SLandon J. Fuller  * @p port of @p port_type.
311caeff9a3SLandon J. Fuller  *
312caeff9a3SLandon J. Fuller  * @param core_id The siba core info.
313caeff9a3SLandon J. Fuller  * @param port_type The bhnd(4) port type.
314caeff9a3SLandon J. Fuller  */
315caeff9a3SLandon J. Fuller u_int
siba_port_region_count(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port)316caeff9a3SLandon J. Fuller siba_port_region_count(struct siba_core_id *core_id, bhnd_port_type port_type,
317caeff9a3SLandon J. Fuller     u_int port)
318caeff9a3SLandon J. Fuller {
319caeff9a3SLandon J. Fuller 	/* The port must exist */
320caeff9a3SLandon J. Fuller 	if (!siba_is_port_valid(core_id, port_type, port))
321caeff9a3SLandon J. Fuller 		return (0);
322caeff9a3SLandon J. Fuller 
323caeff9a3SLandon J. Fuller 	switch (port_type) {
324caeff9a3SLandon J. Fuller 	case BHND_PORT_DEVICE:
325caeff9a3SLandon J. Fuller 		/* The first address space, if any, is mapped to device0.0 */
326caeff9a3SLandon J. Fuller 		if (port == 0)
327*7c7c726bSLandon J. Fuller 			return (min(core_id->num_admatch, 1));
328caeff9a3SLandon J. Fuller 
329caeff9a3SLandon J. Fuller 		/* All remaining address spaces are mapped to device0.(n - 1) */
330*7c7c726bSLandon J. Fuller 		if (port == 1 && core_id->num_admatch >= 2)
331*7c7c726bSLandon J. Fuller 			return (core_id->num_admatch - 1);
332caeff9a3SLandon J. Fuller 
333caeff9a3SLandon J. Fuller 		break;
334caeff9a3SLandon J. Fuller 
335caeff9a3SLandon J. Fuller 	case BHND_PORT_AGENT:
336caeff9a3SLandon J. Fuller 		/* All config blocks are mapped to a single port */
337caeff9a3SLandon J. Fuller 		if (port == 0)
338caeff9a3SLandon J. Fuller 			return (core_id->num_cfg_blocks);
339caeff9a3SLandon J. Fuller 
340caeff9a3SLandon J. Fuller 		break;
341caeff9a3SLandon J. Fuller 
342caeff9a3SLandon J. Fuller 	default:
343caeff9a3SLandon J. Fuller 		break;
344caeff9a3SLandon J. Fuller 	}
345caeff9a3SLandon J. Fuller 
346caeff9a3SLandon J. Fuller 	/* Validated above */
347caeff9a3SLandon J. Fuller 	panic("siba_is_port_valid() returned true for unknown %s.%u port",
348caeff9a3SLandon J. Fuller 	    bhnd_port_type_name(port_type), port);
349caeff9a3SLandon J. Fuller 
350caeff9a3SLandon J. Fuller }
351caeff9a3SLandon J. Fuller 
352caeff9a3SLandon J. Fuller /**
353caeff9a3SLandon J. Fuller  * Map a bhnd(4) type/port/region triplet to its associated config block index,
354caeff9a3SLandon J. Fuller  * if any.
355caeff9a3SLandon J. Fuller  *
356caeff9a3SLandon J. Fuller  * We map config registers to port/region identifiers as follows:
357caeff9a3SLandon J. Fuller  *
358caeff9a3SLandon J. Fuller  * 	[port].[region]	[cfg register block]
359caeff9a3SLandon J. Fuller  * 	agent0.0	0
360caeff9a3SLandon J. Fuller  * 	agent0.1	1
361caeff9a3SLandon J. Fuller  *
362caeff9a3SLandon J. Fuller  * @param port_type The bhnd(4) port type.
363caeff9a3SLandon J. Fuller  * @param port The bhnd(4) port number.
364caeff9a3SLandon J. Fuller  * @param region The bhnd(4) port region.
365caeff9a3SLandon J. Fuller  * @param addridx On success, the corresponding addrspace index.
366caeff9a3SLandon J. Fuller  *
367caeff9a3SLandon J. Fuller  * @retval 0 success
368caeff9a3SLandon J. Fuller  * @retval ENOENT if the given type/port/region cannot be mapped to a
369caeff9a3SLandon J. Fuller  * siba config register block.
370caeff9a3SLandon J. Fuller  */
371caeff9a3SLandon J. Fuller int
siba_cfg_index(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port,u_int region,u_int * cfgidx)372caeff9a3SLandon J. Fuller siba_cfg_index(struct siba_core_id *core_id, bhnd_port_type port_type,
373caeff9a3SLandon J. Fuller     u_int port, u_int region, u_int *cfgidx)
374caeff9a3SLandon J. Fuller {
375caeff9a3SLandon J. Fuller 	/* Config blocks are mapped to agent ports */
376caeff9a3SLandon J. Fuller 	if (port_type != BHND_PORT_AGENT)
377caeff9a3SLandon J. Fuller 		return (ENOENT);
378caeff9a3SLandon J. Fuller 
379caeff9a3SLandon J. Fuller 	/* Port must be valid */
380caeff9a3SLandon J. Fuller 	if (!siba_is_port_valid(core_id, port_type, port))
381caeff9a3SLandon J. Fuller 		return (ENOENT);
382caeff9a3SLandon J. Fuller 
383caeff9a3SLandon J. Fuller 	if (region >= core_id->num_cfg_blocks)
384caeff9a3SLandon J. Fuller 		return (ENOENT);
385caeff9a3SLandon J. Fuller 
386caeff9a3SLandon J. Fuller 	if (region >= SIBA_MAX_CFG)
387caeff9a3SLandon J. Fuller 		return (ENOENT);
388caeff9a3SLandon J. Fuller 
389caeff9a3SLandon J. Fuller 	/* Found */
390caeff9a3SLandon J. Fuller 	*cfgidx = region;
391caeff9a3SLandon J. Fuller 	return (0);
392caeff9a3SLandon J. Fuller }
393caeff9a3SLandon J. Fuller 
394caeff9a3SLandon J. Fuller /**
395caeff9a3SLandon J. Fuller  * Map an bhnd(4) type/port/region triplet to its associated config block
396caeff9a3SLandon J. Fuller  * entry, if any.
397caeff9a3SLandon J. Fuller  *
398caeff9a3SLandon J. Fuller  * The only supported port type is BHND_PORT_DEVICE.
399caeff9a3SLandon J. Fuller  *
400caeff9a3SLandon J. Fuller  * @param dinfo The device info to search for a matching address space.
401caeff9a3SLandon J. Fuller  * @param type The bhnd(4) port type.
402caeff9a3SLandon J. Fuller  * @param port The bhnd(4) port number.
403caeff9a3SLandon J. Fuller  * @param region The bhnd(4) port region.
404caeff9a3SLandon J. Fuller  */
405caeff9a3SLandon J. Fuller struct siba_cfg_block *
siba_find_cfg_block(struct siba_devinfo * dinfo,bhnd_port_type type,u_int port,u_int region)406caeff9a3SLandon J. Fuller siba_find_cfg_block(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
407caeff9a3SLandon J. Fuller     u_int region)
408caeff9a3SLandon J. Fuller {
409caeff9a3SLandon J. Fuller 	u_int	cfgidx;
410caeff9a3SLandon J. Fuller 	int	error;
411caeff9a3SLandon J. Fuller 
412caeff9a3SLandon J. Fuller 	/* Map to addrspace index */
413caeff9a3SLandon J. Fuller 	error = siba_cfg_index(&dinfo->core_id, type, port, region, &cfgidx);
414caeff9a3SLandon J. Fuller 	if (error)
415caeff9a3SLandon J. Fuller 		return (NULL);
416caeff9a3SLandon J. Fuller 
417caeff9a3SLandon J. Fuller 	/* Found */
418caeff9a3SLandon J. Fuller 	return (&dinfo->cfg[cfgidx]);
419caeff9a3SLandon J. Fuller }
420caeff9a3SLandon J. Fuller 
421caeff9a3SLandon J. Fuller /**
422664a7497SLandon J. Fuller  * Map a bhnd(4) type/port/region triplet to its associated address space
423664a7497SLandon J. Fuller  * index, if any.
42406018a8eSLandon J. Fuller  *
42506018a8eSLandon J. Fuller  * For compatibility with bcma(4), we map address spaces to port/region
42606018a8eSLandon J. Fuller  * identifiers as follows:
42706018a8eSLandon J. Fuller  *
428*7c7c726bSLandon J. Fuller  * 	[port.region]	[admatch index]
42906018a8eSLandon J. Fuller  * 	device0.0	0
43006018a8eSLandon J. Fuller  * 	device1.0	1
43106018a8eSLandon J. Fuller  * 	device1.1	2
43206018a8eSLandon J. Fuller  * 	device1.2	3
43306018a8eSLandon J. Fuller  *
434caeff9a3SLandon J. Fuller  * @param core_id The siba core info.
435caeff9a3SLandon J. Fuller  * @param port_type The bhnd(4) port type.
436664a7497SLandon J. Fuller  * @param port The bhnd(4) port number.
437664a7497SLandon J. Fuller  * @param region The bhnd(4) port region.
438664a7497SLandon J. Fuller  * @param addridx On success, the corresponding addrspace index.
439664a7497SLandon J. Fuller  *
440664a7497SLandon J. Fuller  * @retval 0 success
441664a7497SLandon J. Fuller  * @retval ENOENT if the given type/port/region cannot be mapped to a
442664a7497SLandon J. Fuller  * siba address space.
443664a7497SLandon J. Fuller  */
444664a7497SLandon J. Fuller int
siba_addrspace_index(struct siba_core_id * core_id,bhnd_port_type port_type,u_int port,u_int region,u_int * addridx)445caeff9a3SLandon J. Fuller siba_addrspace_index(struct siba_core_id *core_id, bhnd_port_type port_type,
446caeff9a3SLandon J. Fuller     u_int port, u_int region, u_int *addridx)
447664a7497SLandon J. Fuller {
448664a7497SLandon J. Fuller 	u_int idx;
449664a7497SLandon J. Fuller 
450caeff9a3SLandon J. Fuller 	/* Address spaces are always device ports */
451caeff9a3SLandon J. Fuller 	if (port_type != BHND_PORT_DEVICE)
452caeff9a3SLandon J. Fuller 		return (ENOENT);
453caeff9a3SLandon J. Fuller 
454caeff9a3SLandon J. Fuller 	/* Port must be valid */
455caeff9a3SLandon J. Fuller 	if (!siba_is_port_valid(core_id, port_type, port))
456664a7497SLandon J. Fuller 		return (ENOENT);
457664a7497SLandon J. Fuller 
458664a7497SLandon J. Fuller 	if (port == 0)
459664a7497SLandon J. Fuller 		idx = region;
460664a7497SLandon J. Fuller 	else if (port == 1)
461664a7497SLandon J. Fuller 		idx = region + 1;
462664a7497SLandon J. Fuller 	else
463664a7497SLandon J. Fuller 		return (ENOENT);
464664a7497SLandon J. Fuller 
465*7c7c726bSLandon J. Fuller 	if (idx >= core_id->num_admatch)
466664a7497SLandon J. Fuller 		return (ENOENT);
467664a7497SLandon J. Fuller 
468664a7497SLandon J. Fuller 	/* Found */
469664a7497SLandon J. Fuller 	*addridx = idx;
470664a7497SLandon J. Fuller 	return (0);
471664a7497SLandon J. Fuller }
472664a7497SLandon J. Fuller 
473664a7497SLandon J. Fuller /**
474664a7497SLandon J. Fuller  * Map an bhnd(4) type/port/region triplet to its associated address space
475664a7497SLandon J. Fuller  * entry, if any.
476664a7497SLandon J. Fuller  *
477664a7497SLandon J. Fuller  * The only supported port type is BHND_PORT_DEVICE.
478664a7497SLandon J. Fuller  *
47906018a8eSLandon J. Fuller  * @param dinfo The device info to search for a matching address space.
48006018a8eSLandon J. Fuller  * @param type The bhnd(4) port type.
48106018a8eSLandon J. Fuller  * @param port The bhnd(4) port number.
48206018a8eSLandon J. Fuller  * @param region The bhnd(4) port region.
4834ad7e9b0SAdrian Chadd  */
4844ad7e9b0SAdrian Chadd struct siba_addrspace *
siba_find_addrspace(struct siba_devinfo * dinfo,bhnd_port_type type,u_int port,u_int region)48506018a8eSLandon J. Fuller siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port,
48606018a8eSLandon J. Fuller     u_int region)
4874ad7e9b0SAdrian Chadd {
48806018a8eSLandon J. Fuller 	u_int	addridx;
489664a7497SLandon J. Fuller 	int	error;
4904ad7e9b0SAdrian Chadd 
491664a7497SLandon J. Fuller 	/* Map to addrspace index */
492caeff9a3SLandon J. Fuller 	error = siba_addrspace_index(&dinfo->core_id, type, port, region,
493caeff9a3SLandon J. Fuller 	    &addridx);
494664a7497SLandon J. Fuller 	if (error)
49506018a8eSLandon J. Fuller 		return (NULL);
49606018a8eSLandon J. Fuller 
49706018a8eSLandon J. Fuller 	/* Found */
498664a7497SLandon J. Fuller 	if (addridx >= SIBA_MAX_ADDRSPACE)
499664a7497SLandon J. Fuller 		return (NULL);
500664a7497SLandon J. Fuller 
50106018a8eSLandon J. Fuller 	return (&dinfo->addrspace[addridx]);
5024ad7e9b0SAdrian Chadd }
5034ad7e9b0SAdrian Chadd 
5044ad7e9b0SAdrian Chadd /**
50506018a8eSLandon J. Fuller  * Append an address space entry to @p dinfo.
5064ad7e9b0SAdrian Chadd  *
5074ad7e9b0SAdrian Chadd  * @param dinfo The device info entry to update.
50806018a8eSLandon J. Fuller  * @param addridx The address space index.
5094ad7e9b0SAdrian Chadd  * @param base The mapping's base address.
5104ad7e9b0SAdrian Chadd  * @param size The mapping size.
5114ad7e9b0SAdrian Chadd  * @param bus_reserved Number of bytes to reserve in @p size for bus use
5124ad7e9b0SAdrian Chadd  * when registering the resource list entry. This is used to reserve bus
5134ad7e9b0SAdrian Chadd  * access to the core's SIBA_CFG* register blocks.
5144ad7e9b0SAdrian Chadd  *
5154ad7e9b0SAdrian Chadd  * @retval 0 success
5164ad7e9b0SAdrian Chadd  * @retval non-zero An error occurred appending the entry.
5174ad7e9b0SAdrian Chadd  */
518*7c7c726bSLandon J. Fuller static int
siba_append_dinfo_region(struct siba_devinfo * dinfo,uint8_t addridx,uint32_t base,uint32_t size,uint32_t bus_reserved)51906018a8eSLandon J. Fuller siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx,
52006018a8eSLandon J. Fuller     uint32_t base, uint32_t size, uint32_t bus_reserved)
5214ad7e9b0SAdrian Chadd {
5224ad7e9b0SAdrian Chadd 	struct siba_addrspace	*sa;
523f4a3eb02SAdrian Chadd 	rman_res_t		 r_size;
5244ad7e9b0SAdrian Chadd 
5254ad7e9b0SAdrian Chadd 	/* Verify that base + size will not overflow */
5267ba7852fSLandon J. Fuller 	if (size > 0 && UINT32_MAX - (size - 1) < base)
5274ad7e9b0SAdrian Chadd 		return (ERANGE);
5284ad7e9b0SAdrian Chadd 
529f4a3eb02SAdrian Chadd 	/* Verify that size - bus_reserved will not underflow */
530f4a3eb02SAdrian Chadd 	if (size < bus_reserved)
531f4a3eb02SAdrian Chadd 		return (ERANGE);
532f4a3eb02SAdrian Chadd 
5334ad7e9b0SAdrian Chadd 	/* Must not be 0-length */
5344ad7e9b0SAdrian Chadd 	if (size == 0)
5354ad7e9b0SAdrian Chadd 		return (EINVAL);
5364ad7e9b0SAdrian Chadd 
53706018a8eSLandon J. Fuller 	/* Must not exceed addrspace array size */
53806018a8eSLandon J. Fuller 	if (addridx >= nitems(dinfo->addrspace))
5394ad7e9b0SAdrian Chadd 		return (EINVAL);
5404ad7e9b0SAdrian Chadd 
54106018a8eSLandon J. Fuller 	/* Initialize new addrspace entry */
54206018a8eSLandon J. Fuller 	sa = &dinfo->addrspace[addridx];
5434ad7e9b0SAdrian Chadd 	sa->sa_base = base;
5444ad7e9b0SAdrian Chadd 	sa->sa_size = size;
545f4a3eb02SAdrian Chadd 	sa->sa_bus_reserved = bus_reserved;
5464ad7e9b0SAdrian Chadd 
5474ad7e9b0SAdrian Chadd 	/* Populate the resource list */
548f4a3eb02SAdrian Chadd 	r_size = size - bus_reserved;
5494ad7e9b0SAdrian Chadd 	sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
5507ba7852fSLandon J. Fuller 	    base, base + (r_size - 1), r_size);
5514ad7e9b0SAdrian Chadd 
5524ad7e9b0SAdrian Chadd 	return (0);
5534ad7e9b0SAdrian Chadd }
5544ad7e9b0SAdrian Chadd 
5554ad7e9b0SAdrian Chadd /**
5564ad7e9b0SAdrian Chadd  * Deallocate the given device info structure and any associated resources.
5574ad7e9b0SAdrian Chadd  *
5584ad7e9b0SAdrian Chadd  * @param dev The requesting bus device.
559caeff9a3SLandon J. Fuller  * @param child The siba child device.
560caeff9a3SLandon J. Fuller  * @param dinfo Device info associated with @p child to be deallocated.
5614ad7e9b0SAdrian Chadd  */
5624ad7e9b0SAdrian Chadd void
siba_free_dinfo(device_t dev,device_t child,struct siba_devinfo * dinfo)563caeff9a3SLandon J. Fuller siba_free_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo)
5644ad7e9b0SAdrian Chadd {
5654ad7e9b0SAdrian Chadd 	resource_list_free(&dinfo->resources);
5664ad7e9b0SAdrian Chadd 
5674ad7e9b0SAdrian Chadd 	/* Free all mapped configuration blocks */
5684ad7e9b0SAdrian Chadd 	for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
569caeff9a3SLandon J. Fuller 		if (dinfo->cfg_res[i] == NULL)
5704ad7e9b0SAdrian Chadd 			continue;
5714ad7e9b0SAdrian Chadd 
5724ad7e9b0SAdrian Chadd 		bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
573caeff9a3SLandon J. Fuller 		    dinfo->cfg_res[i]);
5744ad7e9b0SAdrian Chadd 
575caeff9a3SLandon J. Fuller 		dinfo->cfg_res[i] = NULL;
5764ad7e9b0SAdrian Chadd 		dinfo->cfg_rid[i] = -1;
5774ad7e9b0SAdrian Chadd 	}
5784ad7e9b0SAdrian Chadd 
579caeff9a3SLandon J. Fuller 	/* Unmap the core's interrupt */
580*7c7c726bSLandon J. Fuller 	if (dinfo->core_id.intr_en && dinfo->intr.mapped) {
581caeff9a3SLandon J. Fuller 		BHND_BUS_UNMAP_INTR(dev, child, dinfo->intr.irq);
582caeff9a3SLandon J. Fuller 		dinfo->intr.mapped = false;
583caeff9a3SLandon J. Fuller 	}
584caeff9a3SLandon J. Fuller 
5854ad7e9b0SAdrian Chadd 	free(dinfo, M_BHND);
5864ad7e9b0SAdrian Chadd }
5874ad7e9b0SAdrian Chadd 
5884ad7e9b0SAdrian Chadd /**
5894ad7e9b0SAdrian Chadd  * Return the core-enumeration-relative offset for the @p addrspace
5904ad7e9b0SAdrian Chadd  * SIBA_R0_ADMATCH* register.
5914ad7e9b0SAdrian Chadd  *
5924ad7e9b0SAdrian Chadd  * @param addrspace The address space index.
5934ad7e9b0SAdrian Chadd  *
5944ad7e9b0SAdrian Chadd  * @retval non-zero success
5954ad7e9b0SAdrian Chadd  * @retval 0 the given @p addrspace index is not supported.
5964ad7e9b0SAdrian Chadd  */
5974ad7e9b0SAdrian Chadd u_int
siba_admatch_offset(uint8_t addrspace)5984ad7e9b0SAdrian Chadd siba_admatch_offset(uint8_t addrspace)
5994ad7e9b0SAdrian Chadd {
6004ad7e9b0SAdrian Chadd 	switch (addrspace) {
6014ad7e9b0SAdrian Chadd 	case 0:
6024ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
6034ad7e9b0SAdrian Chadd 	case 1:
6044ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
6054ad7e9b0SAdrian Chadd 	case 2:
6064ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
6074ad7e9b0SAdrian Chadd 	case 3:
6084ad7e9b0SAdrian Chadd 		return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
6094ad7e9b0SAdrian Chadd 	default:
6104ad7e9b0SAdrian Chadd 		return (0);
6114ad7e9b0SAdrian Chadd 	}
6124ad7e9b0SAdrian Chadd }
6134ad7e9b0SAdrian Chadd 
6144ad7e9b0SAdrian Chadd /**
6154ad7e9b0SAdrian Chadd  * Parse a SIBA_R0_ADMATCH* register.
6164ad7e9b0SAdrian Chadd  *
6174ad7e9b0SAdrian Chadd  * @param addrspace The address space index.
6184ad7e9b0SAdrian Chadd  * @param am The address match register value to be parsed.
619*7c7c726bSLandon J. Fuller  * @param[out] admatch The parsed address match descriptor
6204ad7e9b0SAdrian Chadd  *
6214ad7e9b0SAdrian Chadd  * @retval 0 success
622453130d9SPedro F. Giffuni  * @retval non-zero a parse error occurred.
6234ad7e9b0SAdrian Chadd  */
6244ad7e9b0SAdrian Chadd int
siba_parse_admatch(uint32_t am,struct siba_admatch * admatch)625*7c7c726bSLandon J. Fuller siba_parse_admatch(uint32_t am, struct siba_admatch *admatch)
6264ad7e9b0SAdrian Chadd {
6274ad7e9b0SAdrian Chadd 	u_int am_type;
6284ad7e9b0SAdrian Chadd 
6294ad7e9b0SAdrian Chadd 	/* Extract the base address and size */
6304ad7e9b0SAdrian Chadd 	am_type = SIBA_REG_GET(am, AM_TYPE);
6314ad7e9b0SAdrian Chadd 	switch (am_type) {
6324ad7e9b0SAdrian Chadd 	case 0:
633*7c7c726bSLandon J. Fuller 		/* Type 0 entries are always enabled, and do not support
634*7c7c726bSLandon J. Fuller 		 * negative matching */
635*7c7c726bSLandon J. Fuller 		admatch->am_base = am & SIBA_AM_BASE0_MASK;
636*7c7c726bSLandon J. Fuller 		admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
637*7c7c726bSLandon J. Fuller 		admatch->am_enabled = true;
638*7c7c726bSLandon J. Fuller 		admatch->am_negative = false;
6394ad7e9b0SAdrian Chadd 		break;
6404ad7e9b0SAdrian Chadd 	case 1:
641*7c7c726bSLandon J. Fuller 		admatch->am_base = am & SIBA_AM_BASE1_MASK;
642*7c7c726bSLandon J. Fuller 		admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
643*7c7c726bSLandon J. Fuller 		admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
644*7c7c726bSLandon J. Fuller 		admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
6454ad7e9b0SAdrian Chadd 		break;
6464ad7e9b0SAdrian Chadd 	case 2:
647*7c7c726bSLandon J. Fuller 		admatch->am_base = am & SIBA_AM_BASE2_MASK;
648*7c7c726bSLandon J. Fuller 		admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
649*7c7c726bSLandon J. Fuller 		admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0);
650*7c7c726bSLandon J. Fuller 		admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0);
6514ad7e9b0SAdrian Chadd 		break;
6524ad7e9b0SAdrian Chadd 	default:
6534ad7e9b0SAdrian Chadd 		return (EINVAL);
6544ad7e9b0SAdrian Chadd 	}
6554ad7e9b0SAdrian Chadd 
6564ad7e9b0SAdrian Chadd 	return (0);
6574ad7e9b0SAdrian Chadd }
6588a03f98aSLandon J. Fuller 
6598a03f98aSLandon J. Fuller /**
660ac59515bSLandon J. Fuller  * Write @p value to @p dev's CFG0 target/initiator state register, performing
661ac59515bSLandon J. Fuller  * required read-back and waiting for completion.
6628a03f98aSLandon J. Fuller  *
6638a03f98aSLandon J. Fuller  * @param dev The siba(4) child device.
664ac59515bSLandon J. Fuller  * @param reg The CFG0 state register to write (e.g. SIBA_CFG0_TMSTATELOW,
6658a03f98aSLandon J. Fuller  * SIBA_CFG0_IMSTATE)
6668a03f98aSLandon J. Fuller  * @param value The value to write to @p reg.
6678a03f98aSLandon J. Fuller  * @param mask The mask of bits to be included from @p value.
6688a03f98aSLandon J. Fuller  */
669ac59515bSLandon J. Fuller void
siba_write_target_state(device_t dev,struct siba_devinfo * dinfo,bus_size_t reg,uint32_t value,uint32_t mask)6708a03f98aSLandon J. Fuller siba_write_target_state(device_t dev, struct siba_devinfo *dinfo,
6718a03f98aSLandon J. Fuller     bus_size_t reg, uint32_t value, uint32_t mask)
6728a03f98aSLandon J. Fuller {
6738a03f98aSLandon J. Fuller 	struct bhnd_resource	*r;
6748a03f98aSLandon J. Fuller 	uint32_t		 rval;
6758a03f98aSLandon J. Fuller 
676ac59515bSLandon J. Fuller 	r = dinfo->cfg_res[0];
6778a03f98aSLandon J. Fuller 
678ac59515bSLandon J. Fuller 	KASSERT(r != NULL, ("%s missing CFG0 mapping",
679ac59515bSLandon J. Fuller 	    device_get_nameunit(dev)));
680ac59515bSLandon J. Fuller 	KASSERT(reg <= SIBA_CFG_SIZE-4, ("%s invalid CFG0 register offset %#jx",
681ac59515bSLandon J. Fuller 	    device_get_nameunit(dev), (uintmax_t)reg));
6828a03f98aSLandon J. Fuller 
6838a03f98aSLandon J. Fuller 	rval = bhnd_bus_read_4(r, reg);
6848a03f98aSLandon J. Fuller 	rval &= ~mask;
6858a03f98aSLandon J. Fuller 	rval |= (value & mask);
6868a03f98aSLandon J. Fuller 
6878a03f98aSLandon J. Fuller 	bhnd_bus_write_4(r, reg, rval);
6888a03f98aSLandon J. Fuller 	bhnd_bus_read_4(r, reg); /* read-back */
6898a03f98aSLandon J. Fuller 	DELAY(1);
6908a03f98aSLandon J. Fuller }
6918a03f98aSLandon J. Fuller 
6928a03f98aSLandon J. Fuller /**
693ac59515bSLandon J. Fuller  * Spin for up to @p usec waiting for @p dev's CFG0 target/initiator state
694ac59515bSLandon J. Fuller  * register value to be equal to @p value after applying @p mask bits to both
695ac59515bSLandon J. Fuller  * values.
6968a03f98aSLandon J. Fuller  *
6978a03f98aSLandon J. Fuller  * @param dev The siba(4) child device to wait on.
6988a03f98aSLandon J. Fuller  * @param dinfo The @p dev's device info
699ac59515bSLandon J. Fuller  * @param reg The state register to read (e.g. SIBA_CFG0_TMSTATEHIGH,
700ac59515bSLandon J. Fuller  * SIBA_CFG0_IMSTATE)
701ac59515bSLandon J. Fuller  * @param value The value against which @p reg will be compared.
702ac59515bSLandon J. Fuller  * @param mask The mask to be applied when comparing @p value with @p reg.
703ac59515bSLandon J. Fuller  * @param usec The maximum number of microseconds to wait for completion.
7048a03f98aSLandon J. Fuller  *
7058a03f98aSLandon J. Fuller  * @retval 0 if SIBA_TMH_BUSY is cleared prior to the @p usec timeout.
7068a03f98aSLandon J. Fuller  * @retval ENODEV if SIBA_CFG0 is not mapped by @p dinfo.
707ac59515bSLandon J. Fuller  * @retval ETIMEDOUT if a timeout occurs.
7088a03f98aSLandon J. Fuller  */
7098a03f98aSLandon J. Fuller int
siba_wait_target_state(device_t dev,struct siba_devinfo * dinfo,bus_size_t reg,uint32_t value,uint32_t mask,u_int usec)710ac59515bSLandon J. Fuller siba_wait_target_state(device_t dev, struct siba_devinfo *dinfo, bus_size_t reg,
711ac59515bSLandon J. Fuller     uint32_t value, uint32_t mask, u_int usec)
7128a03f98aSLandon J. Fuller {
7138a03f98aSLandon J. Fuller 	struct bhnd_resource	*r;
714ac59515bSLandon J. Fuller 	uint32_t		 rval;
7158a03f98aSLandon J. Fuller 
716caeff9a3SLandon J. Fuller 	if ((r = dinfo->cfg_res[0]) == NULL)
7178a03f98aSLandon J. Fuller 		return (ENODEV);
7188a03f98aSLandon J. Fuller 
719ac59515bSLandon J. Fuller 	value &= mask;
7208a03f98aSLandon J. Fuller 	for (int i = 0; i < usec; i += 10) {
721ac59515bSLandon J. Fuller 		rval = bhnd_bus_read_4(r, reg);
722ac59515bSLandon J. Fuller 		if ((rval & mask) == value)
7238a03f98aSLandon J. Fuller 			return (0);
7248a03f98aSLandon J. Fuller 
7258a03f98aSLandon J. Fuller 		DELAY(10);
7268a03f98aSLandon J. Fuller 	}
7278a03f98aSLandon J. Fuller 
7288a03f98aSLandon J. Fuller 	return (ETIMEDOUT);
7298a03f98aSLandon J. Fuller }
730