/** * Map a memory region for a device using /dev/xsvc. * * \param dev Device whose memory region is to be mapped. * \param map Parameters of the mapping that is to be created. * * \return * Zero on success or an \c errno value on failure. */ static int pci_device_solx_devfs_map_range(struct pci_device *dev, struct pci_device_mapping *map) { const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? (PROT_READ | PROT_WRITE) : PROT_READ; int err = 0; #ifdef __sparc char map_dev[128]; int map_fd; if (MAPPING_DEV_PATH(dev)) snprintf(map_dev, sizeof (map_dev), "%s%s", "/devices", MAPPING_DEV_PATH(dev)); else strcpy (map_dev, "/dev/fb0"); if ((map_fd = open(map_dev, O_RDWR | O_CLOEXEC)) < 0) { err = errno; (void) fprintf(stderr, "can not open %s: %s\n", map_dev, strerror(errno)); return err; } map->memory = mmap(NULL, map->size, prot, MAP_SHARED, map_fd, map->base); #else /* * Still used xsvc to do the user space mapping */ if (xsvc_fd < 0) { if ((xsvc_fd = open("/dev/xsvc", O_RDWR | O_CLOEXEC)) < 0) { err = errno; (void) fprintf(stderr, "can not open /dev/xsvc: %s\n", strerror(errno)); return err; } } map->memory = mmap(NULL, map->size, prot, MAP_SHARED, xsvc_fd, map->base); #endif if (map->memory == MAP_FAILED) { err = errno; (void) fprintf(stderr, "map rom region =%llx failed: %s\n", map->base, strerror(errno)); } #ifdef __sparc close (map_fd); #endif return err; }
/* * Release all the resources * Solaris version */ static void pci_system_solx_devfs_destroy( void ) { /* * The memory allocated for pci_sys & devices in create routines * will be freed in pci_system_cleanup. * Need to free system-specific allocations here. */ nexus_t *nexus, *next; for (nexus = nexus_list ; nexus != NULL ; nexus = next) { next = nexus->next; close(nexus->fd); free(nexus->path); free(nexus->dev_path); #ifdef __sparc { struct pci_device *dev; int i; for (i = 0; i < nexus->num_devices; i++) { dev = nexus->devlist[i]; if (MAPPING_DEV_PATH(dev)) di_devfs_path_free((char *) MAPPING_DEV_PATH(dev)); } } free(nexus->devlist); #endif free(nexus); } nexus_list = NULL; #ifdef __sparc if (di_phdl != DI_PROM_HANDLE_NIL) (void) di_prom_fini(di_phdl); #else if (xsvc_fd >= 0) { close(xsvc_fd); xsvc_fd = -1; } #endif }
/* * Release resources per device */ static void pci_system_solx_devfs_destroy_device( struct pci_device *dev ) { if (MAPPING_DEV_PATH(dev)) di_devfs_path_free((char *) MAPPING_DEV_PATH(dev)); }
/* * 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); }