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/cdefs.h> 354ad7e9b0SAdrian Chadd __FBSDID("$FreeBSD$"); 364ad7e9b0SAdrian Chadd 374ad7e9b0SAdrian Chadd #include <sys/param.h> 384ad7e9b0SAdrian Chadd #include <sys/bus.h> 394ad7e9b0SAdrian Chadd #include <sys/kernel.h> 404ad7e9b0SAdrian Chadd #include <sys/limits.h> 414ad7e9b0SAdrian Chadd #include <sys/systm.h> 424ad7e9b0SAdrian Chadd 434ad7e9b0SAdrian Chadd #include <machine/bus.h> 444ad7e9b0SAdrian Chadd #include <machine/resource.h> 454ad7e9b0SAdrian Chadd 464ad7e9b0SAdrian Chadd #include <dev/bhnd/bhndvar.h> 474ad7e9b0SAdrian Chadd 484ad7e9b0SAdrian Chadd #include "sibareg.h" 494ad7e9b0SAdrian Chadd #include "sibavar.h" 504ad7e9b0SAdrian Chadd 51*7c7c726bSLandon J. Fuller static int siba_register_interrupts(device_t dev, device_t child, 52*7c7c726bSLandon J. Fuller struct siba_devinfo *dinfo); 53*7c7c726bSLandon J. Fuller static int siba_append_dinfo_region(struct siba_devinfo *dinfo, 54*7c7c726bSLandon J. Fuller uint8_t addridx, uint32_t base, uint32_t size, 55*7c7c726bSLandon J. Fuller uint32_t bus_reserved); 56*7c7c726bSLandon J. Fuller 574ad7e9b0SAdrian Chadd /** 584ad7e9b0SAdrian Chadd * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor 594ad7e9b0SAdrian Chadd * code. 604ad7e9b0SAdrian Chadd * 614ad7e9b0SAdrian Chadd * @param ocp_vendor An OCP vendor code. 624ad7e9b0SAdrian Chadd * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or 634ad7e9b0SAdrian Chadd * BHND_MFGID_INVALID if the OCP vendor is unknown. 644ad7e9b0SAdrian Chadd */ 654ad7e9b0SAdrian Chadd uint16_t 664ad7e9b0SAdrian Chadd siba_get_bhnd_mfgid(uint16_t ocp_vendor) 674ad7e9b0SAdrian Chadd { 684ad7e9b0SAdrian Chadd switch (ocp_vendor) { 694ad7e9b0SAdrian Chadd case OCP_VENDOR_BCM: 704ad7e9b0SAdrian Chadd return (BHND_MFGID_BCM); 714ad7e9b0SAdrian Chadd default: 724ad7e9b0SAdrian Chadd return (BHND_MFGID_INVALID); 734ad7e9b0SAdrian Chadd } 744ad7e9b0SAdrian Chadd } 754ad7e9b0SAdrian Chadd 764ad7e9b0SAdrian Chadd /** 77688fc8c0SLandon J. Fuller * Allocate and return a new empty device info structure. 784ad7e9b0SAdrian Chadd * 79688fc8c0SLandon J. Fuller * @param bus The requesting bus device. 80688fc8c0SLandon J. Fuller * 81688fc8c0SLandon J. Fuller * @retval NULL if allocation failed. 824ad7e9b0SAdrian Chadd */ 834ad7e9b0SAdrian Chadd struct siba_devinfo * 84688fc8c0SLandon J. Fuller siba_alloc_dinfo(device_t bus) 854ad7e9b0SAdrian Chadd { 864ad7e9b0SAdrian Chadd struct siba_devinfo *dinfo; 874ad7e9b0SAdrian Chadd 88688fc8c0SLandon J. Fuller dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT|M_ZERO); 894ad7e9b0SAdrian Chadd if (dinfo == NULL) 904ad7e9b0SAdrian Chadd return NULL; 914ad7e9b0SAdrian Chadd 924ad7e9b0SAdrian Chadd for (u_int i = 0; i < nitems(dinfo->cfg); i++) { 93caeff9a3SLandon J. Fuller dinfo->cfg[i] = ((struct siba_cfg_block){ 94caeff9a3SLandon J. Fuller .cb_base = 0, 95caeff9a3SLandon J. Fuller .cb_size = 0, 96caeff9a3SLandon J. Fuller .cb_rid = -1, 97caeff9a3SLandon J. Fuller }); 98caeff9a3SLandon J. Fuller dinfo->cfg_res[i] = NULL; 994ad7e9b0SAdrian Chadd dinfo->cfg_rid[i] = -1; 1004ad7e9b0SAdrian Chadd } 1014ad7e9b0SAdrian Chadd 1024ad7e9b0SAdrian Chadd resource_list_init(&dinfo->resources); 1034ad7e9b0SAdrian Chadd 1044e96bf3aSLandon J. Fuller dinfo->pmu_state = SIBA_PMU_NONE; 105*7c7c726bSLandon J. Fuller 106*7c7c726bSLandon J. Fuller dinfo->intr = (struct siba_intr) { 107*7c7c726bSLandon J. Fuller .mapped = false, 108*7c7c726bSLandon J. Fuller .rid = -1 109*7c7c726bSLandon J. Fuller }; 110caeff9a3SLandon J. Fuller 1114ad7e9b0SAdrian Chadd return dinfo; 1124ad7e9b0SAdrian Chadd } 1134ad7e9b0SAdrian Chadd 1144ad7e9b0SAdrian Chadd /** 115688fc8c0SLandon J. Fuller * Initialize a device info structure previously allocated via 116688fc8c0SLandon J. Fuller * siba_alloc_dinfo, copying the provided core id. 117688fc8c0SLandon J. Fuller * 118688fc8c0SLandon J. Fuller * @param dev The requesting bus device. 119*7c7c726bSLandon J. Fuller * @param child The siba child device. 120688fc8c0SLandon J. Fuller * @param dinfo The device info instance. 121688fc8c0SLandon J. Fuller * @param core Device core info. 122688fc8c0SLandon J. Fuller * 123688fc8c0SLandon J. Fuller * @retval 0 success 124688fc8c0SLandon J. Fuller * @retval non-zero initialization failed. 125688fc8c0SLandon J. Fuller */ 126688fc8c0SLandon J. Fuller int 127*7c7c726bSLandon J. Fuller siba_init_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo, 128688fc8c0SLandon J. Fuller const struct siba_core_id *core_id) 129688fc8c0SLandon J. Fuller { 130*7c7c726bSLandon J. Fuller int error; 131*7c7c726bSLandon J. Fuller 132688fc8c0SLandon J. Fuller dinfo->core_id = *core_id; 133*7c7c726bSLandon J. Fuller 134*7c7c726bSLandon J. Fuller /* Register all address space mappings */ 135*7c7c726bSLandon J. Fuller for (uint8_t i = 0; i < core_id->num_admatch; i++) { 136*7c7c726bSLandon J. Fuller uint32_t bus_reserved; 137*7c7c726bSLandon J. Fuller 138*7c7c726bSLandon J. Fuller /* If this is the device's core/enumeration addrespace, 139*7c7c726bSLandon J. Fuller * reserve the Sonics configuration register blocks for the 140*7c7c726bSLandon J. Fuller * use of our bus. */ 141*7c7c726bSLandon J. Fuller bus_reserved = 0; 142*7c7c726bSLandon J. Fuller if (i == SIBA_CORE_ADDRSPACE) 143*7c7c726bSLandon J. Fuller bus_reserved = core_id->num_cfg_blocks * SIBA_CFG_SIZE; 144*7c7c726bSLandon J. Fuller 145*7c7c726bSLandon J. Fuller /* Append the region info */ 146*7c7c726bSLandon J. Fuller error = siba_append_dinfo_region(dinfo, i, 147*7c7c726bSLandon J. Fuller core_id->admatch[i].am_base, core_id->admatch[i].am_size, 148*7c7c726bSLandon J. Fuller bus_reserved); 149*7c7c726bSLandon J. Fuller if (error) 150*7c7c726bSLandon J. Fuller return (error); 151*7c7c726bSLandon J. Fuller } 152*7c7c726bSLandon J. Fuller 153*7c7c726bSLandon J. Fuller /* Register all interrupt(s) */ 154*7c7c726bSLandon J. Fuller if ((error = siba_register_interrupts(dev, child, dinfo))) 155*7c7c726bSLandon J. Fuller return (error); 156*7c7c726bSLandon J. Fuller 157*7c7c726bSLandon J. Fuller return (0); 158*7c7c726bSLandon J. Fuller } 159*7c7c726bSLandon J. Fuller 160*7c7c726bSLandon J. Fuller 161*7c7c726bSLandon J. Fuller /** 162*7c7c726bSLandon J. Fuller * Register and map all interrupts for @p dinfo. 163*7c7c726bSLandon J. Fuller * 164*7c7c726bSLandon J. Fuller * @param dev The siba bus device. 165*7c7c726bSLandon J. Fuller * @param child The siba child device. 166*7c7c726bSLandon J. Fuller * @param dinfo The device info instance on which to register all interrupt 167*7c7c726bSLandon J. Fuller * entries. 168*7c7c726bSLandon J. Fuller */ 169*7c7c726bSLandon J. Fuller static int 170*7c7c726bSLandon J. Fuller siba_register_interrupts(device_t dev, device_t child, 171*7c7c726bSLandon J. Fuller struct siba_devinfo *dinfo) 172*7c7c726bSLandon J. Fuller { 173*7c7c726bSLandon J. Fuller int error; 174*7c7c726bSLandon J. Fuller 175*7c7c726bSLandon J. Fuller /* Is backplane interrupt distribution enabled for this core? */ 176*7c7c726bSLandon J. Fuller if (!dinfo->core_id.intr_en) 177*7c7c726bSLandon J. Fuller return (0); 178*7c7c726bSLandon J. Fuller 179*7c7c726bSLandon J. Fuller /* Have one interrupt */ 180*7c7c726bSLandon J. Fuller dinfo->intr.mapped = false; 181*7c7c726bSLandon J. Fuller dinfo->intr.irq = 0; 182*7c7c726bSLandon J. Fuller dinfo->intr.rid = -1; 183*7c7c726bSLandon J. Fuller 184*7c7c726bSLandon J. Fuller /* Map the interrupt */ 185*7c7c726bSLandon J. Fuller error = BHND_BUS_MAP_INTR(dev, child, 0 /* single intr is always 0 */, 186*7c7c726bSLandon J. Fuller &dinfo->intr.irq); 187*7c7c726bSLandon J. Fuller if (error) { 188*7c7c726bSLandon J. Fuller device_printf(dev, "failed mapping interrupt line for core %u: " 189*7c7c726bSLandon J. Fuller "%d\n", dinfo->core_id.core_info.core_idx, error); 190*7c7c726bSLandon J. Fuller return (error); 191*7c7c726bSLandon J. Fuller } 192*7c7c726bSLandon J. Fuller dinfo->intr.mapped = true; 193*7c7c726bSLandon J. Fuller 194*7c7c726bSLandon J. Fuller /* Update the resource list */ 195*7c7c726bSLandon J. Fuller dinfo->intr.rid = resource_list_add_next(&dinfo->resources, SYS_RES_IRQ, 196*7c7c726bSLandon J. Fuller dinfo->intr.irq, dinfo->intr.irq, 1); 197*7c7c726bSLandon J. Fuller 198688fc8c0SLandon J. Fuller return (0); 199688fc8c0SLandon J. Fuller } 200688fc8c0SLandon J. Fuller 201688fc8c0SLandon J. Fuller /** 202caeff9a3SLandon J. Fuller * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port 203caeff9a3SLandon J. Fuller * number. 2044ad7e9b0SAdrian Chadd * 20506018a8eSLandon J. Fuller * @param addrspace Address space index. 2064ad7e9b0SAdrian Chadd */ 20706018a8eSLandon J. Fuller u_int 208caeff9a3SLandon J. Fuller siba_addrspace_device_port(u_int addrspace) 2094ad7e9b0SAdrian Chadd { 21006018a8eSLandon J. Fuller /* The first addrspace is always mapped to device0; the remainder 21106018a8eSLandon J. Fuller * are mapped to device1 */ 21206018a8eSLandon J. Fuller if (addrspace == 0) 21306018a8eSLandon J. Fuller return (0); 21406018a8eSLandon J. Fuller else 21506018a8eSLandon J. Fuller return (1); 2164ad7e9b0SAdrian Chadd } 2174ad7e9b0SAdrian Chadd 2184ad7e9b0SAdrian Chadd /** 219caeff9a3SLandon J. Fuller * Map an addrspace index to its corresponding bhnd(4) BHND_PORT_DEVICE port 220caeff9a3SLandon J. Fuller * region number. 2214ad7e9b0SAdrian Chadd * 22206018a8eSLandon J. Fuller * @param addrspace Address space index. 22306018a8eSLandon J. Fuller */ 22406018a8eSLandon J. Fuller u_int 225caeff9a3SLandon J. Fuller siba_addrspace_device_region(u_int addrspace) 22606018a8eSLandon J. Fuller { 22706018a8eSLandon J. Fuller /* The first addrspace is always mapped to device0.0; the remainder 22806018a8eSLandon J. Fuller * are mapped to device1.0 + (n - 1) */ 22906018a8eSLandon J. Fuller if (addrspace == 0) 23006018a8eSLandon J. Fuller return (0); 23106018a8eSLandon J. Fuller else 23206018a8eSLandon J. Fuller return (addrspace - 1); 23306018a8eSLandon J. Fuller } 23406018a8eSLandon J. Fuller 23506018a8eSLandon J. Fuller /** 236caeff9a3SLandon J. Fuller * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port 237caeff9a3SLandon J. Fuller * number. 23806018a8eSLandon J. Fuller * 239caeff9a3SLandon J. Fuller * @param cfg Config block index. 24006018a8eSLandon J. Fuller */ 24106018a8eSLandon J. Fuller u_int 242caeff9a3SLandon J. Fuller siba_cfg_agent_port(u_int cfg) 24306018a8eSLandon J. Fuller { 244caeff9a3SLandon J. Fuller /* Always agent0 */ 24506018a8eSLandon J. Fuller return (0); 24606018a8eSLandon J. Fuller } 24706018a8eSLandon J. Fuller 24806018a8eSLandon J. Fuller /** 249caeff9a3SLandon J. Fuller * Map an config block index to its corresponding bhnd(4) BHND_PORT_AGENT port 250caeff9a3SLandon J. Fuller * region number. 25106018a8eSLandon J. Fuller * 252caeff9a3SLandon J. Fuller * @param cfg Config block index. 253caeff9a3SLandon J. Fuller */ 254caeff9a3SLandon J. Fuller u_int 255caeff9a3SLandon J. Fuller siba_cfg_agent_region(u_int cfg) 256caeff9a3SLandon J. Fuller { 257caeff9a3SLandon J. Fuller /* Always agent0.<idx> */ 258caeff9a3SLandon J. Fuller return (cfg); 259caeff9a3SLandon J. Fuller } 260caeff9a3SLandon J. Fuller 261caeff9a3SLandon J. Fuller /** 262caeff9a3SLandon J. Fuller * Return the number of bhnd(4) ports to advertise for the given 263caeff9a3SLandon J. Fuller * @p core_id and @p port_type. 26406018a8eSLandon J. Fuller * 265caeff9a3SLandon J. Fuller * Refer to the siba_addrspace_index() and siba_cfg_index() functions for 266caeff9a3SLandon J. Fuller * information on siba's mapping of bhnd(4) port and region identifiers. 267caeff9a3SLandon J. Fuller * 268caeff9a3SLandon J. Fuller * @param core_id The siba core info. 269caeff9a3SLandon J. Fuller * @param port_type The bhnd(4) port type. 270caeff9a3SLandon J. Fuller */ 271caeff9a3SLandon J. Fuller u_int 272caeff9a3SLandon J. Fuller siba_port_count(struct siba_core_id *core_id, bhnd_port_type port_type) 273caeff9a3SLandon J. Fuller { 274caeff9a3SLandon J. Fuller switch (port_type) { 275caeff9a3SLandon J. Fuller case BHND_PORT_DEVICE: 276caeff9a3SLandon J. Fuller /* 0, 1, or 2 ports */ 277*7c7c726bSLandon J. Fuller return (min(core_id->num_admatch, 2)); 278caeff9a3SLandon J. Fuller 279caeff9a3SLandon J. Fuller case BHND_PORT_AGENT: 280caeff9a3SLandon J. Fuller /* One agent port maps all configuration blocks */ 281caeff9a3SLandon J. Fuller if (core_id->num_cfg_blocks > 0) 282caeff9a3SLandon J. Fuller return (1); 283caeff9a3SLandon J. Fuller 284caeff9a3SLandon J. Fuller /* Do not advertise an agent port if there are no configuration 285caeff9a3SLandon J. Fuller * register blocks */ 286caeff9a3SLandon J. Fuller return (0); 287caeff9a3SLandon J. Fuller 288caeff9a3SLandon J. Fuller default: 289caeff9a3SLandon J. Fuller return (0); 290caeff9a3SLandon J. Fuller } 291caeff9a3SLandon J. Fuller } 292caeff9a3SLandon J. Fuller 293caeff9a3SLandon J. Fuller /** 294caeff9a3SLandon J. Fuller * Return true if @p port of @p port_type is defined by @p core_id, false 295caeff9a3SLandon J. Fuller * otherwise. 296caeff9a3SLandon J. Fuller * 297caeff9a3SLandon J. Fuller * @param core_id The siba core info. 298caeff9a3SLandon J. Fuller * @param port_type The bhnd(4) port type. 29906018a8eSLandon J. Fuller * @param port The bhnd(4) port number. 30006018a8eSLandon J. Fuller */ 30106018a8eSLandon J. Fuller bool 302caeff9a3SLandon J. Fuller siba_is_port_valid(struct siba_core_id *core_id, bhnd_port_type port_type, 303caeff9a3SLandon J. Fuller u_int port) 30406018a8eSLandon J. Fuller { 30506018a8eSLandon J. Fuller /* Verify the index against the port count */ 306caeff9a3SLandon J. Fuller if (siba_port_count(core_id, port_type) <= port) 30706018a8eSLandon J. Fuller return (false); 30806018a8eSLandon J. Fuller 30906018a8eSLandon J. Fuller return (true); 31006018a8eSLandon J. Fuller } 31106018a8eSLandon J. Fuller 31206018a8eSLandon J. Fuller /** 313caeff9a3SLandon J. Fuller * Return the number of bhnd(4) regions to advertise for @p core_id on the 314caeff9a3SLandon J. Fuller * @p port of @p port_type. 315caeff9a3SLandon J. Fuller * 316caeff9a3SLandon J. Fuller * @param core_id The siba core info. 317caeff9a3SLandon J. Fuller * @param port_type The bhnd(4) port type. 318caeff9a3SLandon J. Fuller */ 319caeff9a3SLandon J. Fuller u_int 320caeff9a3SLandon J. Fuller siba_port_region_count(struct siba_core_id *core_id, bhnd_port_type port_type, 321caeff9a3SLandon J. Fuller u_int port) 322caeff9a3SLandon J. Fuller { 323caeff9a3SLandon J. Fuller /* The port must exist */ 324caeff9a3SLandon J. Fuller if (!siba_is_port_valid(core_id, port_type, port)) 325caeff9a3SLandon J. Fuller return (0); 326caeff9a3SLandon J. Fuller 327caeff9a3SLandon J. Fuller switch (port_type) { 328caeff9a3SLandon J. Fuller case BHND_PORT_DEVICE: 329caeff9a3SLandon J. Fuller /* The first address space, if any, is mapped to device0.0 */ 330caeff9a3SLandon J. Fuller if (port == 0) 331*7c7c726bSLandon J. Fuller return (min(core_id->num_admatch, 1)); 332caeff9a3SLandon J. Fuller 333caeff9a3SLandon J. Fuller /* All remaining address spaces are mapped to device0.(n - 1) */ 334*7c7c726bSLandon J. Fuller if (port == 1 && core_id->num_admatch >= 2) 335*7c7c726bSLandon J. Fuller return (core_id->num_admatch - 1); 336caeff9a3SLandon J. Fuller 337caeff9a3SLandon J. Fuller break; 338caeff9a3SLandon J. Fuller 339caeff9a3SLandon J. Fuller case BHND_PORT_AGENT: 340caeff9a3SLandon J. Fuller /* All config blocks are mapped to a single port */ 341caeff9a3SLandon J. Fuller if (port == 0) 342caeff9a3SLandon J. Fuller return (core_id->num_cfg_blocks); 343caeff9a3SLandon J. Fuller 344caeff9a3SLandon J. Fuller break; 345caeff9a3SLandon J. Fuller 346caeff9a3SLandon J. Fuller default: 347caeff9a3SLandon J. Fuller break; 348caeff9a3SLandon J. Fuller } 349caeff9a3SLandon J. Fuller 350caeff9a3SLandon J. Fuller /* Validated above */ 351caeff9a3SLandon J. Fuller panic("siba_is_port_valid() returned true for unknown %s.%u port", 352caeff9a3SLandon J. Fuller bhnd_port_type_name(port_type), port); 353caeff9a3SLandon J. Fuller 354caeff9a3SLandon J. Fuller } 355caeff9a3SLandon J. Fuller 356caeff9a3SLandon J. Fuller /** 357caeff9a3SLandon J. Fuller * Map a bhnd(4) type/port/region triplet to its associated config block index, 358caeff9a3SLandon J. Fuller * if any. 359caeff9a3SLandon J. Fuller * 360caeff9a3SLandon J. Fuller * We map config registers to port/region identifiers as follows: 361caeff9a3SLandon J. Fuller * 362caeff9a3SLandon J. Fuller * [port].[region] [cfg register block] 363caeff9a3SLandon J. Fuller * agent0.0 0 364caeff9a3SLandon J. Fuller * agent0.1 1 365caeff9a3SLandon J. Fuller * 366caeff9a3SLandon J. Fuller * @param port_type The bhnd(4) port type. 367caeff9a3SLandon J. Fuller * @param port The bhnd(4) port number. 368caeff9a3SLandon J. Fuller * @param region The bhnd(4) port region. 369caeff9a3SLandon J. Fuller * @param addridx On success, the corresponding addrspace index. 370caeff9a3SLandon J. Fuller * 371caeff9a3SLandon J. Fuller * @retval 0 success 372caeff9a3SLandon J. Fuller * @retval ENOENT if the given type/port/region cannot be mapped to a 373caeff9a3SLandon J. Fuller * siba config register block. 374caeff9a3SLandon J. Fuller */ 375caeff9a3SLandon J. Fuller int 376caeff9a3SLandon J. Fuller siba_cfg_index(struct siba_core_id *core_id, bhnd_port_type port_type, 377caeff9a3SLandon J. Fuller u_int port, u_int region, u_int *cfgidx) 378caeff9a3SLandon J. Fuller { 379caeff9a3SLandon J. Fuller /* Config blocks are mapped to agent ports */ 380caeff9a3SLandon J. Fuller if (port_type != BHND_PORT_AGENT) 381caeff9a3SLandon J. Fuller return (ENOENT); 382caeff9a3SLandon J. Fuller 383caeff9a3SLandon J. Fuller /* Port must be valid */ 384caeff9a3SLandon J. Fuller if (!siba_is_port_valid(core_id, port_type, port)) 385caeff9a3SLandon J. Fuller return (ENOENT); 386caeff9a3SLandon J. Fuller 387caeff9a3SLandon J. Fuller if (region >= core_id->num_cfg_blocks) 388caeff9a3SLandon J. Fuller return (ENOENT); 389caeff9a3SLandon J. Fuller 390caeff9a3SLandon J. Fuller if (region >= SIBA_MAX_CFG) 391caeff9a3SLandon J. Fuller return (ENOENT); 392caeff9a3SLandon J. Fuller 393caeff9a3SLandon J. Fuller /* Found */ 394caeff9a3SLandon J. Fuller *cfgidx = region; 395caeff9a3SLandon J. Fuller return (0); 396caeff9a3SLandon J. Fuller } 397caeff9a3SLandon J. Fuller 398caeff9a3SLandon J. Fuller /** 399caeff9a3SLandon J. Fuller * Map an bhnd(4) type/port/region triplet to its associated config block 400caeff9a3SLandon J. Fuller * entry, if any. 401caeff9a3SLandon J. Fuller * 402caeff9a3SLandon J. Fuller * The only supported port type is BHND_PORT_DEVICE. 403caeff9a3SLandon J. Fuller * 404caeff9a3SLandon J. Fuller * @param dinfo The device info to search for a matching address space. 405caeff9a3SLandon J. Fuller * @param type The bhnd(4) port type. 406caeff9a3SLandon J. Fuller * @param port The bhnd(4) port number. 407caeff9a3SLandon J. Fuller * @param region The bhnd(4) port region. 408caeff9a3SLandon J. Fuller */ 409caeff9a3SLandon J. Fuller struct siba_cfg_block * 410caeff9a3SLandon J. Fuller siba_find_cfg_block(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port, 411caeff9a3SLandon J. Fuller u_int region) 412caeff9a3SLandon J. Fuller { 413caeff9a3SLandon J. Fuller u_int cfgidx; 414caeff9a3SLandon J. Fuller int error; 415caeff9a3SLandon J. Fuller 416caeff9a3SLandon J. Fuller /* Map to addrspace index */ 417caeff9a3SLandon J. Fuller error = siba_cfg_index(&dinfo->core_id, type, port, region, &cfgidx); 418caeff9a3SLandon J. Fuller if (error) 419caeff9a3SLandon J. Fuller return (NULL); 420caeff9a3SLandon J. Fuller 421caeff9a3SLandon J. Fuller /* Found */ 422caeff9a3SLandon J. Fuller return (&dinfo->cfg[cfgidx]); 423caeff9a3SLandon J. Fuller } 424caeff9a3SLandon J. Fuller 425caeff9a3SLandon J. Fuller /** 426664a7497SLandon J. Fuller * Map a bhnd(4) type/port/region triplet to its associated address space 427664a7497SLandon J. Fuller * index, if any. 42806018a8eSLandon J. Fuller * 42906018a8eSLandon J. Fuller * For compatibility with bcma(4), we map address spaces to port/region 43006018a8eSLandon J. Fuller * identifiers as follows: 43106018a8eSLandon J. Fuller * 432*7c7c726bSLandon J. Fuller * [port.region] [admatch index] 43306018a8eSLandon J. Fuller * device0.0 0 43406018a8eSLandon J. Fuller * device1.0 1 43506018a8eSLandon J. Fuller * device1.1 2 43606018a8eSLandon J. Fuller * device1.2 3 43706018a8eSLandon J. Fuller * 438caeff9a3SLandon J. Fuller * @param core_id The siba core info. 439caeff9a3SLandon J. Fuller * @param port_type The bhnd(4) port type. 440664a7497SLandon J. Fuller * @param port The bhnd(4) port number. 441664a7497SLandon J. Fuller * @param region The bhnd(4) port region. 442664a7497SLandon J. Fuller * @param addridx On success, the corresponding addrspace index. 443664a7497SLandon J. Fuller * 444664a7497SLandon J. Fuller * @retval 0 success 445664a7497SLandon J. Fuller * @retval ENOENT if the given type/port/region cannot be mapped to a 446664a7497SLandon J. Fuller * siba address space. 447664a7497SLandon J. Fuller */ 448664a7497SLandon J. Fuller int 449caeff9a3SLandon J. Fuller siba_addrspace_index(struct siba_core_id *core_id, bhnd_port_type port_type, 450caeff9a3SLandon J. Fuller u_int port, u_int region, u_int *addridx) 451664a7497SLandon J. Fuller { 452664a7497SLandon J. Fuller u_int idx; 453664a7497SLandon J. Fuller 454caeff9a3SLandon J. Fuller /* Address spaces are always device ports */ 455caeff9a3SLandon J. Fuller if (port_type != BHND_PORT_DEVICE) 456caeff9a3SLandon J. Fuller return (ENOENT); 457caeff9a3SLandon J. Fuller 458caeff9a3SLandon J. Fuller /* Port must be valid */ 459caeff9a3SLandon J. Fuller if (!siba_is_port_valid(core_id, port_type, port)) 460664a7497SLandon J. Fuller return (ENOENT); 461664a7497SLandon J. Fuller 462664a7497SLandon J. Fuller if (port == 0) 463664a7497SLandon J. Fuller idx = region; 464664a7497SLandon J. Fuller else if (port == 1) 465664a7497SLandon J. Fuller idx = region + 1; 466664a7497SLandon J. Fuller else 467664a7497SLandon J. Fuller return (ENOENT); 468664a7497SLandon J. Fuller 469*7c7c726bSLandon J. Fuller if (idx >= core_id->num_admatch) 470664a7497SLandon J. Fuller return (ENOENT); 471664a7497SLandon J. Fuller 472664a7497SLandon J. Fuller /* Found */ 473664a7497SLandon J. Fuller *addridx = idx; 474664a7497SLandon J. Fuller return (0); 475664a7497SLandon J. Fuller } 476664a7497SLandon J. Fuller 477664a7497SLandon J. Fuller /** 478664a7497SLandon J. Fuller * Map an bhnd(4) type/port/region triplet to its associated address space 479664a7497SLandon J. Fuller * entry, if any. 480664a7497SLandon J. Fuller * 481664a7497SLandon J. Fuller * The only supported port type is BHND_PORT_DEVICE. 482664a7497SLandon J. Fuller * 48306018a8eSLandon J. Fuller * @param dinfo The device info to search for a matching address space. 48406018a8eSLandon J. Fuller * @param type The bhnd(4) port type. 48506018a8eSLandon J. Fuller * @param port The bhnd(4) port number. 48606018a8eSLandon J. Fuller * @param region The bhnd(4) port region. 4874ad7e9b0SAdrian Chadd */ 4884ad7e9b0SAdrian Chadd struct siba_addrspace * 48906018a8eSLandon J. Fuller siba_find_addrspace(struct siba_devinfo *dinfo, bhnd_port_type type, u_int port, 49006018a8eSLandon J. Fuller u_int region) 4914ad7e9b0SAdrian Chadd { 49206018a8eSLandon J. Fuller u_int addridx; 493664a7497SLandon J. Fuller int error; 4944ad7e9b0SAdrian Chadd 495664a7497SLandon J. Fuller /* Map to addrspace index */ 496caeff9a3SLandon J. Fuller error = siba_addrspace_index(&dinfo->core_id, type, port, region, 497caeff9a3SLandon J. Fuller &addridx); 498664a7497SLandon J. Fuller if (error) 49906018a8eSLandon J. Fuller return (NULL); 50006018a8eSLandon J. Fuller 50106018a8eSLandon J. Fuller /* Found */ 502664a7497SLandon J. Fuller if (addridx >= SIBA_MAX_ADDRSPACE) 503664a7497SLandon J. Fuller return (NULL); 504664a7497SLandon J. Fuller 50506018a8eSLandon J. Fuller return (&dinfo->addrspace[addridx]); 5064ad7e9b0SAdrian Chadd } 5074ad7e9b0SAdrian Chadd 5084ad7e9b0SAdrian Chadd /** 50906018a8eSLandon J. Fuller * Append an address space entry to @p dinfo. 5104ad7e9b0SAdrian Chadd * 5114ad7e9b0SAdrian Chadd * @param dinfo The device info entry to update. 51206018a8eSLandon J. Fuller * @param addridx The address space index. 5134ad7e9b0SAdrian Chadd * @param base The mapping's base address. 5144ad7e9b0SAdrian Chadd * @param size The mapping size. 5154ad7e9b0SAdrian Chadd * @param bus_reserved Number of bytes to reserve in @p size for bus use 5164ad7e9b0SAdrian Chadd * when registering the resource list entry. This is used to reserve bus 5174ad7e9b0SAdrian Chadd * access to the core's SIBA_CFG* register blocks. 5184ad7e9b0SAdrian Chadd * 5194ad7e9b0SAdrian Chadd * @retval 0 success 5204ad7e9b0SAdrian Chadd * @retval non-zero An error occurred appending the entry. 5214ad7e9b0SAdrian Chadd */ 522*7c7c726bSLandon J. Fuller static int 52306018a8eSLandon J. Fuller siba_append_dinfo_region(struct siba_devinfo *dinfo, uint8_t addridx, 52406018a8eSLandon J. Fuller uint32_t base, uint32_t size, uint32_t bus_reserved) 5254ad7e9b0SAdrian Chadd { 5264ad7e9b0SAdrian Chadd struct siba_addrspace *sa; 527f4a3eb02SAdrian Chadd rman_res_t r_size; 5284ad7e9b0SAdrian Chadd 5294ad7e9b0SAdrian Chadd /* Verify that base + size will not overflow */ 5307ba7852fSLandon J. Fuller if (size > 0 && UINT32_MAX - (size - 1) < base) 5314ad7e9b0SAdrian Chadd return (ERANGE); 5324ad7e9b0SAdrian Chadd 533f4a3eb02SAdrian Chadd /* Verify that size - bus_reserved will not underflow */ 534f4a3eb02SAdrian Chadd if (size < bus_reserved) 535f4a3eb02SAdrian Chadd return (ERANGE); 536f4a3eb02SAdrian Chadd 5374ad7e9b0SAdrian Chadd /* Must not be 0-length */ 5384ad7e9b0SAdrian Chadd if (size == 0) 5394ad7e9b0SAdrian Chadd return (EINVAL); 5404ad7e9b0SAdrian Chadd 54106018a8eSLandon J. Fuller /* Must not exceed addrspace array size */ 54206018a8eSLandon J. Fuller if (addridx >= nitems(dinfo->addrspace)) 5434ad7e9b0SAdrian Chadd return (EINVAL); 5444ad7e9b0SAdrian Chadd 54506018a8eSLandon J. Fuller /* Initialize new addrspace entry */ 54606018a8eSLandon J. Fuller sa = &dinfo->addrspace[addridx]; 5474ad7e9b0SAdrian Chadd sa->sa_base = base; 5484ad7e9b0SAdrian Chadd sa->sa_size = size; 549f4a3eb02SAdrian Chadd sa->sa_bus_reserved = bus_reserved; 5504ad7e9b0SAdrian Chadd 5514ad7e9b0SAdrian Chadd /* Populate the resource list */ 552f4a3eb02SAdrian Chadd r_size = size - bus_reserved; 5534ad7e9b0SAdrian Chadd sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY, 5547ba7852fSLandon J. Fuller base, base + (r_size - 1), r_size); 5554ad7e9b0SAdrian Chadd 5564ad7e9b0SAdrian Chadd return (0); 5574ad7e9b0SAdrian Chadd } 5584ad7e9b0SAdrian Chadd 5594ad7e9b0SAdrian Chadd /** 5604ad7e9b0SAdrian Chadd * Deallocate the given device info structure and any associated resources. 5614ad7e9b0SAdrian Chadd * 5624ad7e9b0SAdrian Chadd * @param dev The requesting bus device. 563caeff9a3SLandon J. Fuller * @param child The siba child device. 564caeff9a3SLandon J. Fuller * @param dinfo Device info associated with @p child to be deallocated. 5654ad7e9b0SAdrian Chadd */ 5664ad7e9b0SAdrian Chadd void 567caeff9a3SLandon J. Fuller siba_free_dinfo(device_t dev, device_t child, struct siba_devinfo *dinfo) 5684ad7e9b0SAdrian Chadd { 5694ad7e9b0SAdrian Chadd resource_list_free(&dinfo->resources); 5704ad7e9b0SAdrian Chadd 5714ad7e9b0SAdrian Chadd /* Free all mapped configuration blocks */ 5724ad7e9b0SAdrian Chadd for (u_int i = 0; i < nitems(dinfo->cfg); i++) { 573caeff9a3SLandon J. Fuller if (dinfo->cfg_res[i] == NULL) 5744ad7e9b0SAdrian Chadd continue; 5754ad7e9b0SAdrian Chadd 5764ad7e9b0SAdrian Chadd bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i], 577caeff9a3SLandon J. Fuller dinfo->cfg_res[i]); 5784ad7e9b0SAdrian Chadd 579caeff9a3SLandon J. Fuller dinfo->cfg_res[i] = NULL; 5804ad7e9b0SAdrian Chadd dinfo->cfg_rid[i] = -1; 5814ad7e9b0SAdrian Chadd } 5824ad7e9b0SAdrian Chadd 583caeff9a3SLandon J. Fuller /* Unmap the core's interrupt */ 584*7c7c726bSLandon J. Fuller if (dinfo->core_id.intr_en && dinfo->intr.mapped) { 585caeff9a3SLandon J. Fuller BHND_BUS_UNMAP_INTR(dev, child, dinfo->intr.irq); 586caeff9a3SLandon J. Fuller dinfo->intr.mapped = false; 587caeff9a3SLandon J. Fuller } 588caeff9a3SLandon J. Fuller 5894ad7e9b0SAdrian Chadd free(dinfo, M_BHND); 5904ad7e9b0SAdrian Chadd } 5914ad7e9b0SAdrian Chadd 5924ad7e9b0SAdrian Chadd /** 5934ad7e9b0SAdrian Chadd * Return the core-enumeration-relative offset for the @p addrspace 5944ad7e9b0SAdrian Chadd * SIBA_R0_ADMATCH* register. 5954ad7e9b0SAdrian Chadd * 5964ad7e9b0SAdrian Chadd * @param addrspace The address space index. 5974ad7e9b0SAdrian Chadd * 5984ad7e9b0SAdrian Chadd * @retval non-zero success 5994ad7e9b0SAdrian Chadd * @retval 0 the given @p addrspace index is not supported. 6004ad7e9b0SAdrian Chadd */ 6014ad7e9b0SAdrian Chadd u_int 6024ad7e9b0SAdrian Chadd siba_admatch_offset(uint8_t addrspace) 6034ad7e9b0SAdrian Chadd { 6044ad7e9b0SAdrian Chadd switch (addrspace) { 6054ad7e9b0SAdrian Chadd case 0: 6064ad7e9b0SAdrian Chadd return SB0_REG_ABS(SIBA_CFG0_ADMATCH0); 6074ad7e9b0SAdrian Chadd case 1: 6084ad7e9b0SAdrian Chadd return SB0_REG_ABS(SIBA_CFG0_ADMATCH1); 6094ad7e9b0SAdrian Chadd case 2: 6104ad7e9b0SAdrian Chadd return SB0_REG_ABS(SIBA_CFG0_ADMATCH2); 6114ad7e9b0SAdrian Chadd case 3: 6124ad7e9b0SAdrian Chadd return SB0_REG_ABS(SIBA_CFG0_ADMATCH3); 6134ad7e9b0SAdrian Chadd default: 6144ad7e9b0SAdrian Chadd return (0); 6154ad7e9b0SAdrian Chadd } 6164ad7e9b0SAdrian Chadd } 6174ad7e9b0SAdrian Chadd 6184ad7e9b0SAdrian Chadd /** 6194ad7e9b0SAdrian Chadd * Parse a SIBA_R0_ADMATCH* register. 6204ad7e9b0SAdrian Chadd * 6214ad7e9b0SAdrian Chadd * @param addrspace The address space index. 6224ad7e9b0SAdrian Chadd * @param am The address match register value to be parsed. 623*7c7c726bSLandon J. Fuller * @param[out] admatch The parsed address match descriptor 6244ad7e9b0SAdrian Chadd * 6254ad7e9b0SAdrian Chadd * @retval 0 success 626453130d9SPedro F. Giffuni * @retval non-zero a parse error occurred. 6274ad7e9b0SAdrian Chadd */ 6284ad7e9b0SAdrian Chadd int 629*7c7c726bSLandon J. Fuller siba_parse_admatch(uint32_t am, struct siba_admatch *admatch) 6304ad7e9b0SAdrian Chadd { 6314ad7e9b0SAdrian Chadd u_int am_type; 6324ad7e9b0SAdrian Chadd 6334ad7e9b0SAdrian Chadd /* Extract the base address and size */ 6344ad7e9b0SAdrian Chadd am_type = SIBA_REG_GET(am, AM_TYPE); 6354ad7e9b0SAdrian Chadd switch (am_type) { 6364ad7e9b0SAdrian Chadd case 0: 637*7c7c726bSLandon J. Fuller /* Type 0 entries are always enabled, and do not support 638*7c7c726bSLandon J. Fuller * negative matching */ 639*7c7c726bSLandon J. Fuller admatch->am_base = am & SIBA_AM_BASE0_MASK; 640*7c7c726bSLandon J. Fuller admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1); 641*7c7c726bSLandon J. Fuller admatch->am_enabled = true; 642*7c7c726bSLandon J. Fuller admatch->am_negative = false; 6434ad7e9b0SAdrian Chadd break; 6444ad7e9b0SAdrian Chadd case 1: 645*7c7c726bSLandon J. Fuller admatch->am_base = am & SIBA_AM_BASE1_MASK; 646*7c7c726bSLandon J. Fuller admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1); 647*7c7c726bSLandon J. Fuller admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0); 648*7c7c726bSLandon J. Fuller admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0); 6494ad7e9b0SAdrian Chadd break; 6504ad7e9b0SAdrian Chadd case 2: 651*7c7c726bSLandon J. Fuller admatch->am_base = am & SIBA_AM_BASE2_MASK; 652*7c7c726bSLandon J. Fuller admatch->am_size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1); 653*7c7c726bSLandon J. Fuller admatch->am_enabled = ((am & SIBA_AM_ADEN) != 0); 654*7c7c726bSLandon J. Fuller admatch->am_negative = ((am & SIBA_AM_ADNEG) != 0); 6554ad7e9b0SAdrian Chadd break; 6564ad7e9b0SAdrian Chadd default: 6574ad7e9b0SAdrian Chadd return (EINVAL); 6584ad7e9b0SAdrian Chadd } 6594ad7e9b0SAdrian Chadd 6604ad7e9b0SAdrian Chadd return (0); 6614ad7e9b0SAdrian Chadd } 6628a03f98aSLandon J. Fuller 6638a03f98aSLandon J. Fuller /** 664ac59515bSLandon J. Fuller * Write @p value to @p dev's CFG0 target/initiator state register, performing 665ac59515bSLandon J. Fuller * required read-back and waiting for completion. 6668a03f98aSLandon J. Fuller * 6678a03f98aSLandon J. Fuller * @param dev The siba(4) child device. 668ac59515bSLandon J. Fuller * @param reg The CFG0 state register to write (e.g. SIBA_CFG0_TMSTATELOW, 6698a03f98aSLandon J. Fuller * SIBA_CFG0_IMSTATE) 6708a03f98aSLandon J. Fuller * @param value The value to write to @p reg. 6718a03f98aSLandon J. Fuller * @param mask The mask of bits to be included from @p value. 6728a03f98aSLandon J. Fuller */ 673ac59515bSLandon J. Fuller void 6748a03f98aSLandon J. Fuller siba_write_target_state(device_t dev, struct siba_devinfo *dinfo, 6758a03f98aSLandon J. Fuller bus_size_t reg, uint32_t value, uint32_t mask) 6768a03f98aSLandon J. Fuller { 6778a03f98aSLandon J. Fuller struct bhnd_resource *r; 6788a03f98aSLandon J. Fuller uint32_t rval; 6798a03f98aSLandon J. Fuller 680ac59515bSLandon J. Fuller r = dinfo->cfg_res[0]; 6818a03f98aSLandon J. Fuller 682ac59515bSLandon J. Fuller KASSERT(r != NULL, ("%s missing CFG0 mapping", 683ac59515bSLandon J. Fuller device_get_nameunit(dev))); 684ac59515bSLandon J. Fuller KASSERT(reg <= SIBA_CFG_SIZE-4, ("%s invalid CFG0 register offset %#jx", 685ac59515bSLandon J. Fuller device_get_nameunit(dev), (uintmax_t)reg)); 6868a03f98aSLandon J. Fuller 6878a03f98aSLandon J. Fuller rval = bhnd_bus_read_4(r, reg); 6888a03f98aSLandon J. Fuller rval &= ~mask; 6898a03f98aSLandon J. Fuller rval |= (value & mask); 6908a03f98aSLandon J. Fuller 6918a03f98aSLandon J. Fuller bhnd_bus_write_4(r, reg, rval); 6928a03f98aSLandon J. Fuller bhnd_bus_read_4(r, reg); /* read-back */ 6938a03f98aSLandon J. Fuller DELAY(1); 6948a03f98aSLandon J. Fuller } 6958a03f98aSLandon J. Fuller 6968a03f98aSLandon J. Fuller /** 697ac59515bSLandon J. Fuller * Spin for up to @p usec waiting for @p dev's CFG0 target/initiator state 698ac59515bSLandon J. Fuller * register value to be equal to @p value after applying @p mask bits to both 699ac59515bSLandon J. Fuller * values. 7008a03f98aSLandon J. Fuller * 7018a03f98aSLandon J. Fuller * @param dev The siba(4) child device to wait on. 7028a03f98aSLandon J. Fuller * @param dinfo The @p dev's device info 703ac59515bSLandon J. Fuller * @param reg The state register to read (e.g. SIBA_CFG0_TMSTATEHIGH, 704ac59515bSLandon J. Fuller * SIBA_CFG0_IMSTATE) 705ac59515bSLandon J. Fuller * @param value The value against which @p reg will be compared. 706ac59515bSLandon J. Fuller * @param mask The mask to be applied when comparing @p value with @p reg. 707ac59515bSLandon J. Fuller * @param usec The maximum number of microseconds to wait for completion. 7088a03f98aSLandon J. Fuller * 7098a03f98aSLandon J. Fuller * @retval 0 if SIBA_TMH_BUSY is cleared prior to the @p usec timeout. 7108a03f98aSLandon J. Fuller * @retval ENODEV if SIBA_CFG0 is not mapped by @p dinfo. 711ac59515bSLandon J. Fuller * @retval ETIMEDOUT if a timeout occurs. 7128a03f98aSLandon J. Fuller */ 7138a03f98aSLandon J. Fuller int 714ac59515bSLandon J. Fuller siba_wait_target_state(device_t dev, struct siba_devinfo *dinfo, bus_size_t reg, 715ac59515bSLandon J. Fuller uint32_t value, uint32_t mask, u_int usec) 7168a03f98aSLandon J. Fuller { 7178a03f98aSLandon J. Fuller struct bhnd_resource *r; 718ac59515bSLandon J. Fuller uint32_t rval; 7198a03f98aSLandon J. Fuller 720caeff9a3SLandon J. Fuller if ((r = dinfo->cfg_res[0]) == NULL) 7218a03f98aSLandon J. Fuller return (ENODEV); 7228a03f98aSLandon J. Fuller 723ac59515bSLandon J. Fuller value &= mask; 7248a03f98aSLandon J. Fuller for (int i = 0; i < usec; i += 10) { 725ac59515bSLandon J. Fuller rval = bhnd_bus_read_4(r, reg); 726ac59515bSLandon J. Fuller if ((rval & mask) == value) 7278a03f98aSLandon J. Fuller return (0); 7288a03f98aSLandon J. Fuller 7298a03f98aSLandon J. Fuller DELAY(10); 7308a03f98aSLandon J. Fuller } 7318a03f98aSLandon J. Fuller 7328a03f98aSLandon J. Fuller return (ETIMEDOUT); 7338a03f98aSLandon J. Fuller } 734