Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:05

0001 /**
0002  * @file
0003  *
0004  * This file implements a BSP independent version of pci_find_device().
0005  */
0006 
0007 /*
0008  * The software in this file was based upon the pci_find_device()
0009  * implementation provided by  Till Straumann under the following terms.
0010  * That implementation had been copied to multiple BSPs. This implementation
0011  * is BSP independent and follows RTEMS Project coding guidelines.
0012  *
0013  * COPYRIGHT (c) 2016.
0014  * On-Line Applications Research Corporation (OAR).
0015  *
0016  * Authorship
0017  * ----------
0018  * This software was created by
0019  *     Till Straumann <strauman@slac.stanford.edu>, 2001,
0020  *      Stanford Linear Accelerator Center, Stanford University.
0021  *
0022  * Acknowledgement of sponsorship
0023  * ------------------------------
0024  * This software was produced by
0025  *     the Stanford Linear Accelerator Center, Stanford University,
0026  *      under Contract DE-AC03-76SFO0515 with the Department of Energy.
0027  *
0028  * Government disclaimer of liability
0029  * ----------------------------------
0030  * Neither the United States nor the United States Department of Energy,
0031  * nor any of their employees, makes any warranty, express or implied, or
0032  * assumes any legal liability or responsibility for the accuracy,
0033  * completeness, or usefulness of any data, apparatus, product, or process
0034  * disclosed, or represents that its use would not infringe privately owned
0035  * rights.
0036  *
0037  * Stanford disclaimer of liability
0038  * --------------------------------
0039  * Stanford University makes no representations or warranties, express or
0040  * implied, nor assumes any liability for the use of this software.
0041  *
0042  * Stanford disclaimer of copyright
0043  * --------------------------------
0044  * Stanford University, owner of the copyright, hereby disclaims its
0045  * copyright and all other rights in this software.  Hence, anyone may
0046  * freely use it for any purpose without restriction.
0047  *
0048  * Maintenance of notices
0049  * ----------------------
0050  * In the interest of clarity regarding the origin and status of this
0051  * SLAC software, this and all the preceding Stanford University notices
0052  * are to remain affixed to any copy or derivative of this software made
0053  * or distributed by the recipient and are to be affixed to any copy of
0054  * software made or distributed by the recipient that contains a copy or
0055  * derivative of this software.
0056  *
0057  * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
0058  */
0059 
0060 
0061 #include <rtems/pci.h>
0062 #include <rtems/bspIo.h>
0063 #include <inttypes.h>
0064 #include <stdio.h>
0065 
0066 /*
0067  *  Public methods from this file
0068  */
0069 void pci_dump(FILE *f);
0070 
0071 /*
0072  * These are used to construct the handle returned by pci_find_device()
0073  * but the caller does not need to know how to decode them.
0074  */
0075 #define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
0076 #define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
0077 #define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
0078 #define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
0079 
0080 /*
0081  * Function pointer to helper function called during bus iteration.
0082  */
0083 typedef int (*pci_scan_helper_t)(
0084   int   bus,
0085   int   dev,
0086   int   fun,
0087   void *uarg
0088 );
0089 
0090 /*
0091  *
0092  */
0093 static uint32_t pci_scan(
0094   uint32_t           handle,
0095   pci_scan_helper_t  helper,
0096   void              *uarg
0097 );
0098 
0099 typedef struct {
0100   uint16_t   vendor_id;
0101   uint16_t   device_id;
0102   int        instance;
0103   uint8_t    bus;
0104   uint8_t    device;
0105   uint8_t    function;
0106 } pci_scan_arg_t;
0107 
0108 static int find_dev_helper(
0109   int   bus,
0110   int   device,
0111   int   function,
0112   void *uarg
0113 )
0114 {
0115   pci_scan_arg_t  *scan = uarg;
0116   uint16_t         vendor_tmp;
0117   uint16_t         device_tmp;
0118 
0119   pci_read_config_word(bus, device, function, PCI_VENDOR_ID, &vendor_tmp);
0120   if (scan->vendor_id == vendor_tmp) {
0121     pci_read_config_word(bus, device, function, PCI_DEVICE_ID, &device_tmp);
0122     if (scan->device_id == device_tmp && scan->instance-- == 0) {
0123       scan->bus      = bus;
0124       scan->device   = device;
0125       scan->function = function;
0126 
0127       return 1;
0128     }
0129   }
0130   return 0;
0131 }
0132 
0133 int pci_find_device(
0134   uint16_t vendorid,
0135   uint16_t deviceid,
0136   int      instance,
0137   int     *bus,
0138   int     *device,
0139   int     *function
0140 )
0141 {
0142   pci_scan_arg_t  scan;
0143 
0144   scan.instance   = instance;
0145   scan.vendor_id  = vendorid;
0146   scan.device_id  = deviceid;
0147 
0148   if ( pci_scan(0, find_dev_helper, (void*)&scan) != 0 ) {
0149     *bus      = scan.bus;
0150     *device   = scan.device;
0151     *function = scan.function;
0152     return 0;
0153   }
0154   return -1;
0155 }
0156 
0157 static int dump_dev_helper(
0158   int   bus,
0159   int   device,
0160   int   function,
0161   void *arg
0162 )
0163 {
0164   uint16_t  vendor_id;
0165   uint16_t  device_id;
0166   uint16_t  cmd;
0167   uint16_t  status;
0168   uint32_t  base0;
0169   uint32_t  base1;
0170   uint8_t   irq_pin;
0171   uint8_t   int_line;
0172   FILE     *fp = arg;
0173 
0174   pci_read_config_word (bus, device, function, PCI_VENDOR_ID,      &vendor_id);
0175   pci_read_config_word (bus, device, function, PCI_DEVICE_ID,      &device_id);
0176   pci_read_config_word (bus, device, function, PCI_COMMAND,        &cmd);
0177   pci_read_config_word (bus, device, function, PCI_STATUS,         &status);
0178   pci_read_config_dword(bus, device, function, PCI_BASE_ADDRESS_0, &base0);
0179   pci_read_config_dword(bus, device, function, PCI_BASE_ADDRESS_1, &base1);
0180   pci_read_config_byte (bus, device, function, PCI_INTERRUPT_PIN,  &irq_pin);
0181   pci_read_config_byte (bus, device, function, PCI_INTERRUPT_LINE, &int_line);
0182 
0183   fprintf(
0184     fp,
0185     "%3d:0x%02x:%d   0x%04x:0x%04x 0x%04x 0x%04x 0x%08" PRIx32 " 0x%08" PRIx32 "   %d %3d(0x%02x)\n",
0186     bus,
0187     device,
0188     function,
0189     vendor_id,
0190     device_id,
0191     cmd,
0192     status,
0193     base0,
0194     base1,
0195     irq_pin,
0196     int_line,
0197     int_line
0198   );
0199   return 0;
0200 }
0201 
0202 void pci_dump(
0203   FILE *fp
0204 )
0205 {
0206   if ( !fp )
0207     fp = stdout;
0208   fprintf(
0209     fp,
0210     "BUS:SLOT:FUN VENDOR:DEV_ID   CMD  STAT   BASE_ADDR0 BASE_ADDR1 INTn IRQ_LINE\n"
0211   );
0212   pci_scan(0, dump_dev_helper, fp);
0213 }
0214 
0215 static uint32_t pci_scan(
0216   uint32_t           handle,
0217   pci_scan_helper_t  helper,
0218   void               *arg
0219 )
0220 {
0221   uint32_t vendor;
0222   uint8_t  bus;
0223   uint8_t  dev;
0224   uint8_t  fun;
0225   uint8_t  hd;
0226 
0227   bus = PCIB_DEVSIG_BUS(  (unsigned long)handle );
0228   dev = PCIB_DEVSIG_DEV(  (unsigned long)handle );
0229   fun = PCIB_DEVSIG_FUNC( (unsigned long)handle );
0230 
0231   hd = fun > 0 ? PCI_MAX_FUNCTIONS : 1;
0232 
0233   for (; bus<pci_bus_count(); bus++, dev=0) {
0234     for (; dev<PCI_MAX_DEVICES; dev++, fun=0) {
0235       for (; fun<hd; fun++) {
0236         /*
0237          * The last devfn id/slot is special; must skip it
0238          */
0239         if ((PCI_MAX_DEVICES-1 == dev) && (PCI_MAX_FUNCTIONS-1 == fun) )
0240           break;
0241 
0242         (void)pci_read_config_dword(bus, dev, 0, PCI_VENDOR_ID, &vendor);
0243         if (PCI_INVALID_VENDORDEVICEID == vendor)
0244           continue;
0245 
0246         if ( fun == 0 ) {
0247           pci_read_config_byte(bus,dev, 0,  PCI_HEADER_TYPE, &hd);
0248           hd = (hd & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1);
0249         }
0250 
0251         (void)pci_read_config_dword(bus, dev, fun, PCI_VENDOR_ID, &vendor);
0252         if (PCI_INVALID_VENDORDEVICEID == vendor)
0253           continue;
0254         #ifdef PCI_DEBUG
0255           fprintf(
0256             stderr,
0257             "pci_scan: found 0x%08" PRIx32 " at %d/x%02x/%d\n", vendor, bus, dev, fun
0258           );
0259         #endif
0260         if ( (*helper)(bus, dev, fun, arg) > 0 ) {
0261           if ( ++fun >= hd ) {
0262             fun = 0;
0263             if ( ++dev >= PCI_MAX_DEVICES ) {
0264               dev = 0;
0265               bus++;
0266             }
0267           }
0268           return PCIB_DEVSIG_MAKE(bus,dev,fun);
0269         }
0270       }
0271     }
0272   }
0273   return 0;
0274 }