/* * Add an int property 'name' to an MD from an existing PROM property. If * the 'alt_name' PROM property exists then the MD property is created with * the value of the PROM 'alt_name' property, otherwise it is created with * the value of the PROM 'name' property. */ static int add_prom_int_prop(di_prom_handle_t ph, mmd_t *mdp, md_node_t *np, di_node_t di, char *name, char *alt_name) { int count; int rv = 0; int *pp_data = NULL; if (alt_name != NULL) { count = di_prom_prop_lookup_ints(ph, di, alt_name, &pp_data); } if (pp_data == NULL) { count = di_prom_prop_lookup_ints(ph, di, name, &pp_data); } /* * Note: We know that the properties of interest contain a * a single int. */ if (count > 0 && pp_data != NULL) { ASSERT(count == 1); rv = md_add_value_property(mdp, np, name, *pp_data); } return (rv); }
/* * add OBP_REG property to picl cpu node if it's not already there. */ static void add_reg_prop(picl_nodehdl_t pn, di_node_t dn) { int reg_prop[SUN4V_CPU_REGSIZE]; int status; int dlen; int *pdata; ptree_propinfo_t propinfo; status = ptree_get_propval_by_name(pn, OBP_REG, reg_prop, sizeof (reg_prop)); if (status == PICL_SUCCESS) { return; } dlen = di_prom_prop_lookup_ints(ph, dn, OBP_REG, &pdata); if (dlen < 0) { return; } status = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, PICL_PTYPE_BYTEARRAY, PICL_READ, dlen * sizeof (int), OBP_REG, NULL, NULL); if (status != PICL_SUCCESS) { return; } (void) ptree_create_and_add_prop(pn, &propinfo, pdata, NULL); }
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); }
static int get_prom_int(char *prop_name, di_node_t node, di_prom_handle_t ph) { int *n; if (di_prom_prop_lookup_ints(ph, node, prop_name, &n) == 1) { return (*n); } return (0); }
static int get_reg_dev(di_node_t node) { int *reg = NULL; if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, OBP_REG, ®) < 0) { if (di_prom_prop_lookup_ints(prom_handle, node, OBP_REG, ®) < 0) { return (-1); } return (PCI_REG_DEV_G(reg[0])); } return (PCI_REG_DEV_G(reg[0])); }
/* * Given a devinfo node find its reg property. */ static int get_reg_prop(di_node_t dn, int **pdata) { int dret = 0; dret = di_prop_lookup_ints(DDI_DEV_T_ANY, dn, OBP_REG, pdata); if (dret > 0) return (dret); if (!ph) return (0); dret = di_prom_prop_lookup_ints(ph, dn, OBP_REG, pdata); return (dret < 0? 0 : dret); }
/* * Get the NIU/Neptune ethernet function number from the reg property */ static int niufn_instance_get(topo_mod_t *mod, di_node_t node, topo_instance_t *inst) { di_prom_handle_t phan; int rval, *intp; *inst = (topo_instance_t)0; rval = -1; if ((phan = topo_mod_prominfo(mod)) != DI_PROM_HANDLE_NIL) { rval = di_prom_prop_lookup_ints(phan, node, DI_PROP_REG, &intp); } if (rval < 0) { rval = di_prop_lookup_ints(DDI_DEV_T_ANY, node, DI_PROP_REG, &intp); if (rval < 0) return (-1); } *inst = (topo_instance_t)intp[0]; return (0); }
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); }
/* * Solaris version */ static int pci_device_solx_devfs_probe( struct pci_device * dev ) { int err = 0; di_node_t rnode = DI_NODE_NIL; i_devnode_t args = { 0, 0, 0, DI_NODE_NIL }; int *regbuf; pci_regspec_t *reg; int i; int len = 0; uint ent = 0; nexus_t *nexus; #ifdef __sparc if ( (nexus = find_nexus_for_dev(dev)) == NULL ) #else if ( (nexus = find_nexus_for_bus(dev->domain, dev->bus)) == NULL ) #endif return ENODEV; /* * starting to find if it is MEM/MEM64/IO * using libdevinfo */ if ((rnode = di_init(nexus->dev_path, DINFOCPYALL)) == DI_NODE_NIL) { err = errno; (void) fprintf(stderr, "di_init failed: %s\n", strerror(errno)); } else { args.bus = dev->bus; args.dev = dev->dev; args.func = dev->func; (void) di_walk_node(rnode, DI_WALK_CLDFIRST, (void *)&args, find_target_node); } if (args.node != DI_NODE_NIL) { #ifdef __sparc di_minor_t minor; #endif #ifdef __sparc if (minor = di_minor_next(args.node, DI_MINOR_NIL)) MAPPING_DEV_PATH(dev) = di_devfs_minor_path (minor); else MAPPING_DEV_PATH(dev) = NULL; #endif /* * It will succeed for sure, because it was * successfully called in find_target_node */ len = di_prop_lookup_ints(DDI_DEV_T_ANY, args.node, "assigned-addresses", ®buf); #ifdef __sparc if ((len <= 0) && di_phdl) { len = di_prom_prop_lookup_ints(di_phdl, args.node, "assigned-addresses", ®buf); } #endif } if (len <= 0) goto cleanup; /* * how to find the size of rom??? * if the device has expansion rom, * it must be listed in the last * cells because solaris find probe * the base address from offset 0x10 * to 0x30h. So only check the last * item. */ reg = (pci_regspec_t *)®buf[len - CELL_NUMS_1275]; if (PCI_REG_REG_G(reg->pci_phys_hi) == PCI_CONF_ROM) { /* * rom can only be 32 bits */ dev->rom_size = reg->pci_size_low; len = len - CELL_NUMS_1275; } else { /* * size default to 64K and base address * default to 0xC0000 */ dev->rom_size = 0x10000; } /* * Solaris has its own BAR index. * Linux give two region slot for 64 bit address. */ for (i = 0; i < len; i = i + CELL_NUMS_1275) { reg = (pci_regspec_t *)®buf[i]; ent = reg->pci_phys_hi & 0xff; /* * G35 broken in BAR0 */ ent = (ent - PCI_CONF_BASE0) >> 2; if (ent >= 6) { fprintf(stderr, "error ent = %d\n", ent); break; } /* * non relocatable resource is excluded * such like 0xa0000, 0x3b0. If it is met, * the loop is broken; */ if (!PCI_REG_REG_G(reg->pci_phys_hi)) break; if (reg->pci_phys_hi & PCI_PREFETCH_B) { dev->regions[ent].is_prefetchable = 1; } /* * We split the shift count 32 into two 16 to * avoid the complaining of the compiler */ dev->regions[ent].base_addr = reg->pci_phys_low + ((reg->pci_phys_mid << 16) << 16); dev->regions[ent].size = reg->pci_size_low + ((reg->pci_size_hi << 16) << 16); switch (reg->pci_phys_hi & PCI_REG_ADDR_M) { case PCI_ADDR_IO: dev->regions[ent].is_IO = 1; break; case PCI_ADDR_MEM32: break; case PCI_ADDR_MEM64: dev->regions[ent].is_64 = 1; /* * Skip one slot for 64 bit address */ break; } } cleanup: if (rnode != DI_NODE_NIL) { di_fini(rnode); } return (err); }
/* * 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; }