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