static int acebus_update_props(ebus_devstate_t *ebus_p) { dev_info_t *dip = ebus_p->dip; struct ebus_pci_rangespec er[2], *erp; pci_regspec_t *pci_rp, *prp; int length, rnums, imask[3], i, found = 0; /* * If "ranges" property is found, then the device is initialized * by OBP, hence simply return. * Otherwise we create all the properties here. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", (int **)&erp, (uint_t *)&length) == DDI_PROP_SUCCESS) { ddi_prop_free(erp); return (DDI_SUCCESS); } /* * interrupt-map is the only property that comes from a .conf file. * Since it doesn't have the nodeid field set, it must be done here. * Other properties can come from OBP or created here. */ if (acebus_set_imap(dip) != DDI_SUCCESS) { return (DDI_FAILURE); } /* * Create the "ranges" property. * Ebus has BAR0 and BAR1 allocated (both in memory space). * Other BARs are 0. * Hence there are 2 memory ranges it operates in. (one for each BAR). * ie. there are 2 entries in its ranges property. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "assigned-addresses", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not get assigned-addresses", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } /* * Create the 1st mem range in which it operates corresponding * to BAR0 */ er[0].ebus_phys_hi = EBUS_CHILD_PHYS_LOW_RANGE; rnums = (length * sizeof (int))/sizeof (pci_regspec_t); for (i = 0; i < rnums; i++) { prp = pci_rp + i; if (PCI_REG_REG_G(prp->pci_phys_hi) == er[0].ebus_phys_hi) { found = 1; break; } } if (!found) { cmn_err(CE_WARN, "No assigned space for memory range 0."); ddi_prop_free(pci_rp); return (DDI_FAILURE); } found = 0; er[0].ebus_phys_low = 0; er[0].pci_phys_hi = prp->pci_phys_hi; er[0].pci_phys_mid = prp->pci_phys_mid; er[0].pci_phys_low = prp->pci_phys_low; er[0].rng_size = prp->pci_size_low; /* * Create the 2nd mem range in which it operates corresponding * to BAR1 */ er[1].ebus_phys_hi = EBUS_CHILD_PHYS_HI_RANGE; for (i = 0; i < rnums; i++) { prp = pci_rp + i; if (PCI_REG_REG_G(prp->pci_phys_hi) == er[1].ebus_phys_hi) { found = 1; break; } } if (!found) { cmn_err(CE_WARN, "No assigned space for memory range 1."); ddi_prop_free(pci_rp); return (DDI_FAILURE); } er[1].ebus_phys_low = 0; er[1].pci_phys_hi = prp->pci_phys_hi; er[1].pci_phys_mid = prp->pci_phys_mid; er[1].pci_phys_low = prp->pci_phys_low; er[1].rng_size = prp->pci_size_low; ddi_prop_free(pci_rp); length = sizeof (er) / sizeof (int); if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", (int *)er, length) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not create ranges property", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } /* The following properties are as defined by PCI 1275 bindings. */ if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "#address-cells", 2) != DDI_PROP_SUCCESS) return (DDI_FAILURE); if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 1) != DDI_PROP_SUCCESS) return (DDI_FAILURE); if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "#interrupt-cells", 1) != DDI_PROP_SUCCESS) return (DDI_FAILURE); imask[0] = 0x1f; imask[1] = 0x00ffffff; imask[2] = 0x00000003; length = sizeof (imask) / sizeof (int); if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupt-map-mask", (int *)imask, length) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not update imap mask property", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } return (DDI_SUCCESS); }
/* * 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); }