static size_t drm_intel_probe_agp_aperture_size(int fd) { struct pci_device *pci_dev; size_t size = 0; int ret; ret = pci_system_init(); if (ret) goto err; /* XXX handle multiple adaptors? */ pci_dev = pci_device_find_by_slot(0, 0, 2, 0); if (pci_dev == NULL) goto err; ret = pci_device_probe(pci_dev); if (ret) goto err; size = pci_dev->regions[2].size; err: pci_system_cleanup (); return size; }
int main(int argc, char *argv[]) { char *op = "devlist"; struct pci_op *p = NULL; argc = xo_parse_args(argc, argv); if (argc < 0) exit(EXIT_FAILURE); if (argc > 1) { op = argv[1]; } if (pci_system_init()) { err(1, "Couldn't initialize PCI system"); } p = ops; while (p->name != NULL) { if (strcmp(op, p->name) == 0) { p->fcn(argc - 1, &argv[1]); break; } p++; } if (p->name == NULL) usage(); xo_finish(); pci_system_cleanup(); return EXIT_SUCCESS; }
unsigned int init_pci(unsigned char bus, const unsigned char forcemem) { int ret = pci_system_init(); if (ret) die(_("Failed to init pciaccess")); struct pci_id_match match; match.vendor_id = 0x1002; match.device_id = PCI_MATCH_ANY; match.subvendor_id = PCI_MATCH_ANY; match.subdevice_id = PCI_MATCH_ANY; match.device_class = 0; match.device_class_mask = 0; match.match_data = 0; struct pci_device_iterator *iter = pci_id_match_iterator_create(&match); struct pci_device *dev = NULL; char busid[32]; while ((dev = pci_device_next(iter))) { pci_device_probe(dev); if ((dev->device_class & 0x00ffff00) != 0x00030000 && (dev->device_class & 0x00ffff00) != 0x00038000) continue; snprintf(busid, sizeof(busid), "pci:%04x:%02x:%02x.%u", dev->domain, dev->bus, dev->dev, dev->func); if (!bus || bus == dev->bus) break; } pci_iterator_destroy(iter); if (!dev) die(_("Can't find Radeon cards")); const unsigned int device_id = dev->device_id; int reg = 2; if (getfamily(device_id) >= BONAIRE) reg = 5; if (!dev->regions[reg].size) die(_("Can't get the register area size")); // printf("Found area %p, size %lu\n", area, dev->regions[reg].size); // DRM support for VRAM drm_fd = drmOpen(NULL, busid); if (drm_fd >= 0) { drmVersionPtr ver = drmGetVersion(drm_fd); if (strcmp(ver->name, "radeon") != 0 && strcmp(ver->name, "amdgpu") != 0) { close(drm_fd); drm_fd = -1; } strcpy(drm_name, ver->name); drmFreeVersion(ver); } if (drm_fd < 0 && access("/dev/ati/card0", F_OK) == 0) // fglrx path drm_fd = open("/dev/ati/card0", O_RDWR); use_ioctl = 0; if (drm_fd >= 0) { authenticate_drm(drm_fd); uint32_t rreg = 0x8010; use_ioctl = get_drm_value(drm_fd, RADEON_INFO_READ_REG, &rreg); } if (forcemem) { printf(_("Forcing the /dev/mem path.\n")); use_ioctl = 0; } if (!use_ioctl) { int mem = open("/dev/mem", O_RDONLY); if (mem < 0) die(_("Cannot access GPU registers, are you root?")); area = mmap(NULL, MMAP_SIZE, PROT_READ, MAP_PRIVATE, mem, dev->regions[reg].base_addr + 0x8000); if (area == MAP_FAILED) die(_("mmap failed")); } bits.vram = 0; if (drm_fd < 0) { printf(_("Failed to open DRM node, no VRAM support.\n")); } else { drmDropMaster(drm_fd); drmVersionPtr ver = drmGetVersion(drm_fd); /* printf("Version %u.%u.%u, name %s\n", ver->version_major, ver->version_minor, ver->version_patchlevel, ver->name);*/ if (ver->version_major < 2 || (ver->version_major == 2 && ver->version_minor < 36)) { printf(_("Kernel too old for VRAM reporting.\n")); drmFreeVersion(ver); goto out; } drmFreeVersion(ver); // No version indicator, so we need to test once // We use different codepaths for radeon and amdgpu // We store vram_size and check below if the ret value is sane if (strcmp(drm_name, "radeon") == 0) { struct drm_radeon_gem_info gem; ret = drmCommandWriteRead(drm_fd, DRM_RADEON_GEM_INFO, &gem, sizeof(gem)); vramsize = gem.vram_size; } else if (strcmp(drm_name, "amdgpu") == 0) { #ifdef ENABLE_AMDGPU struct drm_amdgpu_info_vram_gtt vram_gtt = {}; struct drm_amdgpu_info request; memset(&request, 0, sizeof(request)); request.return_pointer = (unsigned long) &vram_gtt; request.return_size = sizeof(vram_gtt); request.query = AMDGPU_INFO_VRAM_GTT; ret = drmCommandWrite(drm_fd, DRM_AMDGPU_INFO, &request, sizeof(request)); vramsize = vram_gtt.vram_size; #else printf(_("amdgpu DRM driver is used, but amdgpu VRAM size reporting is not enabled\n")); #endif } if (ret) { printf(_("Failed to get VRAM size, error %d\n"), ret); goto out; } ret = getvram(); if (ret == 0) { if (strcmp(drm_name, "amdgpu") == 0) { #ifndef ENABLE_AMDGPU printf(_("amdgpu DRM driver is used, but amdgpu VRAM usage reporting is not enabled\n")); #endif } printf(_("Failed to get VRAM usage, kernel likely too old\n")); goto out; } bits.vram = 1; } out: pci_system_cleanup(); return device_id; }
static int hwloc_look_pci(struct hwloc_backend *backend) { struct hwloc_topology *topology = backend->topology; struct hwloc_obj *first_obj = NULL, *last_obj = NULL; int ret; struct pci_device_iterator *iter; struct pci_device *pcidev; #ifdef HWLOC_LINUX_SYS DIR *dir; #endif if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) return 0; if (hwloc_get_next_pcidev(topology, NULL)) { hwloc_debug("%s", "PCI objects already added, ignoring pci backend.\n"); return 0; } if (!hwloc_topology_is_thissystem(topology)) { hwloc_debug("%s", "\nno PCI detection (not thissystem)\n"); return 0; } hwloc_debug("%s", "\nScanning PCI buses...\n"); /* initialize PCI scanning */ ret = pci_system_init(); if (ret) { hwloc_debug("%s", "Can not initialize libpciaccess\n"); return -1; } iter = pci_slot_match_iterator_create(NULL); /* iterate over devices */ for (pcidev = pci_device_next(iter); pcidev; pcidev = pci_device_next(iter)) { const char *vendorname, *devicename, *fullname; unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE]; struct hwloc_obj *obj; unsigned os_index; unsigned domain; unsigned device_class; unsigned short tmp16; char name[128]; unsigned offset; /* initialize the config space in case we fail to read it (missing permissions, etc). */ memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE); pci_device_probe(pcidev); pci_device_cfg_read(pcidev, config_space_cache, 0, CONFIG_SPACE_CACHESIZE, NULL); /* try to read the domain */ domain = pcidev->domain; /* try to read the device_class */ device_class = pcidev->device_class >> 8; /* fixup SR-IOV buggy VF device/vendor IDs */ if (0xffff == pcidev->vendor_id && 0xffff == pcidev->device_id) { /* SR-IOV puts ffff:ffff in Virtual Function config space. * The actual VF device ID is stored at a special (dynamic) location in the Physical Function config space. * VF and PF have the same vendor ID. * * libpciaccess just returns ffff:ffff, needs to be fixed. * linuxpci is OK because sysfs files are already fixed the kernel. * (pciutils is OK when it uses those Linux sysfs files.) * * Reading these files is an easy way to work around the libpciaccess issue on Linux, * but we have no way to know if this is caused by SR-IOV or not. * * TODO: * If PF has CAP_ID_PCIX or CAP_ID_EXP (offset>0), * look for extended capability PCI_EXT_CAP_ID_SRIOV (need extended config space (more than 256 bytes)), * then read the VF device ID after it (PCI_IOV_DID bytes later). * Needs access to extended config space (needs root on Linux). * TODO: * Add string info attributes in VF and PF objects? */ #ifdef HWLOC_LINUX_SYS /* Workaround for Linux (the kernel returns the VF device/vendor IDs). */ char path[64]; char value[16]; FILE *file; size_t read; snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/vendor", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { read = fread(value, 1, sizeof(value), file); fclose(file); if (read) /* fixup the pciaccess struct so that pci_device_get_vendor_name() is correct later. */ pcidev->vendor_id = strtoul(value, NULL, 16); } snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/device", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { read = fread(value, 1, sizeof(value), file); fclose(file); if (read) /* fixup the pciaccess struct so that pci_device_get_device_name() is correct later. */ pcidev->device_id = strtoul(value, NULL, 16); } #endif } /* might be useful for debugging (note that domain might be truncated) */ os_index = (domain << 20) + (pcidev->bus << 12) + (pcidev->dev << 4) + pcidev->func; obj = hwloc_alloc_setup_object(HWLOC_OBJ_PCI_DEVICE, os_index); obj->attr->pcidev.domain = domain; obj->attr->pcidev.bus = pcidev->bus; obj->attr->pcidev.dev = pcidev->dev; obj->attr->pcidev.func = pcidev->func; obj->attr->pcidev.vendor_id = pcidev->vendor_id; obj->attr->pcidev.device_id = pcidev->device_id; obj->attr->pcidev.class_id = device_class; obj->attr->pcidev.revision = config_space_cache[PCI_REVISION_ID]; obj->attr->pcidev.linkspeed = 0; /* unknown */ offset = hwloc_pci_find_cap(config_space_cache, PCI_CAP_ID_EXP); if (offset > 0 && offset + 20 /* size of PCI express block up to link status */ <= CONFIG_SPACE_CACHESIZE) hwloc_pci_find_linkspeed(config_space_cache, offset, &obj->attr->pcidev.linkspeed); hwloc_pci_prepare_bridge(obj, config_space_cache); if (obj->type == HWLOC_OBJ_PCI_DEVICE) { memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_VENDOR_ID], sizeof(tmp16)); obj->attr->pcidev.subvendor_id = tmp16; memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_ID], sizeof(tmp16)); obj->attr->pcidev.subdevice_id = tmp16; } else { /* TODO: * bridge must lookup PCI_CAP_ID_SSVID and then look at offset+PCI_SSVID_VENDOR/DEVICE_ID * cardbus must look at PCI_CB_SUBSYSTEM_VENDOR_ID and PCI_CB_SUBSYSTEM_ID */ } /* get the vendor name */ vendorname = pci_device_get_vendor_name(pcidev); if (vendorname && *vendorname) hwloc_obj_add_info(obj, "PCIVendor", vendorname); /* get the device name */ devicename = pci_device_get_device_name(pcidev); if (devicename && *devicename) hwloc_obj_add_info(obj, "PCIDevice", devicename); /* generate or get the fullname */ snprintf(name, sizeof(name), "%s%s%s", vendorname ? vendorname : "", vendorname && devicename ? " " : "", devicename ? devicename : ""); fullname = name; if (*name) obj->name = strdup(name); hwloc_debug(" %04x:%02x:%02x.%01x %04x %04x:%04x %s\n", domain, pcidev->bus, pcidev->dev, pcidev->func, device_class, pcidev->vendor_id, pcidev->device_id, fullname && *fullname ? fullname : "??"); /* queue the object for now */ if (first_obj) last_obj->next_sibling = obj; else first_obj = obj; last_obj = obj; } /* finalize device scanning */ pci_iterator_destroy(iter); pci_system_cleanup(); #ifdef HWLOC_LINUX_SYS dir = opendir("/sys/bus/pci/slots/"); if (dir) { struct dirent *dirent; while ((dirent = readdir(dir)) != NULL) { char path[64]; FILE *file; if (dirent->d_name[0] == '.') continue; snprintf(path, sizeof(path), "/sys/bus/pci/slots/%s/address", dirent->d_name); file = fopen(path, "r"); if (file) { unsigned domain, bus, dev; if (fscanf(file, "%x:%x:%x", &domain, &bus, &dev) == 3) { hwloc_obj_t obj = first_obj; while (obj) { if (obj->attr->pcidev.domain == domain && obj->attr->pcidev.bus == bus && obj->attr->pcidev.dev == dev && obj->attr->pcidev.func == 0) { hwloc_obj_add_info(obj, "PCISlot", dirent->d_name); break; } obj = obj->next_sibling; } } fclose(file); } } closedir(dir); } #endif return hwloc_insert_pci_device_list(backend, first_obj); }
int main(int argc, char **argv) { struct pci_device *dev; void *bios; int err, fd; if (argc != 2) usage(); err = pci_system_init(); if (err != 0) { fprintf(stderr, "Couldn't initialize PCI system: %s\n", strerror(err)); exit(1); } /* Grab the graphics card */ dev = pci_device_find_by_slot(0, 0, 2, 0); if (dev == NULL) errx(1, "Couldn't find graphics card"); err = pci_device_probe(dev); if (err != 0) { fprintf(stderr, "Couldn't probe graphics card: %s\n", strerror(err)); exit(1); } if (dev->vendor_id != 0x8086) errx(1, "Graphics card is non-intel"); /* Some versions of libpciaccess correct this automatically, but some * don't. */ if (dev->rom_size == 0) dev->rom_size = 64 * 1024; bios = malloc(dev->rom_size); if (bios == NULL) errx(1, "Couldn't allocate memory for BIOS data\n"); err = pci_device_read_rom(dev, bios); if (err != 0) { fprintf(stderr, "Couldn't read graphics card ROM: %s\n", strerror(err)); exit(1); } fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC, DEFFILEMODE); if (fd < 0) { fprintf(stderr, "Couldn't open output: %s\n", strerror(errno)); exit(1); } if (write(fd, bios, dev->rom_size) < dev->rom_size) { fprintf(stderr, "Couldn't write BIOS data: %s\n", strerror(errno)); exit(1); } close(fd); pci_system_cleanup(); return 0; }
int stop_pci_support(void){ pci_system_cleanup(); return 0; }
int nva_init() { int ret; ret = pci_system_init(); if (ret) return -1; struct pci_id_match nv_match = {0x10de, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0x30000, 0xffff0000}; struct pci_device_iterator* it = pci_id_match_iterator_create(&nv_match); if (!it) { pci_system_cleanup(); return -1; } struct pci_device *dev; while (dev = pci_device_next(it)) { struct nva_card c = { 0 }; ret = pci_device_probe(dev); if (ret) { fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func); continue; } c.pci = dev; ADDARRAY(nva_cards, c); } pci_iterator_destroy(it); struct pci_id_match nv_sgs_match = {0x12d2, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, 0x30000, 0xffff0000}; it = pci_id_match_iterator_create(&nv_sgs_match); if (!it) { pci_system_cleanup(); return -1; } while (dev = pci_device_next(it)) { struct nva_card c = { 0 }; ret = pci_device_probe(dev); if (ret) { fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func); continue; } c.pci = dev; ADDARRAY(nva_cards, c); } pci_iterator_destroy(it); int i; for (i = 0; i < nva_cardsnum; i++) { dev = nva_cards[i].pci; ret = pci_device_map_range(dev, dev->regions[0].base_addr, dev->regions[0].size, PCI_DEV_MAP_FLAG_WRITABLE, &nva_cards[i].bar0); if (ret) return -1; nva_cards[i].boot0 = nva_rd32(i, 0); nva_cards[i].chipset = nva_cards[i].boot0 >> 20 & 0xff; if (nva_cards[i].chipset < 0x10) { if (nva_cards[i].boot0 & 0xf000) { if (nva_cards[i].boot0 & 0xf00000) nva_cards[i].chipset = 5; else nva_cards[i].chipset = 4; } else { nva_cards[i].chipset = nva_cards[i].boot0 >> 16 & 0xf; if ((nva_cards[i].boot0 & 0xff) >= 0x20) nva_cards[i].is_nv03p = 1; } } if (nva_cards[i].chipset < 0x04) nva_cards[i].card_type = nva_cards[i].chipset; else if (nva_cards[i].chipset < 0x10) nva_cards[i].card_type = 0x04; else if (nva_cards[i].chipset < 0x20) nva_cards[i].card_type = 0x10; else if (nva_cards[i].chipset < 0x30) nva_cards[i].card_type = 0x20; else if (nva_cards[i].chipset < 0x40) nva_cards[i].card_type = 0x30; else if (nva_cards[i].chipset < 0x50 || nva_cards[i].chipset & 0xf0 == 0x60) nva_cards[i].card_type = 0x40; else if (nva_cards[i].chipset < 0xc0) nva_cards[i].card_type = 0x50; else nva_cards[i].card_type = 0xc0; } return 0; }
static int hwloc_look_pci(struct hwloc_backend *backend) { struct hwloc_topology *topology = backend->topology; struct hwloc_obj *first_obj = NULL, *last_obj = NULL; #ifdef HWLOC_HAVE_LIBPCIACCESS int ret; struct pci_device_iterator *iter; struct pci_device *pcidev; #else /* HWLOC_HAVE_PCIUTILS */ struct pci_access *pciaccess; struct pci_dev *pcidev; #endif if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO))) return 0; if (hwloc_get_next_pcidev(topology, NULL)) { hwloc_debug("%s", "PCI objects already added, ignoring pci backend.\n"); return 0; } if (!hwloc_topology_is_thissystem(topology)) { hwloc_debug("%s", "\nno PCI detection (not thissystem)\n"); return 0; } hwloc_debug("%s", "\nScanning PCI buses...\n"); /* initialize PCI scanning */ #ifdef HWLOC_HAVE_LIBPCIACCESS ret = pci_system_init(); if (ret) { hwloc_debug("%s", "Can not initialize libpciaccess\n"); return -1; } iter = pci_slot_match_iterator_create(NULL); #else /* HWLOC_HAVE_PCIUTILS */ pciaccess = pci_alloc(); pciaccess->error = hwloc_pci_error; pciaccess->warning = hwloc_pci_warning; if (setjmp(err_buf)) { pci_cleanup(pciaccess); return -1; } pci_init(pciaccess); pci_scan_bus(pciaccess); #endif /* iterate over devices */ #ifdef HWLOC_HAVE_LIBPCIACCESS for (pcidev = pci_device_next(iter); pcidev; pcidev = pci_device_next(iter)) #else /* HWLOC_HAVE_PCIUTILS */ for (pcidev = pciaccess->devices; pcidev; pcidev = pcidev->next) #endif { const char *vendorname, *devicename, *fullname; unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE]; struct hwloc_obj *obj; unsigned os_index; unsigned domain; unsigned device_class; unsigned short tmp16; char name[128]; unsigned offset; #ifdef HWLOC_HAVE_PCI_FIND_CAP struct pci_cap *cap; #endif /* initialize the config space in case we fail to read it (missing permissions, etc). */ memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE); #ifdef HWLOC_HAVE_LIBPCIACCESS pci_device_probe(pcidev); pci_device_cfg_read(pcidev, config_space_cache, 0, CONFIG_SPACE_CACHESIZE, NULL); #else /* HWLOC_HAVE_PCIUTILS */ pci_read_block(pcidev, 0, config_space_cache, CONFIG_SPACE_CACHESIZE); /* doesn't even tell how much it actually reads */ #endif /* try to read the domain */ #if (defined HWLOC_HAVE_LIBPCIACCESS) || (defined HWLOC_HAVE_PCIDEV_DOMAIN) domain = pcidev->domain; #else domain = 0; /* default domain number */ #endif /* try to read the device_class */ #ifdef HWLOC_HAVE_LIBPCIACCESS device_class = pcidev->device_class >> 8; #else /* HWLOC_HAVE_PCIUTILS */ #ifdef HWLOC_HAVE_PCIDEV_DEVICE_CLASS device_class = pcidev->device_class; #else device_class = config_space_cache[PCI_CLASS_DEVICE] | (config_space_cache[PCI_CLASS_DEVICE+1] << 8); #endif #endif /* might be useful for debugging (note that domain might be truncated) */ os_index = (domain << 20) + (pcidev->bus << 12) + (pcidev->dev << 4) + pcidev->func; obj = hwloc_alloc_setup_object(HWLOC_OBJ_PCI_DEVICE, os_index); obj->attr->pcidev.domain = domain; obj->attr->pcidev.bus = pcidev->bus; obj->attr->pcidev.dev = pcidev->dev; obj->attr->pcidev.func = pcidev->func; obj->attr->pcidev.vendor_id = pcidev->vendor_id; obj->attr->pcidev.device_id = pcidev->device_id; obj->attr->pcidev.class_id = device_class; obj->attr->pcidev.revision = config_space_cache[PCI_REVISION_ID]; obj->attr->pcidev.linkspeed = 0; /* unknown */ #ifdef HWLOC_HAVE_PCI_FIND_CAP cap = pci_find_cap(pcidev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL); offset = cap ? cap->addr : 0; #else offset = hwloc_pci_find_cap(config_space_cache, PCI_CAP_ID_EXP); #endif /* HWLOC_HAVE_PCI_FIND_CAP */ if (0xffff == pcidev->vendor_id && 0xffff == pcidev->device_id) { /* SR-IOV puts ffff:ffff in Virtual Function config space. * The actual VF device ID is stored at a special (dynamic) location in the Physical Function config space. * VF and PF have the same vendor ID. * * libpciaccess just returns ffff:ffff, needs to be fixed. * linuxpci is OK because sysfs files are already fixed the kernel. * pciutils is OK when it uses those Linux sysfs files. * * Reading these files is an easy way to work around the libpciaccess issue on Linux, * but we have no way to know if this is caused by SR-IOV or not. * * TODO: * If PF has CAP_ID_PCIX or CAP_ID_EXP (offset>0), * look for extended capability PCI_EXT_CAP_ID_SRIOV (need extended config space (more than 256 bytes)), * then read the VF device ID after it (PCI_IOV_DID bytes later). * Needs access to extended config space (needs root on Linux). * TODO: * Add string info attributes in VF and PF objects? */ #ifdef HWLOC_LINUX_SYS /* Workaround for Linux (the kernel returns the VF device/vendor IDs). */ char path[64]; char value[16]; FILE *file; snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/vendor", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { fread(value, sizeof(value), 1, file); fclose(file); obj->attr->pcidev.vendor_id = strtoul(value, NULL, 16); } snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/device", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { fread(value, sizeof(value), 1, file); fclose(file); obj->attr->pcidev.device_id = strtoul(value, NULL, 16); } #endif } if (offset > 0 && offset + 20 /* size of PCI express block up to link status */ <= CONFIG_SPACE_CACHESIZE) hwloc_pci_find_linkspeed(config_space_cache, offset, &obj->attr->pcidev.linkspeed); hwloc_pci_prepare_bridge(obj, config_space_cache); if (obj->type == HWLOC_OBJ_PCI_DEVICE) { memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_VENDOR_ID], sizeof(tmp16)); obj->attr->pcidev.subvendor_id = tmp16; memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_ID], sizeof(tmp16)); obj->attr->pcidev.subdevice_id = tmp16; } else { /* TODO: * bridge must lookup PCI_CAP_ID_SSVID and then look at offset+PCI_SSVID_VENDOR/DEVICE_ID * cardbus must look at PCI_CB_SUBSYSTEM_VENDOR_ID and PCI_CB_SUBSYSTEM_ID */ } /* starting from pciutils 2.2, pci_lookup_name() takes a variable number * of arguments, and supports the PCI_LOOKUP_NO_NUMBERS flag. */ /* get the vendor name */ #ifdef HWLOC_HAVE_LIBPCIACCESS vendorname = pci_device_get_vendor_name(pcidev); #else /* HWLOC_HAVE_PCIUTILS */ vendorname = pci_lookup_name(pciaccess, name, sizeof(name), #if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS PCI_LOOKUP_VENDOR|PCI_LOOKUP_NO_NUMBERS, pcidev->vendor_id #else PCI_LOOKUP_VENDOR, pcidev->vendor_id, 0, 0, 0 #endif ); #endif /* HWLOC_HAVE_PCIUTILS */ if (vendorname && *vendorname) hwloc_obj_add_info(obj, "PCIVendor", vendorname); /* get the device name */ #ifdef HWLOC_HAVE_LIBPCIACCESS devicename = pci_device_get_device_name(pcidev); #else /* HWLOC_HAVE_PCIUTILS */ devicename = pci_lookup_name(pciaccess, name, sizeof(name), #if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS, pcidev->vendor_id, pcidev->device_id #else PCI_LOOKUP_DEVICE, pcidev->vendor_id, pcidev->device_id, 0, 0 #endif ); #endif /* HWLOC_HAVE_PCIUTILS */ if (devicename && *devicename) hwloc_obj_add_info(obj, "PCIDevice", devicename); /* generate or get the fullname */ #ifdef HWLOC_HAVE_LIBPCIACCESS snprintf(name, sizeof(name), "%s%s%s", vendorname ? vendorname : "", vendorname && devicename ? " " : "", devicename ? devicename : ""); fullname = name; if (*name) obj->name = strdup(name); #else /* HWLOC_HAVE_PCIUTILS */ fullname = pci_lookup_name(pciaccess, name, sizeof(name), #if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS PCI_LOOKUP_VENDOR|PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS, pcidev->vendor_id, pcidev->device_id #else PCI_LOOKUP_VENDOR|PCI_LOOKUP_DEVICE, pcidev->vendor_id, pcidev->device_id, 0, 0 #endif ); if (fullname && *fullname) obj->name = strdup(fullname); #endif /* HWLOC_HAVE_PCIUTILS */ hwloc_debug(" %04x:%02x:%02x.%01x %04x %04x:%04x %s\n", domain, pcidev->bus, pcidev->dev, pcidev->func, device_class, pcidev->vendor_id, pcidev->device_id, fullname && *fullname ? fullname : "??"); /* queue the object for now */ if (first_obj) last_obj->next_sibling = obj; else first_obj = obj; last_obj = obj; } /* finalize device scanning */ #ifdef HWLOC_HAVE_LIBPCIACCESS pci_iterator_destroy(iter); pci_system_cleanup(); #else /* HWLOC_HAVE_PCIUTILS */ pci_cleanup(pciaccess); #endif return hwloc_insert_pci_device_list(backend, first_obj); }
static int hwloc_look_pci(struct hwloc_backend *backend) { struct hwloc_topology *topology = backend->topology; enum hwloc_type_filter_e pfilter, bfilter; struct hwloc_obj *tree = NULL, *tmp; int ret; struct pci_device_iterator *iter; struct pci_device *pcidev; hwloc_topology_get_type_filter(topology, HWLOC_OBJ_PCI_DEVICE, &pfilter); hwloc_topology_get_type_filter(topology, HWLOC_OBJ_BRIDGE, &bfilter); if (bfilter == HWLOC_TYPE_FILTER_KEEP_NONE && pfilter == HWLOC_TYPE_FILTER_KEEP_NONE) return 0; /* don't do anything if another backend attached PCI already * (they are attached to root until later in the core discovery) */ tmp = hwloc_get_root_obj(topology)->io_first_child; while (tmp) { if (tmp->type == HWLOC_OBJ_PCI_DEVICE || (tmp->type == HWLOC_OBJ_BRIDGE && tmp->attr->bridge.downstream_type == HWLOC_OBJ_BRIDGE_PCI)) { hwloc_debug("%s", "PCI objects already added, ignoring linuxpci backend.\n"); return 0; } tmp = tmp->next_sibling; } hwloc_debug("%s", "\nScanning PCI buses...\n"); /* initialize PCI scanning */ ret = pci_system_init(); if (ret) { hwloc_debug("%s", "Can not initialize libpciaccess\n"); return -1; } iter = pci_slot_match_iterator_create(NULL); /* iterate over devices */ for (pcidev = pci_device_next(iter); pcidev; pcidev = pci_device_next(iter)) { const char *vendorname, *devicename; unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE]; hwloc_obj_type_t type; struct hwloc_obj *obj; unsigned domain; unsigned device_class; unsigned short tmp16; unsigned offset; /* initialize the config space in case we fail to read it (missing permissions, etc). */ memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE); pci_device_probe(pcidev); pci_device_cfg_read(pcidev, config_space_cache, 0, CONFIG_SPACE_CACHESIZE, NULL); /* try to read the domain */ domain = pcidev->domain; /* try to read the device_class */ device_class = pcidev->device_class >> 8; /* bridge or pci dev? */ type = hwloc_pcidisc_check_bridge_type(device_class, config_space_cache); /* filtered? */ if (type == HWLOC_OBJ_PCI_DEVICE) { enum hwloc_type_filter_e filter; hwloc_topology_get_type_filter(topology, HWLOC_OBJ_PCI_DEVICE, &filter); if (filter == HWLOC_TYPE_FILTER_KEEP_NONE) continue; if (filter == HWLOC_TYPE_FILTER_KEEP_IMPORTANT && !hwloc_filter_check_pcidev_subtype_important(device_class)) continue; } else if (type == HWLOC_OBJ_BRIDGE) { enum hwloc_type_filter_e filter; hwloc_topology_get_type_filter(topology, HWLOC_OBJ_BRIDGE, &filter); if (filter == HWLOC_TYPE_FILTER_KEEP_NONE) continue; /* HWLOC_TYPE_FILTER_KEEP_IMPORTANT filtered later in the core */ } /* fixup SR-IOV buggy VF device/vendor IDs */ if (0xffff == pcidev->vendor_id && 0xffff == pcidev->device_id) { /* SR-IOV puts ffff:ffff in Virtual Function config space. * The actual VF device ID is stored at a special (dynamic) location in the Physical Function config space. * VF and PF have the same vendor ID. * * libpciaccess just returns ffff:ffff, needs to be fixed. * linuxpci is OK because sysfs files are already fixed in the kernel. * (pciutils is OK when it uses those Linux sysfs files.) * * Reading these files is an easy way to work around the libpciaccess issue on Linux, * but we have no way to know if this is caused by SR-IOV or not. * * TODO: * If PF has CAP_ID_PCIX or CAP_ID_EXP (offset>0), * look for extended capability PCI_EXT_CAP_ID_SRIOV (need extended config space (more than 256 bytes)), * then read the VF device ID after it (PCI_IOV_DID bytes later). * Needs access to extended config space (needs root on Linux). * TODO: * Add string info attributes in VF and PF objects? */ #ifdef HWLOC_LINUX_SYS /* Workaround for Linux (the kernel returns the VF device/vendor IDs). */ char path[64]; char value[16]; FILE *file; size_t read; snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/vendor", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { read = fread(value, 1, sizeof(value), file); fclose(file); if (read) /* fixup the pciaccess struct so that pci_device_get_vendor_name() is correct later. */ pcidev->vendor_id = strtoul(value, NULL, 16); } snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/device", domain, pcidev->bus, pcidev->dev, pcidev->func); file = fopen(path, "r"); if (file) { read = fread(value, 1, sizeof(value), file); fclose(file); if (read) /* fixup the pciaccess struct so that pci_device_get_device_name() is correct later. */ pcidev->device_id = strtoul(value, NULL, 16); } #endif } obj = hwloc_alloc_setup_object(topology, type, HWLOC_UNKNOWN_INDEX); obj->attr->pcidev.domain = domain; obj->attr->pcidev.bus = pcidev->bus; obj->attr->pcidev.dev = pcidev->dev; obj->attr->pcidev.func = pcidev->func; obj->attr->pcidev.vendor_id = pcidev->vendor_id; obj->attr->pcidev.device_id = pcidev->device_id; obj->attr->pcidev.class_id = device_class; obj->attr->pcidev.revision = config_space_cache[PCI_REVISION_ID]; obj->attr->pcidev.linkspeed = 0; /* unknown */ offset = hwloc_pcidisc_find_cap(config_space_cache, PCI_CAP_ID_EXP); if (offset > 0 && offset + 20 /* size of PCI express block up to link status */ <= CONFIG_SPACE_CACHESIZE) hwloc_pcidisc_find_linkspeed(config_space_cache, offset, &obj->attr->pcidev.linkspeed); if (type == HWLOC_OBJ_BRIDGE) { if (hwloc_pcidisc_setup_bridge_attr(obj, config_space_cache) < 0) continue; } if (obj->type == HWLOC_OBJ_PCI_DEVICE) { memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_VENDOR_ID], sizeof(tmp16)); obj->attr->pcidev.subvendor_id = tmp16; memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_ID], sizeof(tmp16)); obj->attr->pcidev.subdevice_id = tmp16; } else { /* TODO: * bridge must lookup PCI_CAP_ID_SSVID and then look at offset+PCI_SSVID_VENDOR/DEVICE_ID * cardbus must look at PCI_CB_SUBSYSTEM_VENDOR_ID and PCI_CB_SUBSYSTEM_ID */ } /* get the vendor name */ vendorname = pci_device_get_vendor_name(pcidev); if (vendorname && *vendorname) hwloc_obj_add_info(obj, "PCIVendor", vendorname); /* get the device name */ devicename = pci_device_get_device_name(pcidev); if (devicename && *devicename) hwloc_obj_add_info(obj, "PCIDevice", devicename); hwloc_debug(" %04x:%02x:%02x.%01x %04x %04x:%04x %s %s\n", domain, pcidev->bus, pcidev->dev, pcidev->func, device_class, pcidev->vendor_id, pcidev->device_id, vendorname && *vendorname ? vendorname : "??", devicename && *devicename ? devicename : "??"); hwloc_pcidisc_tree_insert_by_busid(&tree, obj); } /* finalize device scanning */ pci_iterator_destroy(iter); pci_system_cleanup(); hwloc_pcidisc_tree_attach(topology, tree); return 0; }
int nva_init() { int ret; ret = pci_system_init(); if (ret) return -1; int i; for (i = 0; i < ARRAY_SIZE(nv_match); i++) { struct pci_device_iterator* it = pci_id_match_iterator_create(&nv_match[i]); if (!it) { pci_system_cleanup(); return -1; } struct pci_device *dev; while ((dev = pci_device_next(it))) { struct nva_card c = { 0 }; ret = pci_device_probe(dev); if (ret) { fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func); continue; } c.pci = dev; ADDARRAY(nva_cards, c); } pci_iterator_destroy(it); } for (i = 0; i < nva_cardsnum; i++) { struct pci_device *dev; dev = nva_cards[i].pci; ret = pci_device_map_range(dev, dev->regions[0].base_addr, dev->regions[0].size, PCI_DEV_MAP_FLAG_WRITABLE, &nva_cards[i].bar0); if (ret) { fprintf (stderr, "WARN: Can't probe %04x:%02x:%02x.%x\n", dev->domain, dev->bus, dev->dev, dev->func); int j; for (j = i + 1; j < nva_cardsnum; j++) { nva_cards[j-1] = nva_cards[j]; } nva_cardsnum--; i--; continue; } nva_cards[i].bar0len = dev->regions[0].size; if (dev->regions[1].size) { nva_cards[i].hasbar1 = 1; nva_cards[i].bar1len = dev->regions[1].size; ret = pci_device_map_range(dev, dev->regions[1].base_addr, dev->regions[1].size, PCI_DEV_MAP_FLAG_WRITABLE, &nva_cards[i].bar1); if (ret) { nva_cards[i].bar1 = 0; } } if (dev->regions[2].size) { nva_cards[i].hasbar2 = 1; nva_cards[i].bar2len = dev->regions[2].size; ret = pci_device_map_range(dev, dev->regions[2].base_addr, dev->regions[2].size, PCI_DEV_MAP_FLAG_WRITABLE, &nva_cards[i].bar2); if (ret) { nva_cards[i].bar2 = 0; } } else if (dev->regions[3].size) { nva_cards[i].hasbar2 = 1; nva_cards[i].bar2len = dev->regions[3].size; ret = pci_device_map_range(dev, dev->regions[3].base_addr, dev->regions[3].size, PCI_DEV_MAP_FLAG_WRITABLE, &nva_cards[i].bar2); if (ret) { nva_cards[i].bar2 = 0; } } uint32_t pmc_id = nva_rd32(i, 0); parse_pmc_id(pmc_id, &nva_cards[i].chipset); } return (nva_cardsnum == 0); }
int main( int argc, char ** argv ) { struct pci_device * dev; uint8_t val; int newval; int mode; int argp; setuid(0); if( pci_system_init() ) { fprintf( stderr, "ERROR: PCI bus init failed. No root?\n" ); exit( 1 ); } dev = pci_device_find_by_slot( 0, 0, 2, 1 ); if( !isNc10( dev ) ) { fprintf( stderr, "ERROR: This device does not look not like a Samsung NC10.\n" ); exit( 1 ); } mode = 0; argp = 1; switch( argc ) { case 1: mode = 0; break; case 2: if( !strcmp( "-get", argv[argp] ) ) { mode=0; argp++; } else { usage(); exit( 1 ); } break; case 3: if( !strcmp( "-set", argv[argp] ) || !strcmp( "=", argv[argp] ) ) { mode = 1; argp++; } else if( !strcmp( "-inc", argv[argp] ) || !strcmp( "+", argv[argp] ) ) { mode = 2; argp++; } else if( !strcmp( "-dec", argv[argp] ) || !strcmp( "-", argv[argp] ) ) { mode = 3; argp++; } else { usage(); exit( 1 ); } break; default: usage(); exit( 1 ); } switch( mode ) { case 0: /* get */ val = getBrightness( dev ); printf("%d\n", val); break; case 1: /* set */ val = (uint8_t) atoi( argv[argp] ); setBrightness( dev, val ); break; case 2: /* inc */ val = getBrightness( dev ); newval = val + atoi( argv[argp] ); if( newval > 255 ) newval = 255; setBrightness( dev, (uint8_t) newval ); break; case 3: /* dec */ val = getBrightness( dev ); newval = val - atoi( argv[argp] ); if( newval < 0 ) newval = 0; setBrightness( dev, (uint8_t) newval ); break; } pci_system_cleanup(); return 0; }