Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:58

0001 /*
0002  * pci.c :  this file contains basic PCI Io functions.
0003  *
0004  *  Copyright (C) 1999 valette@crf.canon.fr
0005  *
0006  *  This code is heavily inspired by the public specification of STREAM V2
0007  *  that can be found at :
0008  *
0009  *      <http://www.chorus.com/Documentation/index.html> by following
0010  *  the STREAM API Specification Document link.
0011  *
0012  *  The license and distribution terms for this file may be
0013  *  found in the file LICENSE in this distribution or at
0014  *  http://www.rtems.org/license/LICENSE.
0015  *
0016  *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
0017  *   - separated bridge detection code out of this file
0018  */
0019 
0020 #include <rtems.h>
0021 #include <bsp.h>
0022 
0023 #include <libcpu/io.h>
0024 #include <bsp/pci.h>
0025 #include <rtems/bspIo.h>
0026 
0027 #undef SHOW_PCI_SETTING
0028 
0029 /* allow for overriding these definitions */
0030 #ifndef PCI_CONFIG_ADDR
0031 #define PCI_CONFIG_ADDR      0xcf8
0032 #endif
0033 #ifndef PCI_CONFIG_DATA
0034 #define PCI_CONFIG_DATA      0xcfc
0035 #endif
0036 
0037 /* define a shortcut */
0038 #define pci  BSP_pci_configuration
0039 
0040 #ifndef  PCI_CONFIG_ADDR_VAL
0041 #define  PCI_CONFIG_ADDR_VAL(bus, slot, funcion, offset) \
0042      (0x80<<24|((bus)<<16)|(PCI_DEVFN((slot),(function))<<8)|(((offset)&~3)))
0043 #endif
0044 
0045 #ifndef  PCI_CONFIG_WR_ADDR
0046 #define  PCI_CONFIG_WR_ADDR( addr, val ) out_le32((volatile uint32_t*)(addr), (val))
0047 #endif
0048 
0049 #define PCI_CONFIG_SET_ADDR(addr, bus, slot,function,offset) \
0050   PCI_CONFIG_WR_ADDR((addr), PCI_CONFIG_ADDR_VAL((bus), (slot), (function), (offset)))
0051 
0052 
0053 extern void detect_host_bridge(void);
0054 
0055 /*
0056  * Bit encode for PCI_CONFIG_HEADER_TYPE register
0057  */
0058 unsigned char ucMaxPCIBus;
0059 
0060 static int
0061 indirect_pci_read_config_byte(
0062   unsigned char bus,
0063   unsigned char slot,
0064   unsigned char function,
0065   unsigned char offset,
0066   uint8_t       *val
0067 ) {
0068   PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
0069   *val = in_8(pci.pci_config_data + (offset&3));
0070   return PCIBIOS_SUCCESSFUL;
0071 }
0072 
0073 static int
0074 indirect_pci_read_config_word(
0075   unsigned char bus,
0076   unsigned char slot,
0077   unsigned char function,
0078   unsigned char offset,
0079   uint16_t      *val
0080 ) {
0081   *val = 0xffff;
0082   if (offset&1)
0083     return PCIBIOS_BAD_REGISTER_NUMBER;
0084 
0085   PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
0086   *val = in_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)));
0087   return PCIBIOS_SUCCESSFUL;
0088 }
0089 
0090 static int
0091 indirect_pci_read_config_dword(
0092   unsigned char bus,
0093   unsigned char slot,
0094   unsigned char function,
0095   unsigned char offset,
0096   uint32_t *val
0097 ) {
0098   *val = 0xffffffff;
0099   if (offset&3)
0100     return PCIBIOS_BAD_REGISTER_NUMBER;
0101 
0102   PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
0103   *val = in_le32((volatile uint32_t *)pci.pci_config_data);
0104   return PCIBIOS_SUCCESSFUL;
0105 }
0106 
0107 static int
0108 indirect_pci_write_config_byte(
0109   unsigned char bus,
0110   unsigned char slot,
0111   unsigned char function,
0112   unsigned char offset,
0113   uint8_t       val
0114 ) {
0115   PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
0116   out_8(pci.pci_config_data + (offset&3), val);
0117   return PCIBIOS_SUCCESSFUL;
0118 }
0119 
0120 static int
0121 indirect_pci_write_config_word(
0122   unsigned char bus,
0123   unsigned char slot,
0124   unsigned char function,
0125   unsigned char offset,
0126   uint16_t      val
0127 ) {
0128   if (offset&1)
0129     return PCIBIOS_BAD_REGISTER_NUMBER;
0130 
0131   PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
0132   out_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)), val);
0133   return PCIBIOS_SUCCESSFUL;
0134 }
0135 
0136 static int
0137 indirect_pci_write_config_dword(
0138   unsigned char bus,
0139   unsigned char slot,
0140   unsigned char function,
0141   unsigned char offset,
0142   uint32_t      val
0143 ) {
0144   if (offset&3)
0145     return PCIBIOS_BAD_REGISTER_NUMBER;
0146   PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
0147   out_le32((volatile uint32_t *)pci.pci_config_data, val);
0148   return PCIBIOS_SUCCESSFUL;
0149 }
0150 
0151 const pci_config_access_functions pci_indirect_functions = {
0152   indirect_pci_read_config_byte,
0153   indirect_pci_read_config_word,
0154   indirect_pci_read_config_dword,
0155   indirect_pci_write_config_byte,
0156   indirect_pci_write_config_word,
0157   indirect_pci_write_config_dword
0158 };
0159 
0160 rtems_pci_config_t BSP_pci_configuration = {
0161   (volatile unsigned char*)PCI_CONFIG_ADDR,
0162   (volatile unsigned char*)PCI_CONFIG_DATA,
0163   &pci_indirect_functions
0164 };
0165 
0166 static int
0167 direct_pci_read_config_byte(
0168   unsigned char bus,
0169   unsigned char slot,
0170   unsigned char function,
0171   unsigned char offset,
0172   uint8_t      *val
0173 ) {
0174   if (bus != 0 || (1<<slot & 0xff8007fe)) {
0175     *val=0xff;
0176      return PCIBIOS_DEVICE_NOT_FOUND;
0177   }
0178   *val=in_8(pci.pci_config_data + ((1<<slot)&~1)
0179    + (function<<8) + offset);
0180   return PCIBIOS_SUCCESSFUL;
0181 }
0182 
0183 static int
0184 direct_pci_read_config_word(
0185   unsigned char bus,
0186   unsigned char slot,
0187   unsigned char function,
0188   unsigned char offset,
0189   uint16_t     *val
0190 ) {
0191   *val = 0xffff;
0192   if (offset&1)
0193     return PCIBIOS_BAD_REGISTER_NUMBER;
0194   if (bus != 0 || (1<<slot & 0xff8007fe))
0195      return PCIBIOS_DEVICE_NOT_FOUND;
0196 
0197   *val=in_le16((volatile uint16_t *)
0198       (pci.pci_config_data + ((1<<slot)&~1)
0199        + (function<<8) + offset));
0200   return PCIBIOS_SUCCESSFUL;
0201 }
0202 
0203 static int
0204 direct_pci_read_config_dword(
0205   unsigned char bus,
0206   unsigned char slot,
0207   unsigned char function,
0208   unsigned char offset,
0209   uint32_t     *val
0210 ) {
0211   *val = 0xffffffff;
0212   if (offset&3)
0213     return PCIBIOS_BAD_REGISTER_NUMBER;
0214   if (bus != 0 || (1<<slot & 0xff8007fe))
0215      return PCIBIOS_DEVICE_NOT_FOUND;
0216 
0217   *val=in_le32((volatile uint32_t *)
0218       (pci.pci_config_data + ((1<<slot)&~1)
0219        + (function<<8) + offset));
0220   return PCIBIOS_SUCCESSFUL;
0221 }
0222 
0223 static int
0224 direct_pci_write_config_byte(
0225   unsigned char bus,
0226   unsigned char slot,
0227   unsigned char function,
0228   unsigned char offset,
0229   uint8_t       val
0230 ) {
0231   if (bus != 0 || (1<<slot & 0xff8007fe))
0232      return PCIBIOS_DEVICE_NOT_FOUND;
0233 
0234   out_8(pci.pci_config_data + ((1<<slot)&~1)
0235      + (function<<8) + offset,
0236      val);
0237   return PCIBIOS_SUCCESSFUL;
0238 }
0239 
0240 static int
0241 direct_pci_write_config_word(
0242   unsigned char bus,
0243   unsigned char slot,
0244   unsigned char function,
0245   unsigned char offset,
0246   uint16_t      val
0247 ) {
0248   if (offset&1)
0249     return PCIBIOS_BAD_REGISTER_NUMBER;
0250   if (bus != 0 || (1<<slot & 0xff8007fe))
0251      return PCIBIOS_DEVICE_NOT_FOUND;
0252 
0253   out_le16((volatile uint16_t *)
0254      (pci.pci_config_data + ((1<<slot)&~1)
0255    + (function<<8) + offset),
0256      val);
0257   return PCIBIOS_SUCCESSFUL;
0258 }
0259 
0260 static int
0261 direct_pci_write_config_dword(
0262   unsigned char bus,
0263   unsigned char slot,
0264   unsigned char function,
0265   unsigned char offset,
0266   uint32_t      val
0267 ) {
0268   if (offset&3)
0269     return PCIBIOS_BAD_REGISTER_NUMBER;
0270   if (bus != 0 || (1<<slot & 0xff8007fe))
0271      return PCIBIOS_DEVICE_NOT_FOUND;
0272 
0273   out_le32((volatile uint32_t *)
0274      (pci.pci_config_data + ((1<<slot)&~1)
0275    + (function<<8) + offset),
0276      val);
0277   return PCIBIOS_SUCCESSFUL;
0278 }
0279 
0280 const pci_config_access_functions pci_direct_functions = {
0281   direct_pci_read_config_byte,
0282   direct_pci_read_config_word,
0283   direct_pci_read_config_dword,
0284   direct_pci_write_config_byte,
0285   direct_pci_write_config_word,
0286   direct_pci_write_config_dword
0287 };
0288 
0289 #define PRINT_MSG() \
0290   printk("pci : Device %d:0x%02x:%d routed to interrupt_line %d\n", \
0291     pbus, pslot, pfun, int_name )
0292 
0293 /*
0294 ** Validate a test interrupt name and print a warning if its not one of
0295 ** the names defined in the routing record.
0296 */
0297 static int test_intname(
0298   const struct _int_map *row,
0299   int pbus,
0300   int pslot,
0301   int pfun,
0302   int int_pin,
0303   int int_name
0304 ) {
0305   int j, k;
0306   int _nopin= -1, _noname= -1;
0307 
0308   for (j=0; row->pin_route[j].pin > -1; j++) {
0309     if ( row->pin_route[j].pin == int_pin ) {
0310    _nopin = 0;
0311 
0312    for (k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ ) {
0313      if ( row->pin_route[j].int_name[k] == int_name ) {
0314        _noname=0; break;
0315      }
0316    }
0317    break;
0318     }
0319   }
0320 
0321    if( _nopin  )
0322    {
0323       printk("pci : Device %d:0x%02x:%d supplied a bogus interrupt_pin %d\n", pbus, pslot, pfun, int_pin );
0324       return -1;
0325    }
0326    else
0327    {
0328       if( _noname ) {
0329         unsigned char v = row->pin_route[j].int_name[0];
0330         printk("pci : Device %d:0x%02x:%d supplied a suspicious interrupt_line %d, ", pbus, pslot, pfun, int_name );
0331         if ( (row->opts & PCI_FIXUP_OPT_OVERRIDE_NAME) && 255 != (v = row->pin_route[j].int_name[0]) ) {
0332             printk("OVERRIDING with %d from fixup table\n", v);
0333             pci_write_config_byte(pbus,pslot,pfun,PCI_INTERRUPT_LINE,v);
0334         } else {
0335             printk("using it anyway\n");
0336         }
0337       }
0338    }
0339    return 0;
0340 }
0341 
0342 struct pcibridge
0343 {
0344   int bus;
0345   int slot;
0346 };
0347 
0348 static int FindPCIbridge( int mybus, struct pcibridge *pb )
0349 {
0350   int          pbus, pslot;
0351   uint8_t      bussec, buspri;
0352   uint16_t     devid, vendorid, dclass;
0353 
0354   for(pbus=0; pbus< pci_bus_count(); pbus++) {
0355     for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
0356       pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
0357       if ( devid == 0xffff ) continue;
0358 
0359       pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
0360       if ( vendorid == 0xffff ) continue;
0361 
0362       pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
0363 
0364       if ( dclass == PCI_CLASS_BRIDGE_PCI ) {
0365         pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS,    &buspri);
0366         pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS,  &bussec);
0367 
0368 #ifdef SHOW_PCI_SETTING
0369          printk("pci : Found bridge at %d:0x%02x, mybus %d, pribus %d, secbus %d ",
0370                  pbus, pslot, mybus, buspri, bussec );
0371 #endif
0372          if ( bussec == mybus ) {
0373 #ifdef SHOW_PCI_SETTING
0374            printk("match\n");
0375 #endif
0376            /* found our nearest bridge going towards the root */
0377            pb->bus = pbus;
0378            pb->slot = pslot;
0379 
0380            return 0;
0381         }
0382 #ifdef SHOW_PCI_SETTING
0383          printk("no match\n");
0384 #endif
0385       }
0386 
0387      }
0388    }
0389    return -1;
0390 }
0391 
0392 void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
0393 {
0394   unsigned char        cvalue;
0395   uint16_t             devid;
0396   int                  ismatch, i, j, pbus, pslot, pfun, int_pin, int_name, nfuns;
0397 
0398   /*
0399    * If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
0400    * INTERRUPT_NAME if one isn't already in place.  Then, drivers can
0401    * trivially use INTERRUPT_NAME to hook up with devices.
0402    */
0403 
0404   for (pbus=0; pbus< pci_bus_count(); pbus++) {
0405     for (pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
0406       pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
0407       if ( devid == 0xffff ) continue;
0408 
0409       /* got a device */
0410       pci_read_config_byte(pbus, pslot, 0, PCI_HEADER_TYPE, &cvalue);
0411       nfuns = cvalue & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1;
0412 
0413       for (pfun=0; pfun< nfuns; pfun++) {
0414         pci_read_config_word(pbus, pslot, pfun, PCI_DEVICE_ID, &devid);
0415         if( devid == 0xffff ) continue;
0416 
0417         pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_PIN, &cvalue);
0418         int_pin = cvalue;
0419 
0420         pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_LINE, &cvalue);
0421         int_name = cvalue;
0422 
0423         /* printk("pci : device %d:0x%02x:%i devid %04x, intpin %d, intline  %d\n",
0424            pbus, pslot, pfun, devid, int_pin, int_name ); */
0425 
0426 #ifdef SHOW_PCI_SETTING
0427         {
0428           unsigned short cmd,stat;
0429           unsigned char  lat, seclat, csize;
0430 
0431           pci_read_config_word(pbus,pslot,pfun,PCI_COMMAND, &cmd );
0432           pci_read_config_word(pbus,pslot,pfun,PCI_STATUS, &stat );
0433           pci_read_config_byte(pbus,pslot,pfun,PCI_LATENCY_TIMER, &lat );
0434           pci_read_config_byte(pbus,pslot,pfun,PCI_SEC_LATENCY_TIMER, &seclat );
0435           pci_read_config_byte(pbus,pslot,pfun,PCI_CACHE_LINE_SIZE, &csize );
0436 
0437 
0438           printk("pci : device %d:0x%02x:%d  cmd %04X, stat %04X, latency %d, "
0439               " sec_latency %d, clsize %d\n", pbus, pslot, pfun, cmd, stat,
0440               lat, seclat, csize);
0441         }
0442 #endif
0443 
0444         if ( int_pin > 0 ) {
0445           ismatch = 0;
0446 
0447           /*
0448            * first run thru the bspmap table and see if we have an
0449            * explicit configuration
0450            */
0451           for (i=0; bspmap[i].bus > -1; i++) {
0452             if ( bspmap[i].bus == pbus && bspmap[i].slot == pslot ) {
0453               ismatch = -1;
0454               /* we have a record in the table that gives specific
0455                * pins and interrupts for devices in this slot */
0456               if ( int_name == 255 ) {
0457                 /* find the vector associated with whatever pin the
0458                  * device gives us
0459                  */
0460                 for ( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ ) {
0461                   if ( bspmap[i].pin_route[j].pin == int_pin ) {
0462                     int_name = bspmap[i].pin_route[j].int_name[0];
0463                     break;
0464                   }
0465                 }
0466                 if ( int_name == -1 ) {
0467                   printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled int "
0468                       "pin %i to an interrupt_line.\n", pbus, pslot, pfun, int_pin );
0469                 } else {
0470                   PRINT_MSG();
0471                   pci_write_config_byte( pbus,pslot,pfun,
0472                       PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
0473                 }
0474               } else {
0475                 test_intname( &bspmap[i],pbus,pslot,pfun,int_pin,int_name);
0476               }
0477               break;
0478             }
0479           }
0480 
0481           if ( !ismatch ) {
0482             /*
0483              * no match, which means we're on a bus someplace.  Work
0484              * backwards from it to one of our defined busses,
0485              * swizzling thru each bridge on the way.
0486              */
0487 
0488             /* keep pbus, pslot pointed to the device being
0489              * configured while we track down the bridges using
0490              * tbus,tslot.  We keep searching the routing table because
0491              * we may end up finding our bridge in it
0492              */
0493 
0494             int tbus= pbus, tslot= pslot;
0495 
0496             for (;;) {
0497               for (i=0; bspmap[i].bus > -1; i++) {
0498                 if ( bspmap[i].bus == tbus &&
0499                     (bspmap[i].slot == tslot || bspmap[i].slot == -1) ) {
0500                   ismatch = -1;
0501                   /* found a record for this bus, so swizzle the
0502                    * int_pin which we then use to find the
0503                    * interrupt_name.
0504                    */
0505 
0506                   if ( int_name == 255 ) {
0507                     /*
0508                      * FIXME.  I can't believe this little hack
0509                      * is right.  It does not yield an error in
0510                      * convienently simple situations.
0511                      */
0512                     if ( tbus ) int_pin = (*swizzler)(tslot,int_pin);
0513 
0514                     /*
0515                      * int_pin points to the interrupt channel
0516                      * this card ends up delivering interrupts
0517                      * on.  Find the int_name servicing it.
0518                      */
0519                     for (int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++){
0520                       if ( bspmap[i].pin_route[j].pin == int_pin ) {
0521                         int_name = bspmap[i].pin_route[j].int_name[0];
0522                         break;
0523                       }
0524                     }
0525 
0526                     if ( int_name == -1 ) {
0527                       printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled "
0528                           "int pin %i to an interrupt_line.\n",
0529                           pbus, pslot, pfun, int_pin );
0530                     } else {
0531                       PRINT_MSG();
0532                       pci_write_config_byte(pbus,pslot,pfun,
0533                           PCI_INTERRUPT_LINE,(cvalue=int_name, cvalue));
0534                     }
0535                   } else {
0536                     test_intname(&bspmap[i],pbus,pslot,pfun,int_pin,int_name);
0537                   }
0538                   goto donesearch;
0539                 }
0540               }
0541 
0542               if ( !ismatch ) {
0543                 struct pcibridge   pb;
0544 
0545                 /*
0546                  * Haven't found our bus in the int map, so work
0547                  * upwards thru the bridges till we find it.
0548                  */
0549 
0550                 if ( FindPCIbridge( tbus, &pb )== 0 ) {
0551                   int_pin = (*swizzler)(tslot,int_pin);
0552 
0553                   /* our next bridge up is on pb.bus, pb.slot- now
0554                    * instead of pointing to the device we're
0555                    * trying to configure, we move from bridge to
0556                    * bridge.
0557                    */
0558 
0559                   tbus = pb.bus;
0560                   tslot = pb.slot;
0561                 } else {
0562                   printk("pci : No bridge from bus %i towards root found\n",
0563                       tbus );
0564                   goto donesearch;
0565                 }
0566               }
0567             }
0568           }
0569 donesearch:
0570 
0571           if ( !ismatch && int_pin != 0 && int_name == 255 ) {
0572             printk("pci : Unable to match device %d:0x%02x:%d with an int "
0573                 "routing table entry\n", pbus, pslot, pfun  );
0574           }
0575         }
0576       }
0577     }
0578   }
0579 }
0580 
0581 /*
0582  * This routine determines the maximum bus number in the system
0583  */
0584 int pci_initialize(void)
0585 {
0586   unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
0587   unsigned char ucHeader;
0588   unsigned char ucMaxSubordinate;
0589   uint32_t ulClass;
0590   uint32_t ulDeviceID;
0591 
0592   detect_host_bridge();
0593 
0594   /*
0595    * Scan PCI bus 0 looking for PCI-PCI bridges
0596    */
0597   for (ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
0598     pci_read_config_dword(0, ucSlotNumber, 0, PCI_VENDOR_ID, &ulDeviceID);
0599     if (ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
0600       /* This slot is empty */
0601       continue;
0602     }
0603     pci_read_config_byte(0, ucSlotNumber, 0, PCI_HEADER_TYPE, &ucHeader);
0604     if (ucHeader&PCI_HEADER_TYPE_MULTI_FUNCTION)  {
0605       ucNumFuncs=PCI_MAX_FUNCTIONS;
0606     } else {
0607       ucNumFuncs=1;
0608     }
0609     for (ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
0610       pci_read_config_dword(0, ucSlotNumber, ucFnNumber,
0611                             PCI_VENDOR_ID, &ulDeviceID);
0612       if (ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
0613         /* This slot/function is empty */
0614         continue;
0615       }
0616 
0617       /* This slot/function has a device fitted. */
0618       pci_read_config_dword(0, ucSlotNumber, ucFnNumber,
0619                             PCI_CLASS_REVISION, &ulClass);
0620       ulClass >>= 16;
0621       if (ulClass == PCI_CLASS_BRIDGE_PCI) {
0622         /* We have found a PCI-PCI bridge */
0623         pci_read_config_byte(0, ucSlotNumber, ucFnNumber,
0624                      PCI_SUBORDINATE_BUS, &ucMaxSubordinate);
0625        if (ucMaxSubordinate>ucMaxPCIBus) {
0626          ucMaxPCIBus=ucMaxSubordinate;
0627        }
0628      }
0629    }
0630  }
0631  return PCIB_ERR_SUCCESS;
0632 }
0633 
0634 /*
0635  * Return the number of PCI busses in the system
0636  */
0637 unsigned char pci_bus_count(void)
0638 {
0639   return (ucMaxPCIBus+1);
0640 }