[syslinux] [PATCH] pci: Introduce slot and function information

Sebastian Herbszt herbszt at gmx.de
Sun Aug 3 13:57:19 PDT 2008


H. Peter Anvin wrote:
> Here is a preliminary patch if you are interested...

I noticed pci_device_list is gone. If i don't mistake it was possible to
create a "custom" pci_device_list without using pci_scan() and use
get_module_name_from_pci_ids() to resolve it.
The new get_module_name_from_pci_ids() expects a pci_domain
which implies bus, slot and device hierarchy which is not needed
in this case. But since we got no users i don't think it does matter.

Just trivial comments below.

> diff --git a/com32/lib/pci/scan.c b/com32/lib/pci/scan.c
> index 1c3f526..298c4db 100644
> --- a/com32/lib/pci/scan.c
> +++ b/com32/lib/pci/scan.c
> @@ -65,7 +65,7 @@ static void remove_eol(char *string)
>  for(i = 0; i < j; i++) if(string[i] == '\n') string[i] = 0;
> }
> 
> -/* converting a hexa string into its numerical value*/
> +/* converting a hexa string into its numerical value */
> static int hex_to_int(char *hexa)
> {
>   return strtoul(hexa, NULL, 16);
> @@ -73,7 +73,7 @@ static int hex_to_int(char *hexa)
> 
> /* Try to match any pci device to the appropriate kernel module */
> /* it uses the modules.pcimap from the boot device*/

/* it uses the modules.pcimap from the boot device */

> -void get_module_name_from_pci_ids(struct pci_device_list *pci_device_list)
> +int get_module_name_from_pci_ids(struct pci_domain *domain)
> {
>   char line[MAX_LINE];
>   char module_name[21]; // the module name field is 21 char long
> @@ -83,29 +83,24 @@ void get_module_name_from_pci_ids(struct pci_device_list *pci_device_list)
>   char sub_vendor_id[16];
>   char sub_product_id[16];
>   FILE *f;
> -  int pci_dev;
> +  struct pci_device *dev;
> 
>   /* Intializing the linux_kernel_module for each pci device to "unknow" */

/* Initializing the linux_kernel_module for each pci device to "unknown" */

> -  /* adding a pci_dev_info member if needed*/
> -  for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
> -    struct pci_device *pci_device = &(pci_device_list->pci_device[pci_dev]);
> -
> -    /* initialize the pci_dev_info structure if it doesn't exist yet. */
> -    if (! pci_device->pci_dev_info) {
> -      pci_device->pci_dev_info = calloc(1,sizeof *pci_device->pci_dev_info);
> -
> -      if (!pci_device->pci_dev_info) {
> - printf("Can't allocate memory\n");
> - return;
> -      }
> +  /* adding a dev_info member if needed*/

/* adding a dev_info member if needed */

> +  for_each_pci_func(dev, domain) {
> +    /* initialize the dev_info structure if it doesn't exist yet. */
> +    if (! dev->dev_info) {
> +      dev->dev_info = zalloc(sizeof *dev->dev_info);
> +      if (!dev->dev_info)

if (! dev->dev_info) vs. if (!dev->dev_info) ?

> + return -1;
>     }
> -    strlcpy(pci_device->pci_dev_info->linux_kernel_module,"unknown",7);
> +    strcpy(dev->dev_info->linux_kernel_module, "unknown");
>   }
> 
>   /* Opening the modules.pcimap (ofa linux kernel) from the boot device*/

 /* Opening the modules.pcimap (of a linux kernel) from the boot device */

> -  f=fopen("modules.pcimap","r");
> +  f=fopen("modules.pcimap", "r");
>   if (!f)
> -    return;
> +    return -1;
> 
>   strcpy(vendor_id,"0000");
>   strcpy(product_id,"0000");
> @@ -141,26 +136,23 @@ void get_module_name_from_pci_ids(struct pci_device_list *pci_device_list)
>    }
>     /* if a pci_device match an entry, fill the linux_kernel_module with

 /* if a pci_device matches an entry, fill the linux_kernel_module with

>        the appropriate kernel module */
> -    for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
> -      struct pci_device *pci_device =
> - &pci_device_list->pci_device[pci_dev];
> -
> -      if (hex_to_int(vendor_id) == pci_device->vendor &&
> -   hex_to_int(product_id) == pci_device->product &&
> -   (hex_to_int(sub_product_id) & pci_device->sub_product)
> -   == pci_device->sub_product &&
> -   (hex_to_int(sub_vendor_id) & pci_device->sub_vendor)
> -   == pci_device->sub_vendor)
> - strcpy(pci_device->pci_dev_info->linux_kernel_module,
> -        module_name);
> +    for_each_pci_func(dev, domain) {
> +      if (hex_to_int(vendor_id) == dev->vendor &&
> +   hex_to_int(product_id) == dev->product &&
> +   (hex_to_int(sub_product_id) & dev->sub_product)
> +   == dev->sub_product &&
> +   (hex_to_int(sub_vendor_id) & dev->sub_vendor)
> +   == dev->sub_vendor)
> + strcpy(dev->dev_info->linux_kernel_module, module_name);
>     }
>   }
> - fclose(f);
> +  fclose(f);
> +  return 0;
> }
> 
> /* Try to match any pci device to the appropriate vendor and product name */
> /* it uses the pci.ids from the boot device*/

/* it uses the pci.ids from the boot device */

> -void get_name_from_pci_ids(struct pci_device_list *pci_device_list)
> +int get_name_from_pci_ids(struct pci_domain *domain)
> {
>   char line[MAX_LINE];
>   char vendor[255];
> @@ -170,156 +162,138 @@ void get_name_from_pci_ids(struct pci_device_list *pci_device_list)
>   char sub_product_id[5];
>   char sub_vendor_id[5];
>   FILE *f;
> -  int pci_dev;
> -
> - /* Intializing the vendor/product name for each pci device to "unknow" */
> - /* adding a pci_dev_info member if needed*/
> - for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
> -    struct pci_device *pci_device = &pci_device_list->pci_device[pci_dev];
> -
> -    /* initialize the pci_dev_info structure if it doesn't exist yet. */
> -    if (! pci_device->pci_dev_info) {
> -      pci_device->pci_dev_info = calloc(1,sizeof *pci_device->pci_dev_info);
> -
> -      if (!pci_device->pci_dev_info) {
> - printf("Can't allocate memory\n");
> - return;
> -      }
> +  struct pci_device *dev;
> +
> +  /* Intializing the vendor/product name for each pci device to "unknown" */
> +  /* adding a dev_info member if needed*/

/* adding a dev_info member if needed */

> +  for_each_pci_func(dev, domain) {
> +    /* initialize the dev_info structure if it doesn't exist yet. */
> +    if (! dev->dev_info) {
> +      dev->dev_info = zalloc(sizeof *dev->dev_info);
> +      if (!dev->dev_info)
> + return -1;
>     }
> -
> -    strlcpy(pci_device->pci_dev_info->vendor_name,"unknown",7);
> -    strlcpy(pci_device->pci_dev_info->product_name,"unknown",7);
> +    strcpy(dev->dev_info->vendor_name,"unknown");
> +    strcpy(dev->dev_info->product_name,"unknown");
>   }
> 
>   /* Opening the pci.ids from the boot device*/

/* Opening the pci.ids from the boot device */

> -  f=fopen("pci.ids","r");
> +  f = fopen("pci.ids","r");

f = fopen("pci.ids", "r");

>   if (!f)
> -        return;
> +    return -1;
> +
>   strcpy(vendor_id,"0000");
>   strcpy(product_id,"0000");
>   strcpy(sub_product_id,"0000");
>   strcpy(sub_vendor_id,"0000");
> 
> -
>   /* for each line we found in the pci.ids*/

/* for each line we found in the pci.ids */

>   while ( fgets(line, sizeof line, f) ) {
>     /* Skipping uncessary lines */
>     if ((line[0] == '#') || (line[0] == ' ') || (line[0] == 'C') ||
>  (line[0] == 10))
> -        continue;
> +      continue;
>     /* If the line doesn't start with a tab, it means that's a vendor id */
>     if (line[0] != '\t') {
> -
> - /* the 4th first chars are the vendor_id */
> -        strlcpy(vendor_id,line,4);
> -
> - /* the vendor name is the next field*/
> -        vendor_id[4]=0;
> -        strlcpy(vendor,skipspace(strstr(line," ")),255);
> -
> -        remove_eol(vendor);
> - /* init product_id, sub_product and sub_vendor */
> -        strcpy(product_id,"0000");
> -        strcpy(sub_product_id,"0000");
> -        strcpy(sub_vendor_id,"0000");
> -
> - /* ffff is an invalid vendor id */
> - if (strstr(vendor_id,"ffff")) break;
> - /* assign the vendor_name to any matching pci device*/
> - for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
> -   struct pci_device *pci_device =
> -     &pci_device_list->pci_device[pci_dev];
> -
> -   if (hex_to_int(vendor_id) == pci_device->vendor)
> -     strlcpy(pci_device->pci_dev_info->vendor_name,vendor,255);
> - }
> -    /* if we have a tab + a char, it means this is a product id */
> +      
> +      /* the 4th first chars are the vendor_id */

/* the 4 first chars are the vendor_id */

> +      strlcpy(vendor_id,line,4);
> +      
> +      /* the vendor name is the next field*/

/* the vendor name is the next field */

> +      vendor_id[4]=0;
> +      strlcpy(vendor,skipspace(strstr(line," ")),255);
> +      
> +      remove_eol(vendor);
> +      /* init product_id, sub_product and sub_vendor */
> +      strcpy(product_id,"0000");
> +      strcpy(sub_product_id,"0000");
> +      strcpy(sub_vendor_id,"0000");
> +      
> +      /* ffff is an invalid vendor id */
> +      if (strstr(vendor_id,"ffff")) break;
> +      /* assign the vendor_name to any matching pci device*/

/* assign the vendor_name to any matching pci device */

> +      for_each_pci_func(dev, domain) {
> + if (hex_to_int(vendor_id) == dev->vendor)
> +   strlcpy(dev->dev_info->vendor_name,vendor,255);
> +      }
> +      /* if we have a tab + a char, it means this is a product id */
>     } else if ((line[0] == '\t') && (line[1] != '\t')) {
> -
> - /* the product name the second field */
> -        strlcpy(product,skipspace(strstr(line," ")),255);
> -        remove_eol(product);
> -
> - /* the product id is first field */
> - strlcpy(product_id,&line[1],4);
> -        product_id[4]=0;
> -
> - /* init sub_product and sub_vendor */
> -        strcpy(sub_product_id,"0000");
> -        strcpy(sub_vendor_id,"0000");
> -
> - /* assign the product_name to any matching pci device*/
> - for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
> -   struct pci_device *pci_device =
> -     &pci_device_list->pci_device[pci_dev];
> -   if (hex_to_int(vendor_id) == pci_device->vendor &&
> -       hex_to_int(product_id) == pci_device->product)
> -     strlcpy(pci_device->pci_dev_info->product_name,product,255);
> - }
> -
> -    /* if we have two tabs, it means this is a sub product */
> +      
> +      /* the product name the second field */

/* the product name is the second field */

> +      strlcpy(product,skipspace(strstr(line," ")),255);
> +      remove_eol(product);
> +      
> +      /* the product id is first field */
> +      strlcpy(product_id,&line[1],4);
> +      product_id[4]=0;
> +      
> +      /* init sub_product and sub_vendor */
> +      strcpy(sub_product_id,"0000");
> +      strcpy(sub_vendor_id,"0000");
> +      
> +      /* assign the product_name to any matching pci device*/

/* assign the product_name to any matching pci device */

> +      for_each_pci_func(dev, domain) {
> + if (hex_to_int(vendor_id) == dev->vendor &&
> +     hex_to_int(product_id) == dev->product)
> +   strlcpy(dev->dev_info->product_name,product,255);
> +      }
> +      
> +      /* if we have two tabs, it means this is a sub product */
>     } else if ((line[0] == '\t') && (line[1] == '\t')) {
> -
> +      
>       /* the product name is last field */
>       strlcpy(product,skipspace(strstr(line," ")),255);
>       strlcpy(product,skipspace(strstr(product," ")),255);
>       remove_eol(product);
> -
> +      
>       /* the sub_vendor id is first field */
>       strlcpy(sub_vendor_id,&line[2],4);
>       sub_vendor_id[4]=0;
> -
> +      
>       /* the sub_vendor id is second field */
>       strlcpy(sub_product_id,&line[7],4);
>       sub_product_id[4]=0;
> -
> +      
>       /* assign the product_name to any matching pci device*/

/* assign the product_name to any matching pci device */

> -      for (pci_dev=0; pci_dev < pci_device_list->count; pci_dev++) {
> - struct pci_device *pci_device =
> -   &pci_device_list->pci_device[pci_dev];
> -
> - if (hex_to_int(vendor_id) == pci_device->vendor &&
> -     hex_to_int(product_id) == pci_device->product &&
> -     hex_to_int(sub_product_id) == pci_device->sub_product &&
> -     hex_to_int(sub_vendor_id) == pci_device->sub_vendor)
> -   strlcpy(pci_device->pci_dev_info->product_name,product,255);
> +      for_each_pci_func(dev, domain) {
> + if (hex_to_int(vendor_id) == dev->vendor &&
> +     hex_to_int(product_id) == dev->product &&
> +     hex_to_int(sub_product_id) == dev->sub_product &&
> +     hex_to_int(sub_vendor_id) == dev->sub_vendor)
> +   strlcpy(dev->dev_info->product_name,product,255);
>       }
>     }
>   }
>   fclose(f);
> +  return 0;
> }
> 
> /* searching if any pcidevice match our query */
> -struct match *find_pci_device(struct pci_device_list * pci_device_list,
> +struct match *find_pci_device(const struct pci_domain *domain,
>        struct match *list)
> {
> -  int pci_dev;
>   uint32_t did, sid;
>   struct match *m;
> +  const struct pci_device *dev;
> +
>   /* for all matches we have to search */
>   for (m = list; m; m = m->next) {
> -   /* for each pci device we know */
> -    for (pci_dev = 0; pci_dev < pci_device_list->count; pci_dev++) {
> -      struct pci_device *pci_device =
> - &pci_device_list->pci_device[pci_dev];
> -
> +    /* for each pci device we know */
> +    for_each_pci_func(dev, domain) {
>       /* sid & did are the easiest way to compare devices */
>       /* they are made of vendor/product subvendor/subproduct ids */
> -      sid =
> - ((pci_device->sub_product) << 16 | (pci_device->
> -     sub_vendor));
> -      did = ((pci_device->product << 16) | (pci_device->vendor));
> -
> +      sid = dev->svid_sdid;
> +      did = dev->vid_did;
>       /*if the current device match */
>       if (((did ^ m->did) & m->did_mask) == 0 &&
>    ((sid ^ m->sid) & m->sid_mask) == 0 &&
> -   pci_device->revision >= m->rid_min
> -   && pci_device->revision <= m->rid_max) {
> +   dev->revision >= m->rid_min
> +   && dev->revision <= m->rid_max) {
>  dprintf("PCI Match: Vendor=%04x Product=%04x Sub_vendor=%04x Sub_Product=%04x Release=%02x\n",
> - pci_device->vendor, pci_device->product,
> - pci_device->sub_vendor,
> - pci_device->sub_product,
> - pci_device->revision);
> + dev->vendor, dev->product,
> + dev->sub_vendor,
> + dev->sub_product,
> + dev->revision);
>  /* returning the matched pci device */
>  return m;
>       }
> @@ -329,45 +303,32 @@ struct match *find_pci_device(struct pci_device_list * pci_device_list,
> }
> 
> /* scanning the pci bus to find pci devices */
> -int pci_scan(struct pci_bus_list * pci_bus_list, struct pci_device_list * pci_device_list)
> +struct pci_domain *pci_scan(void)
> {
> -  unsigned int bus, dev, func, maxfunc;
> -  uint32_t did, sid;
> -  uint8_t hdrtype, rid;
> +  struct pci_domain *domain = NULL;
> +  struct pci_bus    *bus    = NULL;
> +  struct pci_slot   *slot   = NULL;
> +  struct pci_device *func   = NULL;
> +  unsigned int nbus, ndev, nfunc, maxfunc;
> +  uint32_t did, sid, rcid;
> +  uint8_t hdrtype;
>   pciaddr_t a;
>   int cfgtype;
> 
> -  pci_device_list->count = 0;
> -
> -#ifdef DEBUG
> -  outl(~0, 0xcf8);
> -  printf("Poking at port CF8 = %#08x\n", inl(0xcf8));
> -  outl(0, 0xcf8);
> -#endif
> -
>   cfgtype = pci_set_config_type(PCI_CFG_AUTO);
>   (void)cfgtype;
> 
>   dprintf("PCI configuration type %d\n", cfgtype);
>   dprintf("Scanning PCI Buses\n");
> 
> -  /* We try to detect 256 buses */
> -  for (bus = 0; bus < MAX_PCI_BUSES; bus++) {
> -
> +  for (nbus = 0; nbus < MAX_PCI_BUSSES; nbus++) {
>     dprintf("Probing bus 0x%02x... \n", bus);
> 
> -    pci_bus_list->pci_bus[bus].id = bus;
> -    pci_bus_list->pci_bus[bus].pci_device_count = 0;
> -    pci_bus_list->count = 0;;
> -
> -    for (dev = 0; dev < MAX_PCI_DEVICES ; dev++) {
> +    for (ndev = 0; ndev < MAX_PCI_DEVICES ; ndev++) {

for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) {

>       maxfunc = 1; /* Assume a single-function device */
> -      for (func = 0; func < maxfunc; func++) {
> - struct pci_device *pci_device =
> -   &pci_device_list->pci_device[pci_device_list->count];
> -
> - a = pci_mkaddr(bus, dev, func, 0);
> 
> +      for (nfunc = 0; nfunc < maxfunc; nfunc++) {
> + a = pci_mkaddr(nbus, ndev, nfunc, 0);
>  did = pci_readl(a);
> 
>  if (did == 0xffffffff || did == 0xffff0000 ||
> @@ -379,36 +340,79 @@ int pci_scan(struct pci_bus_list * pci_bus_list, struct pci_device_list * pci_de
>  if (hdrtype & 0x80)
>    maxfunc = MAX_PCI_FUNC; /* Multifunction device */
> 
> - rid = pci_readb(a + 0x08);
> - sid = pci_readl(a + 0x2c);
> + rcid = pci_readl(a + 0x08);
> + sid  = pci_readl(a + 0x2c);
> 
> - pci_device->addr = a;
> - pci_device->product = did >> 16;
> - pci_device->sub_product = sid >> 16;
> - pci_device->vendor = (did << 16) >> 16;
> - pci_device->sub_vendor = (sid << 16) >> 16;
> - pci_device->revision = rid;
> - pci_device_list->count++;
> - pci_device++;
> + if (!domain) {
> +   domain = zalloc(sizeof *domain);
> +   if (!domain)
> +     goto bail;
> + }
> + if (!bus) {
> +   bus = zalloc(sizeof *bus);
> +   if (!bus)
> +     goto bail;
> +   domain->bus[nbus] = bus;
> + }
> + if (!slot) {
> +   slot = zalloc(sizeof *slot);
> +   if (!slot)
> +     goto bail;
> +   bus->slot[ndev] = slot;
> + }
> + func = zalloc(sizeof *func);
> + if (!func)
> +   goto bail;
> +
> + slot->func[nfunc] = func;
> +
> + func->vid_did   = did;
> + func->svid_sdid = sid;
> + func->rid_class = rcid;
> 
>  dprintf
>    ("Scanning: BUS %02x DID %08x (%04x:%04x) SID %08x RID %02x\n",
>     bus, did, did >> 16, (did << 16) >> 16,
> -    sid, rid);
> - /* Adding the detected pci device to the bus */
> - pci_bus_list->pci_bus[bus].
> -   pci_device[pci_bus_list->pci_bus[bus].
> -      pci_device_count] = pci_device;
> - pci_bus_list->pci_bus[bus].pci_device_count++;
> +    sid, rcid & 0xff);
>       }
>     }
>   }
> 
> -  /* Detecting pci buses that have pci devices connected */
> -  for (bus = 0; bus < MAX_PCI_BUSES; bus++) {
> -    if (pci_bus_list->pci_bus[bus].pci_device_count > 0) {
> -      pci_bus_list->count++;
> +  return domain;
> +
> + bail:
> +  free_pci_domain(domain);
> +  return NULL;
> +}
> +
> +void free_pci_domain(struct pci_domain *domain)
> +{  
> +  struct pci_bus    *bus;
> +  struct pci_slot   *slot;
> +  struct pci_device *func;
> +  unsigned int nbus, ndev, nfunc;
> +
> +  if (domain) {
> +    for (nbus = 0; nbus < MAX_PCI_BUSSES; nbus++) {
> +      bus = domain->bus[nbus];
> +      if (bus) {
> + for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) {
> +   slot = bus->slot[ndev];
> +   if (slot) {
> +     for (nfunc = 0; nfunc < MAX_PCI_FUNC; nfunc++) {
> +       func = slot->func[nfunc];
> +       if (func) {
> + if (func->dev_info)
> +   free(func->dev_info);
> + free(func);
> +       }
> +       free(slot);
> +     }
> +   }
> +   free(bus);
> + }
> +      }
> +      free(domain);
>     }
>   }
> -  return 0;
> }
>

- Sebastian




More information about the Syslinux mailing list