コード例 #1
0
ファイル: xf86platformBus.c プロジェクト: MrKepzie/xserver
static void
platform_find_pci_info(struct xf86_platform_device *pd, char *busid)
{
    struct pci_slot_match devmatch;
    struct pci_device *info;
    struct pci_device_iterator *iter;
    int ret;

    ret = sscanf(busid, "pci:%04x:%02x:%02x.%u",
                 &devmatch.domain, &devmatch.bus, &devmatch.dev,
                 &devmatch.func);
    if (ret != 4)
        return;

    iter = pci_slot_match_iterator_create(&devmatch);
    info = pci_device_next(iter);
    if (info) {
        pd->pdev = info;
        pci_device_probe(info);
        if (pci_device_is_boot_vga(info)) {
            primaryBus.type = BUS_PLATFORM;
            primaryBus.id.plat = pd;
        }
    }
    pci_iterator_destroy(iter);

}
コード例 #2
0
static struct pci_device*
ati_device_get_primary(void)
{
    struct pci_device *device = NULL;
    struct pci_device_iterator *device_iter;

    device_iter = pci_slot_match_iterator_create(NULL);

    while ((device = pci_device_next(device_iter)) != NULL) {
        if (xf86IsPrimaryPci(device))
            break;
    }

    pci_iterator_destroy(device_iter);

    return device;
}
コード例 #3
0
static struct pci_device *
ati_device_get_indexed(int index)
{
    struct pci_device *device = NULL;
    struct pci_device_iterator *device_iter;
    int count = 0;

    device_iter = pci_slot_match_iterator_create(NULL);

    while ((device = pci_device_next(device_iter)) != NULL) {
        if (device->vendor_id == PCI_VENDOR_ATI) {
            if (count == index)
                return device;
            count++;
        }
    }
    return NULL;
}
コード例 #4
0
static void
pci_userspace_init(void)
{
	/* FIXME: add a hook to make rump call this, once and only once */
	static int is_init = 0;
	if (is_init)
		return;
	is_init = 1;

	if (get_privileged_ports (&master_host, &master_device))
		err(1, "get_privileged_ports");

	pci_system_init ();
	struct pci_device_iterator *dev_iter;
	struct pci_device *pci_dev;
        dev_iter = pci_slot_match_iterator_create (NULL);
	int i = 0;
        while ((pci_dev = pci_device_next (dev_iter)) != NULL) {
		pci_devices[i++] = pci_dev;
	}
}
コード例 #5
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;
  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);
}
コード例 #6
0
ファイル: xf86pciBus.c プロジェクト: AmesianX/xorg-server
void
xf86PciProbe(void)
{
    int i = 0, k;
    int num = 0;
    struct pci_device *info;
    struct pci_device_iterator *iter;
    struct pci_device **xf86PciVideoInfo = NULL;

    if (!xf86scanpci()) {
        xf86PciVideoInfo = NULL;
        return;
    }

    iter = pci_slot_match_iterator_create(&xf86IsolateDevice);
    while ((info = pci_device_next(iter)) != NULL) {
        if (PCIINFOCLASSES(info->device_class)) {
            num++;
            xf86PciVideoInfo = xnfreallocarray(xf86PciVideoInfo,
                                               num + 1,
                                               sizeof(struct pci_device *));
            xf86PciVideoInfo[num] = NULL;
            xf86PciVideoInfo[num - 1] = info;

            pci_device_probe(info);
            if (primaryBus.type == BUS_NONE && pci_device_is_boot_vga(info)) {
                primaryBus.type = BUS_PCI;
                primaryBus.id.pci = info;
            }
            info->user_data = 0;
        }
    }
    free(iter);

    /* If we haven't found a primary device try a different heuristic */
    if (primaryBus.type == BUS_NONE && num) {
        for (i = 0; i < num; i++) {
            uint16_t command;

            info = xf86PciVideoInfo[i];
            pci_device_cfg_read_u16(info, &command, 4);

            if ((command & PCI_CMD_MEM_ENABLE)
                && ((num == 1) || IS_VGA(info->device_class))) {
                if (primaryBus.type == BUS_NONE) {
                    primaryBus.type = BUS_PCI;
                    primaryBus.id.pci = info;
                }
                else {
                    xf86Msg(X_NOTICE,
                            "More than one possible primary device found\n");
                    primaryBus.type ^= (BusType) (-1);
                }
            }
        }
    }

    /* Print a summary of the video devices found */
    for (k = 0; k < num; k++) {
        const char *prim = " ";
        Bool memdone = FALSE, iodone = FALSE;

        info = xf86PciVideoInfo[k];

        if (!PCIALWAYSPRINTCLASSES(info->device_class))
            continue;

        if (xf86IsPrimaryPci(info))
            prim = "*";

        xf86Msg(X_PROBED, "PCI:%s(%u:%u:%u:%u) %04x:%04x:%04x:%04x ", prim,
                info->domain, info->bus, info->dev, info->func,
                info->vendor_id, info->device_id,
                info->subvendor_id, info->subdevice_id);

        xf86ErrorF("rev %d", info->revision);

        for (i = 0; i < 6; i++) {
            struct pci_mem_region *r = &info->regions[i];

            if (r->size && !r->is_IO) {
                if (!memdone) {
                    xf86ErrorF(", Mem @ ");
                    memdone = TRUE;
                }
                else
                    xf86ErrorF(", ");
                xf86ErrorF("0x%08lx/%ld", (long) r->base_addr, (long) r->size);
            }
        }

        for (i = 0; i < 6; i++) {
            struct pci_mem_region *r = &info->regions[i];

            if (r->size && r->is_IO) {
                if (!iodone) {
                    xf86ErrorF(", I/O @ ");
                    iodone = TRUE;
                }
                else
                    xf86ErrorF(", ");
                xf86ErrorF("0x%08lx/%ld", (long) r->base_addr, (long) r->size);
            }
        }

        if (info->rom_size) {
            xf86ErrorF(", BIOS @ 0x\?\?\?\?\?\?\?\?/%ld",
                       (long) info->rom_size);
        }

        xf86ErrorF("\n");
    }
    free(xf86PciVideoInfo);
}
コード例 #7
0
/* This function is used to provide a workaround for binary drivers that
 * don't export their PCI ID's properly. If distros don't end up using this
 * feature it can and should be removed because the symbol-based resolution
 * scheme should be the primary one */
static void
matchDriverFromFiles (char** matches, uint16_t match_vendor, uint16_t match_chip)
{
    DIR *idsdir;
    FILE *fp;
    struct dirent *direntry;
    char *line = NULL;
    size_t len;
    ssize_t read;
    char path_name[256], vendor_str[5], chip_str[5];
    uint16_t vendor, chip;
    int i, j;

    idsdir = opendir(PCI_TXT_IDS_PATH);
    if (!idsdir)
        return;

    xf86Msg(X_INFO, "Scanning %s directory for additional PCI ID's supported by the drivers\n", PCI_TXT_IDS_PATH);
    direntry = readdir(idsdir);
    /* Read the directory */
    while (direntry) {
        if (direntry->d_name[0] == '.') {
            direntry = readdir(idsdir);
            continue;
        }
        len = strlen(direntry->d_name);
        /* A tiny bit of sanity checking. We should probably do better */
        if (strncmp(&(direntry->d_name[len-4]), ".ids", 4) == 0) {
            /* We need the full path name to open the file */
            strncpy(path_name, PCI_TXT_IDS_PATH, 256);
            strncat(path_name, "/", 1);
            strncat(path_name, direntry->d_name, (256 - strlen(path_name) - 1));
            fp = fopen(path_name, "r");
            if (fp == NULL) {
                xf86Msg(X_ERROR, "Could not open %s for reading. Exiting.\n", path_name);
                goto end;
            }
            /* Read the file */
#ifdef __GLIBC__
            while ((read = getline(&line, &len, fp)) != -1) {
#else
            while ((line = fgetln(fp, &len)) != (char *)NULL) {
#endif /* __GLIBC __ */
                xchomp(line);
                if (isdigit(line[0])) {
                    strncpy(vendor_str, line, 4);
                    vendor_str[4] = '\0';
                    vendor = (int)strtol(vendor_str, NULL, 16);
                    if ((strlen(&line[4])) == 0) {
                        chip_str[0] = '\0';
                        chip = -1;
                    } else {
                        /* Handle trailing whitespace */
                        if (isspace(line[4])) {
                            chip_str[0] = '\0';
                            chip = -1;
                        } else {
                            /* Ok, it's a real ID */
                            strncpy(chip_str, &line[4], 4);
                            chip_str[4] = '\0';
                            chip = (int)strtol(chip_str, NULL, 16);
                        }
                    }
                    if (vendor == match_vendor && chip == match_chip ) {
                        i = 0;
                        while (matches[i]) {
                            i++;
                        }
                        matches[i] = (char*)xalloc(sizeof(char) * strlen(direntry->d_name) -  3);
                        if (!matches[i]) {
                            xf86Msg(X_ERROR, "Could not allocate space for the module name. Exiting.\n");
                            goto end;
                        }
                        /* hack off the .ids suffix. This should guard
                         * against other problems, but it will end up
                         * taking off anything after the first '.' */
                        for (j = 0; j < (strlen(direntry->d_name) - 3) ; j++) {
                            if (direntry->d_name[j] == '.') {
                                matches[i][j] = '\0';
                                break;
                            } else {
                                matches[i][j] = direntry->d_name[j];
                            }
                        }
                        xf86Msg(X_INFO, "Matched %s from file name %s\n", matches[i], direntry->d_name);
                    }
                } else {
                    /* TODO Handle driver overrides here */
                }
            }
            fclose(fp);
        }
        direntry = readdir(idsdir);
    }
 end:
    xfree(line);
    closedir(idsdir);
}
#endif /* __linux__ */

static void
listPossibleVideoDrivers(char *matches[], int nmatches)
{
    struct pci_device * info = NULL;
    struct pci_device_iterator *iter;
    int i;
    
    for (i = 0 ; i < nmatches ; i++) {
        matches[i] = NULL;
    }
    i = 0;

#ifdef sun
    /* Check for driver type based on /dev/fb type and if valid, use
       it instead of PCI bus probe results */
    if (xf86Info.consoleFd >= 0) {
	struct vis_identifier   visid;
	const char *cp;
	extern char xf86SolarisFbDev[PATH_MAX];
	int iret;

	SYSCALL(iret = ioctl(xf86Info.consoleFd, VIS_GETIDENTIFIER, &visid));
	if (iret < 0) {
	    int fbfd;

	    fbfd = open(xf86SolarisFbDev, O_RDONLY);
	    if (fbfd >= 0) {
		SYSCALL(iret = ioctl(fbfd, VIS_GETIDENTIFIER, &visid));
		close(fbfd);
	    }
	}

	if (iret < 0) {
	    xf86Msg(X_WARNING,
		    "could not get frame buffer identifier from %s\n",
		    xf86SolarisFbDev);
	} else {
	    xf86Msg(X_PROBED, "console driver: %s\n", visid.name);

	    /* Special case from before the general case was set */
	    if (strcmp(visid.name, "NVDAnvda") == 0) {
		matches[i++] = xnfstrdup("nvidia");
	    }

	    /* General case - split into vendor name (initial all-caps
	       prefix) & driver name (rest of the string). */
	    if (strcmp(visid.name, "SUNWtext") != 0) {
		for (cp = visid.name; (*cp != '\0') && isupper(*cp); cp++) {
		    /* find end of all uppercase vendor section */
		}
		if ((cp != visid.name) && (*cp != '\0')) {
		    char *driverName = xnfstrdup(cp);
		    char *vendorName = xnfstrdup(visid.name);
		    vendorName[cp - visid.name] = '\0';

		    matches[i++] = vendorName;
		    matches[i++] = driverName;
		}
	    }
	}
    }
#endif
#ifdef __sparc__
    {
	char *sbusDriver = sparcDriverName();
	if (sbusDriver)
	    matches[i++] = xnfstrdup(sbusDriver);
    }
#endif

    /* Find the primary device, and get some information about it. */
    iter = pci_slot_match_iterator_create(NULL);
    while ((info = pci_device_next(iter)) != NULL) {
	if (xf86IsPrimaryPci(info)) {
	    break;
	}
    }

    pci_iterator_destroy(iter);

    if (!info) {
	ErrorF("Primary device is not PCI\n");
    }
#ifdef __linux__
    else {
	matchDriverFromFiles(matches, info->vendor_id, info->device_id);
    }
#endif /* __linux__ */

    for (i = 0; (i < nmatches) && (matches[i]); i++) {
	/* find end of matches list */
    }

    if ((info != NULL) && (i < nmatches)) {
	i += videoPtrToDriverList(info, &(matches[i]), nmatches - i);
    }

    /* Fallback to platform default hardware */
    if (i < (nmatches - 1)) {
#if defined(__i386__) || defined(__amd64__) || defined(__hurd__)
	matches[i++] = xnfstrdup("vesa");
#elif defined(__sparc__) && !defined(sun)
	matches[i++] = xnfstrdup("sunffb");
#endif
    }

    /* Fallback to platform default frame buffer driver */
    if (i < (nmatches - 1)) {
#if !defined(__linux__) && defined(__sparc__)
	matches[i++] = xnfstrdup("wsfb");
#else
	matches[i++] = xnfstrdup("fbdev");
#endif
    }
}

/* copy a screen section and enter the desired driver
 * and insert it at i in the list of screens */
static Bool
copyScreen(confScreenPtr oscreen, GDevPtr odev, int i, char *driver)
{
    GDevPtr cptr = NULL;

    xf86ConfigLayout.screens[i].screen = xnfcalloc(1, sizeof(confScreenRec));
    if(!xf86ConfigLayout.screens[i].screen)
        return FALSE;
    memcpy(xf86ConfigLayout.screens[i].screen, oscreen, sizeof(confScreenRec));

    cptr = xcalloc(1, sizeof(GDevRec));
    if (!cptr)
        return FALSE;
    memcpy(cptr, odev, sizeof(GDevRec));

    cptr->identifier = Xprintf("Autoconfigured Video Device %s", driver);
    cptr->driver = driver;

    /* now associate the new driver entry with the new screen entry */
    xf86ConfigLayout.screens[i].screen->device = cptr;
    cptr->myScreenSection = xf86ConfigLayout.screens[i].screen;

    return TRUE;
}
コード例 #8
0
ファイル: topology-pci.c プロジェクト: CoryXie/hwloc
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);
}
コード例 #9
0
ファイル: topology-pci.c プロジェクト: tblume/openmpi-hwloc
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;
}