Samuel Thibault, le Wed 06 Feb 2013 01:55:18 +0100, a écrit :
> Jeff Squyres (jsquyres), le Wed 06 Feb 2013 01:41:21 +0100, a écrit :
> > On Feb 5, 2013, at 3:50 PM, Samuel Thibault <[email protected]>
> > wrote:
> >
> > > Jeff Squyres (jsquyres), le Tue 05 Feb 2013 22:52:01 +0100, a écrit :
> > >> It was just pointed out to me that libpci is licensed under the GPL (not
> > >> the LGPL).
> > >
> > > I'm told that we could use libpciaccess instead, which is BSD.
> >
> > That would be great -- is it easily available?
>
> Yes. I've made a quick port
Here is a quick version (I haven't taken the time to handle the hwloc.m4
stuff).
Samuel
Index: src/topology-libpci.c
===================================================================
--- src/topology-libpci.c (révision 5235)
+++ src/topology-libpci.c (copie de travail)
@@ -1,7 +1,7 @@
/*
* Copyright © 2009 CNRS
* Copyright © 2009-2012 Inria. All rights reserved.
- * Copyright © 2009-2011 Université Bordeaux 1
+ * Copyright © 2009-2011, 2013 Université Bordeaux 1
* See COPYING in top-level directory.
*/
@@ -14,7 +14,6 @@
#include <private/debug.h>
#include <private/misc.h>
-#include <pci/pci.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
@@ -22,8 +21,92 @@
#include <stdarg.h>
#include <setjmp.h>
-#define CONFIG_SPACE_CACHESIZE 256
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+#include <pciaccess.h>
+#undef HWLOC_HAVE_LIBPCI
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
+#include <pci/pci.h>
+#endif
+
+#ifndef PCI_HEADER_TYPE
+#define PCI_HEADER_TYPE 0x0e
+#endif
+#ifndef PCI_HEADER_TYPE_BRIDGE
+#define PCI_HEADER_TYPE_BRIDGE 1
+#endif
+
+#ifndef PCI_CLASS_DEVICE
+#define PCI_CLASS_DEVICE 0x0a
+#endif
+#ifndef PCI_CLASS_BRIDGE_PCI
+#define PCI_CLASS_BRIDGE_PCI 0x0604
+#endif
+
+#ifndef PCI_REVISION_ID
+#define PCI_REVISION_ID 0x08
+#endif
+
+#ifndef PCI_SUBSYSTEM_VENDOR_ID
+#define PCI_SUBSYSTEM_VENDOR_ID 0x2c
+#endif
+#ifndef PCI_SUBSYSTEM_ID
+#define PCI_SUBSYSTEM_ID 0x2e
+#endif
+
+#ifndef PCI_PRIMARY_BUS
+#define PCI_PRIMARY_BUS 0x18
+#endif
+#ifndef PCI_SECONDARY_BUS
+#define PCI_SECONDARY_BUS 0x19
+#endif
+#ifndef PCI_SUBORDINATE_BUS
+#define PCI_SUBORDINATE_BUS 0x1a
+#endif
+
+#ifndef PCI_EXP_LNKSTA
+#define PCI_EXP_LNKSTA 18
+#endif
+
+#ifndef PCI_EXP_LNKSTA_SPEED
+#define PCI_EXP_LNKSTA_SPEED 0x000f
+#endif
+#ifndef PCI_EXP_LNKSTA_WIDTH
+#define PCI_EXP_LNKSTA_WIDTH 0x03f0
+#endif
+
+#ifndef PCI_CAP_ID_EXP
+#define PCI_CAP_ID_EXP 0x10
+#endif
+
+#ifndef PCI_CAP_NORMAL
+#define PCI_CAP_NORMAL 1
+#endif
+
+#ifndef PCI_STATUS
+#define PCI_STATUS 0x06
+#endif
+
+#ifndef PCI_CAPABILITY_LIST
+#define PCI_CAPABILITY_LIST 0x34
+#endif
+
+#ifndef PCI_STATUS_CAP_LIST
+#define PCI_STATUS_CAP_LIST 0x10
+#endif
+
+#ifndef PCI_CAP_LIST_ID
+#define PCI_CAP_LIST_ID 0
+#endif
+
+#ifndef PCI_CAP_LIST_NEXT
+#define PCI_CAP_LIST_NEXT 1
+#endif
+
+#define CONFIG_SPACE_CACHESIZE_TRY 256
+#define CONFIG_SPACE_CACHESIZE 64
+
static void
hwloc_pci_traverse_print_cb(void * cbdata __hwloc_attribute_unused,
struct hwloc_obj *pcidev, int depth
__hwloc_attribute_unused)
@@ -290,6 +373,7 @@
return parent;
}
+#ifdef HWLOC_HAVE_LIBPCI
/* Avoid letting libpci call exit(1) when no PCI bus is available. */
static jmp_buf err_buf;
static void
@@ -308,15 +392,59 @@
hwloc_pci_warning(char *msg __hwloc_attribute_unused, ...)
{
}
+#endif
+#ifndef HWLOC_HAVE_PCI_FIND_CAP
+static unsigned
+hwloc_pci_find_cap(const unsigned char *config, size_t config_size, unsigned
cap)
+{
+ unsigned char seen[256] = { 0 };
+ unsigned char ptr;
+
+ if (!(config[PCI_STATUS] & PCI_STATUS_CAP_LIST))
+ return 0;
+
+ for (ptr = config[PCI_CAPABILITY_LIST] & ~3;
+ ptr;
+ ptr = config[ptr + PCI_CAP_LIST_NEXT] & ~3) {
+ unsigned char id;
+
+ if (ptr >= config_size)
+ return 0;
+
+ /* Looped around! */
+ if (seen[ptr])
+ return 0;
+ seen[ptr] = 1;
+
+ id = config[ptr + PCI_CAP_LIST_ID];
+ if (id == cap)
+ return ptr;
+ if (id == 0xff)
+ break;
+
+ if (ptr + PCI_CAP_LIST_NEXT >= config_size)
+ return 0;
+ }
+ return 0;
+}
+#endif
+
static int
hwloc_look_libpci(struct hwloc_backend *backend)
{
struct hwloc_topology *topology = backend->topology;
+ struct hwloc_obj fakehostbridge; /* temporary object covering the whole PCI
hierarchy until its complete */
+ unsigned current_hostbridge;
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ int ret;
+ struct pci_device_iterator *iter;
+ struct pci_device *pcidev;
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
struct pci_access *pciaccess;
struct pci_dev *pcidev;
- struct hwloc_obj fakehostbridge; /* temporary object covering the whole PCI
hierarchy until its complete */
- unsigned current_hostbridge;
+#endif
if (!(hwloc_topology_get_flags(topology) &
(HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO)))
return 0;
@@ -331,6 +459,16 @@
hwloc_debug("%s", "\nScanning PCI buses...\n");
+#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);
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
pciaccess = pci_alloc();
pciaccess->error = hwloc_pci_error;
pciaccess->warning = hwloc_pci_warning;
@@ -343,20 +481,43 @@
pci_init(pciaccess);
pci_scan_bus(pciaccess);
- pcidev = pciaccess->devices;
- while (pcidev) {
- char name[128];
+#endif
+
+#ifdef HWLOC_HAVE_LIBPCI
+ for (pcidev = pciaccess->devices;
+ pcidev;
+ pcidev = pcidev->next)
+#endif
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ for (pcidev = pci_device_next(iter);
+ pcidev;
+ pcidev = pci_device_next(iter))
+#endif
+ {
const char *resname;
- u8 config_space_cache[CONFIG_SPACE_CACHESIZE];
+ unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE_TRY];
+ unsigned config_space_cachesize = CONFIG_SPACE_CACHESIZE_TRY;
struct hwloc_obj *obj;
unsigned char headertype;
unsigned os_index;
unsigned isbridge;
unsigned domain;
unsigned device_class;
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ pciaddr_t got;
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
+ char name[128];
+#endif
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ pci_device_cfg_read(pcidev, config_space_cache, 0,
CONFIG_SPACE_CACHESIZE_TRY, &got);
+ config_space_cachesize = got;
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
/* cache what we need of the config space */
- pci_read_block(pcidev, 0, config_space_cache, CONFIG_SPACE_CACHESIZE);
+ pci_read_block(pcidev, 0, config_space_cache, CONFIG_SPACE_CACHESIZE_TRY);
+#endif
/* read some fields that may not always be available */
#ifdef HWLOC_HAVE_PCIDEV_DOMAIN
@@ -364,12 +525,17 @@
#else
domain = 0; /* default domain number */
#endif
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ device_class = pcidev->device_class >> 8;
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
#ifdef HWLOC_HAVE_PCIDEV_DEVICE_CLASS
device_class = pcidev->device_class;
#else
HWLOC_BUILD_ASSERT(PCI_CLASS_DEVICE < CONFIG_SPACE_CACHESIZE);
device_class = config_space_cache[PCI_CLASS_DEVICE] |
(config_space_cache[PCI_CLASS_DEVICE+1] << 8);
#endif
+#endif
/* is this a bridge? */
HWLOC_BUILD_ASSERT(PCI_HEADER_TYPE < CONFIG_SPACE_CACHESIZE);
@@ -396,16 +562,24 @@
obj->attr->pcidev.subdevice_id = config_space_cache[PCI_SUBSYSTEM_ID];
obj->attr->pcidev.linkspeed = 0; /* unknown */
+ {
#ifdef HWLOC_HAVE_PCI_FIND_CAP
+ struct pci_cap *cap = pci_find_cap(pcidev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
+ unsigned offset;
+ if (cap)
{
- struct pci_cap *cap = pci_find_cap(pcidev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
- if (cap) {
- if (cap->addr + PCI_EXP_LNKSTA >= CONFIG_SPACE_CACHESIZE) {
- fprintf(stderr, "cannot read PCI_EXP_LNKSTA cap at %d (only %d
cached)\n", cap->addr + PCI_EXP_LNKSTA, CONFIG_SPACE_CACHESIZE);
+ offset = cap->addr;
+#else
+ unsigned offset = hwloc_pci_find_cap(config_space_cache,
config_space_cachesize, PCI_CAP_ID_EXP);
+ if (offset > 0)
+ {
+#endif /* HWLOC_HAVE_PCI_FIND_CAP */
+ if (offset + PCI_EXP_LNKSTA + 4 >= config_space_cachesize) {
+ fprintf(stderr, "cannot read PCI_EXP_LNKSTA cap at %d (only %d
cached)\n", offset + PCI_EXP_LNKSTA, CONFIG_SPACE_CACHESIZE);
} else {
unsigned linksta, speed, width;
float lanespeed;
- memcpy(&linksta, &config_space_cache[cap->addr + PCI_EXP_LNKSTA], 4);
+ memcpy(&linksta, &config_space_cache[offset + PCI_EXP_LNKSTA], 4);
speed = linksta & PCI_EXP_LNKSTA_SPEED; /* PCIe generation */
width = (linksta & PCI_EXP_LNKSTA_WIDTH) >> 4; /* how many lanes */
/* PCIe Gen1 = 2.5GT/s signal-rate per lane with 8/10 encoding =
0.25GB/s data-rate per lane
@@ -417,7 +591,6 @@
}
}
}
-#endif /* HWLOC_HAVE_PCI_FIND_CAP */
if (isbridge) {
HWLOC_BUILD_ASSERT(PCI_PRIMARY_BUS < CONFIG_SPACE_CACHESIZE);
@@ -437,6 +610,10 @@
* of arguments, and supports the PCI_LOOKUP_NO_NUMBERS flag.
*/
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ resname = pci_device_get_vendor_name(pcidev);
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
resname = pci_lookup_name(pciaccess, name, sizeof(name),
#if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS
PCI_LOOKUP_VENDOR|PCI_LOOKUP_NO_NUMBERS,
@@ -446,9 +623,14 @@
pcidev->vendor_id, 0, 0, 0
#endif
);
+#endif
if (resname)
hwloc_obj_add_info(obj, "PCIVendor", resname);
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ resname = pci_device_get_device_name(pcidev);
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
resname = pci_lookup_name(pciaccess, name, sizeof(name),
#if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS
PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS,
@@ -458,9 +640,11 @@
pcidev->vendor_id, pcidev->device_id, 0, 0
#endif
);
+#endif
if (resname)
hwloc_obj_add_info(obj, "PCIDevice", resname);
+#ifdef HWLOC_HAVE_LIBPCI
resname = pci_lookup_name(pciaccess, name, sizeof(name),
#if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS
PCI_LOOKUP_VENDOR|PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS,
@@ -474,6 +658,7 @@
obj->name = strdup(resname);
else
resname = "??";
+#endif
hwloc_debug(" %04x:%02x:%02x.%01x %04x %04x:%04x %s\n",
domain, pcidev->bus, pcidev->dev, pcidev->func,
@@ -481,10 +666,14 @@
resname);
hwloc_pci_add_object(&fakehostbridge, obj);
- pcidev = pcidev->next;
}
+#ifdef HWLOC_HAVE_LIBPCIACCESS
+ pci_system_cleanup();
+#endif
+#ifdef HWLOC_HAVE_LIBPCI
pci_cleanup(pciaccess);
+#endif
hwloc_debug("%s", "\nPCI hierarchy after basic scan:\n");
hwloc_pci_traverse(NULL, &fakehostbridge, hwloc_pci_traverse_print_cb);