/* * function to read the PCI Bus, Device, and function numbers for the * device instance. * * dev - handle to device private data */ int oce_get_bdf(struct oce_dev *dev) { pci_regspec_t *pci_rp; uint32_t length; int rc; /* Get "reg" property */ rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dev->dip, 0, "reg", (int **)&pci_rp, (uint_t *)&length); if ((rc != DDI_SUCCESS) || (length < (sizeof (pci_regspec_t) / sizeof (int)))) { oce_log(dev, CE_WARN, MOD_CONFIG, "Failed to read \"reg\" property, Status = 0x%x", rc); return (rc); } dev->pci_bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); dev->pci_device = PCI_REG_DEV_G(pci_rp->pci_phys_hi); dev->pci_function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); oce_log(dev, CE_NOTE, MOD_CONFIG, "\"reg\" property num=%d, Bus=%d, Device=%d, Function=%d", length, dev->pci_bus, dev->pci_device, dev->pci_function); /* Free the memory allocated by ddi_prop_lookup_int_array() */ ddi_prop_free(pci_rp); return (rc); }
static int gfxp_pci_get_bsf(dev_info_t *dip, uint8_t *bus, uint8_t *dev, uint8_t *func) { pci_regspec_t *pci_rp; uint32_t length; int rc; /* get "reg" property */ rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, (uint_t *)&length); if ((rc != DDI_SUCCESS) || (length < (sizeof (pci_regspec_t) / sizeof (int)))) { return (DDI_FAILURE); } *bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); *dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); *func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); /* * free the memory allocated by ddi_prop_lookup_int_array(). */ ddi_prop_free(pci_rp); return (DDI_SUCCESS); }
static int find_target_node(di_node_t node, void *arg) { int *regbuf = NULL; int len = 0; uint32_t busno, funcno, devno; i_devnode_t *devnode = (i_devnode_t *)arg; /* * Test the property functions, only for testing */ /* void *prop = DI_PROP_NIL; (void) fprintf(stderr, "start of node 0x%x\n", node->nodeid); while ((prop = di_prop_hw_next(node, prop)) != DI_PROP_NIL) { int i; (void) fprintf(stderr, "name=%s: ", di_prop_name(prop)); len = 0; if (!strcmp(di_prop_name(prop), "reg")) { len = di_prop_ints(prop, ®buf); } for (i = 0; i < len; i++) { fprintf(stderr, "0x%0x.", regbuf[i]); } fprintf(stderr, "\n"); } (void) fprintf(stderr, "end of node 0x%x\n", node->nodeid); */ len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", ®buf); #ifdef __sparc if ((len <= 0) && di_phdl) len = di_prom_prop_lookup_ints(di_phdl, node, "reg", ®buf); #endif if (len <= 0) { #ifdef DEBUG fprintf(stderr, "error = %x\n", errno); fprintf(stderr, "can not find assigned-address\n"); #endif return (DI_WALK_CONTINUE); } busno = PCI_REG_BUS_G(regbuf[0]); devno = PCI_REG_DEV_G(regbuf[0]); funcno = PCI_REG_FUNC_G(regbuf[0]); if ((busno == devnode->bus) && (devno == devnode->dev) && (funcno == devnode->func)) { devnode->node = node; return (DI_WALK_TERMINATE); } return (DI_WALK_CONTINUE); }
int get_bdf(dev_info_t *dip, int *bus, int *device, int *func) { pci_regspec_t *pci_rp; int len; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, (uint_t *)&len) != DDI_SUCCESS) return (-1); if (len < (sizeof (pci_regspec_t) / sizeof (int))) { ddi_prop_free(pci_rp); return (-1); } if (bus != NULL) *bus = (int)PCI_REG_BUS_G(pci_rp->pci_phys_hi); if (device != NULL) *device = (int)PCI_REG_DEV_G(pci_rp->pci_phys_hi); if (func != NULL) *func = (int)PCI_REG_FUNC_G(pci_rp->pci_phys_hi); ddi_prop_free(pci_rp); return (0); }
static int sunos_add_devices(di_devlink_t link, void *arg) { struct devlink_cbarg *largs = (struct devlink_cbarg *)arg; struct node_args *nargs; di_node_t myself, pnode; uint64_t session_id = 0; uint16_t bdf = 0; struct libusb_device *dev; sunos_dev_priv_t *devpriv; const char *path, *newpath; int n, i; int *addr_prop; uint8_t bus_number = 0; nargs = (struct node_args *)largs->nargs; myself = largs->myself; if (nargs->last_ugenpath) { /* the same node's links */ return (DI_WALK_CONTINUE); } /* * Construct session ID. * session ID = ...parent hub addr|hub addr|dev addr. */ pnode = myself; i = 0; while (pnode != DI_NODE_NIL) { if (di_prop_exists(DDI_DEV_T_ANY, pnode, "root-hub") == 1) { /* walk to root */ uint32_t *regbuf = NULL; uint32_t reg; n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "reg", (int **)®buf); reg = regbuf[0]; bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); session_id |= (bdf << i * 8); /* same as 'unit-address' property */ bus_number = (PCI_REG_DEV_G(reg) << 3) | PCI_REG_FUNC_G(reg); usbi_dbg("device bus address=%s:%x", di_bus_addr(pnode), bus_number); break; } /* usb_addr */ n = di_prop_lookup_ints(DDI_DEV_T_ANY, pnode, "assigned-address", &addr_prop); if ((n != 1) || (addr_prop[0] == 0)) { usbi_dbg("cannot get valid usb_addr"); return (DI_WALK_CONTINUE); } session_id |= ((addr_prop[0] & 0xff) << i * 8); if (++i > 7) break; pnode = di_parent_node(pnode); } path = di_devlink_path(link); dev = usbi_get_device_by_session_id(nargs->ctx, session_id); if (dev == NULL) { dev = usbi_alloc_device(nargs->ctx, session_id); if (dev == NULL) { usbi_dbg("can't alloc device"); return (DI_WALK_TERMINATE); } devpriv = (sunos_dev_priv_t *)dev->os_priv; if ((newpath = strrchr(path, '/')) == NULL) { libusb_unref_device(dev); return (DI_WALK_TERMINATE); } devpriv->ugenpath = strndup(path, strlen(path) - strlen(newpath)); dev->bus_number = bus_number; if (sunos_fill_in_dev_info(myself, dev) != LIBUSB_SUCCESS) { libusb_unref_device(dev); return (DI_WALK_TERMINATE); } if (usbi_sanitize_device(dev) < 0) { libusb_unref_device(dev); usbi_dbg("sanatize failed: "); return (DI_WALK_TERMINATE); } } else { usbi_dbg("Dev %s exists", path); } devpriv = (sunos_dev_priv_t *)dev->os_priv; if (nargs->last_ugenpath == NULL) { /* first device */ nargs->last_ugenpath = devpriv->ugenpath; if (discovered_devs_append(*(nargs->discdevs), dev) == NULL) { usbi_dbg("cannot append device"); } /* * we alloc and hence ref this dev. We don't need to ref it * hereafter. Front end or app should take care of their ref. */ libusb_unref_device(dev); } usbi_dbg("Device %s %s id=0x%llx, devcount:%d, bdf=%x", devpriv->ugenpath, path, (uint64_t)session_id, (*nargs->discdevs)->len, bdf); return (DI_WALK_CONTINUE); }
/* * This function is called from di_walk_minor() when any PROBE is processed */ static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) { probe_info_t *pinfo = (probe_info_t *)arg; char *nexus_name, *nexus_dev_path; nexus_t *nexus; int fd; char nexus_path[MAXPATHLEN]; di_prop_t prop; char *strings; int *ints; int numval; int pci_node = 0; int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M); int domain = 0; di_node_t rnode = DI_NODE_NIL; #ifdef __sparc int bus_range_found = 0; int device_type_found = 0; di_prom_prop_t prom_prop; #endif #ifdef DEBUG nexus_name = di_devfs_minor_path(minor); fprintf(stderr, "-- device name: %s\n", nexus_name); di_devfs_path_free(nexus_name); #endif for (prop = di_prop_next(di_node, NULL); prop != NULL; prop = di_prop_next(di_node, prop)) { const char *prop_name = di_prop_name(prop); #ifdef DEBUG fprintf(stderr, " property: %s\n", prop_name); #endif if (strcmp(prop_name, "device_type") == 0) { numval = di_prop_strings(prop, &strings); if (numval == 1) { if (strncmp(strings, "pci", 3) != 0) /* not a PCI node, bail */ return (DI_WALK_CONTINUE); else { pci_node = 1; #ifdef __sparc device_type_found = 1; #endif } } } else if (strcmp(prop_name, "class-code") == 0) { /* not a root bus node, bail */ return (DI_WALK_CONTINUE); } else if (strcmp(prop_name, "bus-range") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 2) { first_bus = ints[0]; last_bus = ints[1]; #ifdef __sparc bus_range_found = 1; #endif } } #ifdef __sparc domain = nexus_count; #else else if (strcmp(prop_name, "pciseg") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 1) { domain = ints[0]; } } #endif }
static int probe_device_node(di_node_t node, void *arg) { int *retbuf = NULL; int len = 0, i; struct pci_device *pci_base; probe_info_t *pinfo = ((probe_args_t *)arg)->pinfo; nexus_t *nexus = ((probe_args_t *)arg)->nexus; property_info_t property_list[] = { { "class-code", 0 }, { "device-id", 0 }, { "vendor-id", 0 }, { "revision-id", 0}, { "subsystem-vendor-id", 0}, { "subsystem-id", 0}, }; #define NUM_PROPERTIES sizeof(property_list)/sizeof(property_info_t) len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", &retbuf); #ifdef __sparc if ((len <= 0) && di_phdl) len = di_prom_prop_lookup_ints(di_phdl, node, "reg", &retbuf); #endif /* Exclude usb devices */ if (len < 5) { return DI_WALK_CONTINUE; } pci_base = &pinfo->devices[pinfo->num_devices].base; pci_base->domain = nexus->domain; pci_base->bus = PCI_REG_BUS_G(retbuf[0]); pci_base->dev = PCI_REG_DEV_G(retbuf[0]); pci_base->func = PCI_REG_FUNC_G(retbuf[0]); /* Get property values */ for (i = 0; i < NUM_PROPERTIES; i++) { len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, property_list[i].name, &retbuf); #ifdef __sparc if ((len <= 0) && di_phdl) len = di_prom_prop_lookup_ints(di_phdl, node, property_list[i].name, &retbuf); #endif if (len > 0) property_list[i].value = retbuf[0]; else { /* a device must have property "class-code", "device-id", "vendor-id" */ if (i < 3) return DI_WALK_CONTINUE; #ifdef DEBUG fprintf(stderr, "cannot get property \"%s\" for nexus = %s :\n", property_list[i].name, nexus->path); fprintf(stderr, " domain = %x, busno = %x, devno = %x, funcno = %x\n", pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func); #endif } } if ((property_list[1].value == 0) && (property_list[2].value == 0)) return DI_WALK_CONTINUE; pci_base->device_class = property_list[0].value; pci_base->device_id = property_list[1].value; pci_base->vendor_id = property_list[2].value; pci_base->revision = property_list[3].value; pci_base->subvendor_id = property_list[4].value; pci_base->subdevice_id = property_list[5].value; #ifdef DEBUG fprintf(stderr, "nexus = %s, domain = %x, busno = %x, devno = %x, funcno = %x\n", nexus->path, pci_base->domain, pci_base->bus, pci_base->dev, pci_base->func); #endif pinfo->num_devices++; if (pinfo->num_devices == pinfo->num_allocated_elems) { struct pci_device_private *new_devs; size_t new_num_elems = pinfo->num_allocated_elems * 2; new_devs = realloc(pinfo->devices, new_num_elems * sizeof (struct pci_device_private)); if (new_devs == NULL) { (void) fprintf(stderr, "Error allocating memory for PCI devices:" " %s\n discarding additional devices\n", strerror(errno)); ((probe_args_t *)arg)->ret = 1; return (DI_WALK_TERMINATE); } (void) memset(&new_devs[pinfo->num_devices], 0, pinfo->num_allocated_elems * sizeof (struct pci_device_private)); pinfo->num_allocated_elems = new_num_elems; pinfo->devices = new_devs; } return (DI_WALK_CONTINUE); }
/* * This function is called from di_walk_minor() when any PROBE is processed */ static int probe_nexus_node(di_node_t di_node, di_minor_t minor, void *arg) { probe_info_t *pinfo = (probe_info_t *)arg; char *nexus_name, *nexus_dev_path; nexus_t *nexus; int fd; char nexus_path[MAXPATHLEN]; di_prop_t prop; char *strings; int *ints; int numval; int pci_node = 0; int first_bus = 0, last_bus = PCI_REG_BUS_G(PCI_REG_BUS_M); int domain = 0; #ifdef __sparc int bus_range_found = 0; int device_type_found = 0; di_prom_prop_t prom_prop; #endif #ifdef DEBUG nexus_name = di_devfs_minor_path(minor); fprintf(stderr, "-- device name: %s\n", nexus_name); #endif for (prop = di_prop_next(di_node, NULL); prop != NULL; prop = di_prop_next(di_node, prop)) { const char *prop_name = di_prop_name(prop); #ifdef DEBUG fprintf(stderr, " property: %s\n", prop_name); #endif if (strcmp(prop_name, "device_type") == 0) { numval = di_prop_strings(prop, &strings); if (numval == 1) { if (strncmp(strings, "pci", 3) != 0) /* not a PCI node, bail */ return (DI_WALK_CONTINUE); else { pci_node = 1; #ifdef __sparc device_type_found = 1; #endif } } } else if (strcmp(prop_name, "class-code") == 0) { /* not a root bus node, bail */ return (DI_WALK_CONTINUE); } else if (strcmp(prop_name, "bus-range") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 2) { first_bus = ints[0]; last_bus = ints[1]; #ifdef __sparc bus_range_found = 1; #endif } } else if (strcmp(prop_name, "pciseg") == 0) { numval = di_prop_ints(prop, &ints); if (numval == 1) { domain = ints[0]; } } } #ifdef __sparc if ((!device_type_found) && di_phdl) { numval = di_prom_prop_lookup_strings(di_phdl, di_node, "device_type", &strings); if (numval == 1) { if (strncmp(strings, "pci", 3) != 0) return (DI_WALK_CONTINUE); else pci_node = 1; } } if ((!bus_range_found) && di_phdl) { numval = di_prom_prop_lookup_ints(di_phdl, di_node, "bus-range", &ints); if (numval == 2) { first_bus = ints[0]; last_bus = ints[1]; } } #endif if (pci_node != 1) return (DI_WALK_CONTINUE); /* we have a PCI root bus node. */ nexus = calloc(1, sizeof(nexus_t)); if (nexus == NULL) { (void) fprintf(stderr, "Error allocating memory for nexus: %s\n", strerror(errno)); return (DI_WALK_TERMINATE); } nexus->first_bus = first_bus; nexus->last_bus = last_bus; nexus->domain = domain; #ifdef __sparc if ((nexus->devlist = calloc(INITIAL_NUM_DEVICES, sizeof (struct pci_device *))) == NULL) { (void) fprintf(stderr, "Error allocating memory for nexus devlist: %s\n", strerror(errno)); free (nexus); return (DI_WALK_TERMINATE); } nexus->num_allocated_elems = INITIAL_NUM_DEVICES; nexus->num_devices = 0; #endif nexus_name = di_devfs_minor_path(minor); if (nexus_name == NULL) { (void) fprintf(stderr, "Error getting nexus path: %s\n", strerror(errno)); free(nexus); return (DI_WALK_CONTINUE); } snprintf(nexus_path, sizeof(nexus_path), "/devices%s", nexus_name); di_devfs_path_free(nexus_name); #ifdef DEBUG fprintf(stderr, "nexus = %s, bus-range = %d - %d\n", nexus_path, first_bus, last_bus); #endif if ((fd = open(nexus_path, O_RDWR | O_CLOEXEC)) >= 0) { nexus->fd = fd; nexus->path = strdup(nexus_path); nexus_dev_path = di_devfs_path(di_node); nexus->dev_path = strdup(nexus_dev_path); di_devfs_path_free(nexus_dev_path); if ((do_probe(nexus, pinfo) != 0) && (errno != ENXIO)) { (void) fprintf(stderr, "Error probing node %s: %s\n", nexus_path, strerror(errno)); (void) close(fd); free(nexus->path); free(nexus->dev_path); free(nexus); } else { nexus->next = nexus_list; nexus_list = nexus; } } else { (void) fprintf(stderr, "Error opening %s: %s\n", nexus_path, strerror(errno)); free(nexus); } return DI_WALK_CONTINUE; }
static int pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, off_t offset, off_t len, caddr_t *vaddrp) { struct regspec reg; ddi_map_req_t mr; ddi_acc_hdl_t *hp; pci_regspec_t pci_reg; pci_regspec_t *pci_rp; int rnumber; int length; pci_acc_cfblk_t *cfp; int space; mr = *mp; /* Get private copy of request */ mp = &mr; /* * check for register number */ switch (mp->map_type) { case DDI_MT_REGSPEC: pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); pci_rp = &pci_reg; if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) return (DDI_FAILURE); break; case DDI_MT_RNUMBER: rnumber = mp->map_obj.rnumber; /* * get ALL "reg" properties for dip, select the one of * of interest. In x86, "assigned-addresses" property * is identical to the "reg" property, so there is no * need to cross check the two to determine the physical * address of the registers. * This routine still performs some validity checks to * make sure that everything is okay. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) return (DDI_FAILURE); /* * validate the register number. */ length /= (sizeof (pci_regspec_t) / sizeof (int)); if (rnumber >= length) { ddi_prop_free(pci_rp); return (DDI_FAILURE); } /* * copy the required entry. */ pci_reg = pci_rp[rnumber]; /* * free the memory allocated by ddi_prop_lookup_int_array */ ddi_prop_free(pci_rp); pci_rp = &pci_reg; if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) return (DDI_FAILURE); mp->map_type = DDI_MT_REGSPEC; break; default: return (DDI_ME_INVAL); } space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; /* * check for unmap and unlock of address space */ if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { /* * Adjust offset and length * A non-zero length means override the one in the regspec. */ pci_rp->pci_phys_low += (uint_t)offset; if (len != 0) pci_rp->pci_size_low = len; switch (space) { case PCI_ADDR_CONFIG: /* No work required on unmap of Config space */ return (DDI_SUCCESS); case PCI_ADDR_IO: reg.regspec_bustype = 1; break; case PCI_ADDR_MEM64: /* * MEM64 requires special treatment on map, to check * that the device is below 4G. On unmap, however, * we can assume that everything is OK... the map * must have succeeded. */ /* FALLTHROUGH */ case PCI_ADDR_MEM32: reg.regspec_bustype = 0; break; default: return (DDI_FAILURE); } reg.regspec_addr = pci_rp->pci_phys_low; reg.regspec_size = pci_rp->pci_size_low; mp->map_obj.rp = ® return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); } /* check for user mapping request - not legal for Config */ if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { return (DDI_FAILURE); } /* * check for config space * On x86, CONFIG is not mapped via MMU and there is * no endian-ness issues. Set the attr field in the handle to * indicate that the common routines to call the nexus driver. */ if (space == PCI_ADDR_CONFIG) { /* Can't map config space without a handle */ hp = (ddi_acc_hdl_t *)mp->map_handlep; if (hp == NULL) return (DDI_FAILURE); /* record the device address for future reference */ cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); *vaddrp = (caddr_t)offset; return (pci_fm_acc_setup(hp, offset, len)); } /* * range check */ if ((offset >= pci_rp->pci_size_low) || (len > pci_rp->pci_size_low) || (offset + len > pci_rp->pci_size_low)) { return (DDI_FAILURE); } /* * Adjust offset and length * A non-zero length means override the one in the regspec. */ pci_rp->pci_phys_low += (uint_t)offset; if (len != 0) pci_rp->pci_size_low = len; /* * convert the pci regsec into the generic regspec used by the * parent root nexus driver. */ switch (space) { case PCI_ADDR_IO: reg.regspec_bustype = 1; break; case PCI_ADDR_MEM64: /* * We can't handle 64-bit devices that are mapped above * 4G or that are larger than 4G. */ if (pci_rp->pci_phys_mid != 0 || pci_rp->pci_size_hi != 0) return (DDI_FAILURE); /* * Other than that, we can treat them as 32-bit mappings */ /* FALLTHROUGH */ case PCI_ADDR_MEM32: reg.regspec_bustype = 0; break; default: return (DDI_FAILURE); } reg.regspec_addr = pci_rp->pci_phys_low; reg.regspec_size = pci_rp->pci_size_low; mp->map_obj.rp = ® return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); }