source: rtems/c/src/lib/libbsp/powerpc/shared/pci/pci.c @ 844c273

4.104.114.84.95
Last change on this file since 844c273 was 844c273, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 27, 2004 at 5:22:11 PM

2004-04-09 Greg Menke <gregory.menke@…>

PR 608/bsps

  • pci/pcibios.c: Added BusCountPCI()
  • Property mode set to 100644
File size: 17.5 KB
Line 
1/*
2 * pci.c :  this file contains basic PCI Io functions.
3 *
4 *  CopyRight (C) 1999 valette@crf.canon.fr
5 *
6 *  This code is heavilly inspired by the public specification of STREAM V2
7 *  that can be found at :
8 *
9 *      <http://www.chorus.com/Documentation/index.html> by following
10 *  the STREAM API Specification Document link.
11 *
12 *  The license and distribution terms for this file may be
13 *  found in found in the file LICENSE in this distribution or at
14 *  http://www.rtems.com/license/LICENSE.
15 *
16 *  $Id$
17 *
18 *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
19 *   - separated bridge detection code out of this file
20 */
21
22#include <libcpu/io.h>
23#include <bsp/pci.h>
24#include <rtems/bspIo.h>
25
26/* allow for overriding these definitions */
27#ifndef PCI_CONFIG_ADDR
28#define PCI_CONFIG_ADDR                 0xcf8
29#endif
30#ifndef PCI_CONFIG_DATA
31#define PCI_CONFIG_DATA                 0xcfc
32#endif
33
34#define PCI_INVALID_VENDORDEVICEID      0xffffffff
35#define PCI_MULTI_FUNCTION              0x80
36
37/* define a shortcut */
38#define pci     BSP_pci_configuration
39
40
41
42/*
43 * Bit encode for PCI_CONFIG_HEADER_TYPE register
44 */
45unsigned char ucMaxPCIBus;
46
47static int
48indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
49                              unsigned char function,
50                              unsigned char offset, unsigned char *val) {
51        out_be32((unsigned int*) pci.pci_config_addr,
52                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
53        *val = in_8(pci.pci_config_data + (offset&3));
54        return PCIBIOS_SUCCESSFUL;
55}
56
57static int
58indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
59                              unsigned char function,
60                              unsigned char offset, unsigned short *val) {
61        *val = 0xffff;
62        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
63        out_be32((unsigned int*) pci.pci_config_addr,
64                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
65        *val = in_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)));
66        return PCIBIOS_SUCCESSFUL;
67}
68
69static int
70indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
71                              unsigned char function,
72                              unsigned char offset, unsigned int *val) {
73        *val = 0xffffffff;
74        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
75        out_be32((unsigned int*) pci.pci_config_addr,
76                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
77        *val = in_le32((volatile unsigned int *)pci.pci_config_data);
78        return PCIBIOS_SUCCESSFUL;
79}
80
81static int
82indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
83                               unsigned char function,
84                               unsigned char offset, unsigned char val) {
85        out_be32((unsigned int*) pci.pci_config_addr,
86                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
87        out_8(pci.pci_config_data + (offset&3), val);
88        return PCIBIOS_SUCCESSFUL;
89}
90
91static int
92indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
93                               unsigned char function,
94                               unsigned char offset, unsigned short val) {
95        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
96        out_be32((unsigned int*) pci.pci_config_addr,
97                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
98        out_le16((volatile unsigned short *)(pci.pci_config_data + (offset&3)), val);
99        return PCIBIOS_SUCCESSFUL;
100}
101
102static int
103indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
104                                unsigned char function,
105                                unsigned char offset, unsigned int val) {
106        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
107        out_be32((unsigned int*) pci.pci_config_addr,
108                 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
109        out_le32((volatile unsigned int *)pci.pci_config_data, val);
110        return PCIBIOS_SUCCESSFUL;
111}
112
113const pci_config_access_functions pci_indirect_functions = {
114        indirect_pci_read_config_byte,
115        indirect_pci_read_config_word,
116        indirect_pci_read_config_dword,
117        indirect_pci_write_config_byte,
118        indirect_pci_write_config_word,
119        indirect_pci_write_config_dword
120};
121
122pci_config BSP_pci_configuration = {(volatile unsigned char*)PCI_CONFIG_ADDR,
123                         (volatile unsigned char*)PCI_CONFIG_DATA,
124                         &pci_indirect_functions};
125
126static int
127direct_pci_read_config_byte(unsigned char bus, unsigned char slot,
128                            unsigned char function,
129                            unsigned char offset, unsigned char *val) {
130        if (bus != 0 || (1<<slot & 0xff8007fe)) {
131                *val=0xff;
132                return PCIBIOS_DEVICE_NOT_FOUND;
133        }
134        *val=in_8(pci.pci_config_data + ((1<<slot)&~1)
135                  + (function<<8) + offset);
136        return PCIBIOS_SUCCESSFUL;
137}
138
139static int
140direct_pci_read_config_word(unsigned char bus, unsigned char slot,
141                            unsigned char function,
142                            unsigned char offset, unsigned short *val) {
143        *val = 0xffff;
144        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
145        if (bus != 0 || (1<<slot & 0xff8007fe)) {
146                return PCIBIOS_DEVICE_NOT_FOUND;
147        }
148        *val=in_le16((volatile unsigned short *)
149                     (pci.pci_config_data + ((1<<slot)&~1)
150                      + (function<<8) + offset));
151        return PCIBIOS_SUCCESSFUL;
152}
153
154static int
155direct_pci_read_config_dword(unsigned char bus, unsigned char slot,
156                             unsigned char function,
157                             unsigned char offset, unsigned int *val) {
158        *val = 0xffffffff;
159        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
160        if (bus != 0 || (1<<slot & 0xff8007fe)) {
161                return PCIBIOS_DEVICE_NOT_FOUND;
162        }
163        *val=in_le32((volatile unsigned int *)
164                     (pci.pci_config_data + ((1<<slot)&~1)
165                      + (function<<8) + offset));
166        return PCIBIOS_SUCCESSFUL;
167}
168
169static int
170direct_pci_write_config_byte(unsigned char bus, unsigned char slot,
171                             unsigned char function,
172                             unsigned char offset, unsigned char val) {
173        if (bus != 0 || (1<<slot & 0xff8007fe)) {
174                return PCIBIOS_DEVICE_NOT_FOUND;
175        }
176        out_8(pci.pci_config_data + ((1<<slot)&~1)
177              + (function<<8) + offset,
178              val);
179        return PCIBIOS_SUCCESSFUL;
180}
181
182static int
183direct_pci_write_config_word(unsigned char bus, unsigned char slot,
184                             unsigned char function,
185                             unsigned char offset, unsigned short val) {
186        if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
187        if (bus != 0 || (1<<slot & 0xff8007fe)) {
188                return PCIBIOS_DEVICE_NOT_FOUND;
189        }
190        out_le16((volatile unsigned short *)
191                 (pci.pci_config_data + ((1<<slot)&~1)
192                  + (function<<8) + offset),
193                 val);
194        return PCIBIOS_SUCCESSFUL;
195}
196
197static int
198direct_pci_write_config_dword(unsigned char bus, unsigned char slot,
199                              unsigned char function,
200                              unsigned char offset, unsigned int val) {
201        if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
202        if (bus != 0 || (1<<slot & 0xff8007fe)) {
203                return PCIBIOS_DEVICE_NOT_FOUND;
204        }
205        out_le32((volatile unsigned int *)
206                 (pci.pci_config_data + ((1<<slot)&~1)
207                  + (function<<8) + offset),
208                 val);
209        return PCIBIOS_SUCCESSFUL;
210}
211
212const pci_config_access_functions pci_direct_functions = {
213        direct_pci_read_config_byte,
214        direct_pci_read_config_word,
215        direct_pci_read_config_dword,
216        direct_pci_write_config_byte,
217        direct_pci_write_config_word,
218        direct_pci_write_config_dword
219};
220
221#define PRINT_MSG() \
222             printk("pci : Device %d:%02x routed to interrupt_line %d\n", pbus, pslot, int_name )
223
224/*
225** Validate a test interrupt name and print a warning if its not one of
226** the names defined in the routing record.
227*/
228static int test_intname(
229  const struct _int_map *row, int pbus, int pslot, int int_pin, int int_name )
230{
231   int j,k;
232   int _nopin= -1, _noname= -1;
233
234   for(j=0; row->pin_route[j].pin > -1; j++)
235   {
236      if( row->pin_route[j].pin == int_pin )
237      {
238         _nopin = 0;
239
240         for(k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ )
241         {
242            if( row->pin_route[j].int_name[k] == int_name ){ _noname=0; break; }
243         }
244         break;
245      }
246   }
247
248   if( _nopin  )
249   {
250      printk("pci : Device %d:%02x supplied a bogus interrupt_pin %d\n", pbus, pslot, int_pin );
251      return -1;
252   }
253   else
254   {
255      if( _noname )
256         printk("pci : Device %d:%02x supplied a suspicious interrupt_line %d, using it anyway\n", pbus, pslot, int_name );
257   }
258   return 0;
259}
260
261struct pcibridge
262{
263      int bus,slot;
264};
265
266static int FindPCIbridge( int mybus, struct pcibridge *pb )
267{
268   int          pbus, pslot;
269   uint8_t      bussec, buspri;
270   uint16_t     devid, vendorid, dclass;
271
272   for(pbus=0; pbus< BusCountPCI(); pbus++)
273   {
274      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
275      {
276         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
277         if( devid == 0xffff ) continue;
278
279         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
280         if( vendorid == 0xffff ) continue;
281
282         pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
283
284         if( dclass == PCI_CLASS_BRIDGE_PCI )
285         {
286            pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS,    &buspri);
287            pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS,  &bussec);
288
289#if 0
290            printk("pci : Found bridge at %d:%d, mybus %d, pribus %d, secbus %d  ", pbus, pslot, mybus, buspri, bussec );
291#endif
292            if( bussec == mybus )
293            {
294#if 0
295               printk("match\n");
296#endif
297               /* found our nearest bridge going towards the root */
298               pb->bus = pbus;
299               pb->slot = pslot;
300
301               return 0;
302            }
303#if 0
304            printk("no match\n");
305#endif
306         }
307
308      }
309   }
310   return -1;
311}
312
313void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
314{
315   unsigned char        cvalue;
316   uint16_t             devid;
317   int                  ismatch, i, j, pbus, pslot, int_pin, int_name;
318
319   /*
320   ** If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
321   ** INTERRUPT_NAME if one isn't already in place.  Then, drivers can
322   ** trivially use INTERRUPT_NAME to hook up with devices.
323   */
324
325   for(pbus=0; pbus< BusCountPCI(); pbus++)
326   {
327      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
328      {
329         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
330         if( devid == 0xffff ) continue;
331
332         /* got a device */
333
334         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_PIN, &cvalue);
335         int_pin = cvalue;
336
337         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_LINE, &cvalue);
338         int_name = cvalue;
339
340/* printk("pci : device %d:%02x devid %04x, intpin %d, intline  %d\n", pbus, pslot, devid, int_pin, int_name ); */
341
342         if( int_pin > 0 )
343         {
344            ismatch = 0;
345
346            /*
347            ** first run thru the bspmap table and see if we have an explicit configuration
348            */
349            for(i=0; bspmap[i].bus > -1; i++)
350            {
351               if( bspmap[i].bus == pbus && bspmap[i].slot == pslot )
352               {
353                  ismatch = -1;
354                  /* we have a record in the table that gives specific
355                   * pins and interrupts for devices in this slot */
356                  if( int_name == 255 )
357                  {
358                     /* find the vector associated with whatever pin the device gives us */
359                     for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
360                     {
361                        if( bspmap[i].pin_route[j].pin == int_pin )
362                        {
363                           int_name = bspmap[i].pin_route[j].int_name[0];
364                           break;
365                        }
366                     }
367                     if( int_name == -1 )
368                     {
369                        printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %d to an interrupt_line.\n", pbus, pslot, int_pin );
370                     }
371                     else
372                     {
373                        PRINT_MSG();
374                        pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
375                     }
376                  }
377                  else
378                  {
379                     test_intname( &bspmap[i],pbus,pslot,int_pin,int_name);
380                  }
381                  break;
382               }
383            }
384
385            if( !ismatch )
386            {
387               /*
388               ** no match, which means we're on a bus someplace.  Work
389               ** backwards from it to one of our defined busses,
390               ** swizzling thru each bridge on the way.
391               */
392
393               /* keep pbus, pslot pointed to the device being
394               configured while we track down the bridges using
395               tbus,tslot.  We keep searching the routing table because
396               we may end up finding our bridge in it */
397
398               int tbus= pbus, tslot= pslot;
399
400               for(;;)
401               {
402
403                  for(i=0; bspmap[i].bus > -1; i++)
404                  {
405                     if( bspmap[i].bus == tbus && (bspmap[i].slot == tslot || bspmap[i].slot == -1) )
406                     {
407                        ismatch = -1;
408                        /* found a record for this bus, so swizzle the
409                         * int_pin which we then use to find the
410                         * interrupt_name.
411                         */
412
413                        if( int_name == 255 )
414                        {
415                           /*
416                           ** FIXME.  I can't believe this little hack
417                           ** is right.  It does not yield an error in
418                           ** convienently simple situations.
419                           */
420                           if( tbus ) int_pin = (*swizzler)(tslot,int_pin);
421
422                           /*
423                           ** int_pin points to the interrupt channel
424                           ** this card ends up delivering interrupts
425                           ** on.  Find the int_name servicing it.
426                           */
427                           for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
428                           {
429                              if( bspmap[i].pin_route[j].pin == int_pin )
430                              {
431                                 int_name = bspmap[i].pin_route[j].int_name[0];
432                                 break;
433                              }
434                           }
435                           if( int_name == -1 )
436                           {
437                              printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %d to an interrupt_line.\n", pbus, pslot, int_pin );
438                           }
439                           else
440                           {
441                              PRINT_MSG();
442                              pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
443                           }
444                        }
445                        else
446                        {
447                           test_intname(&bspmap[i],pbus,pslot,int_pin,int_name);
448                        }
449                        goto donesearch;
450                     }
451                  }
452
453                  if( !ismatch )
454                  {
455                     struct pcibridge   pb;
456
457                     /*
458                     ** Haven't found our bus in the int map, so work
459                     ** upwards thru the bridges till we find it.
460                     */
461
462                     if( FindPCIbridge( tbus, &pb )== 0 )
463                     {
464                        int_pin = (*swizzler)(tslot,int_pin);
465
466                        /* our next bridge up is on pb.bus, pb.slot- now
467                        ** instead of pointing to the device we're
468                        ** trying to configure, we move from bridge to
469                        ** bridge.
470                        */
471
472                        tbus = pb.bus;
473                        tslot = pb.slot;
474                     }
475                     else
476                     {
477                        printk("pci : No bridge from bus %d towards root found\n", tbus );
478                        goto donesearch;
479                     }
480
481                  }
482
483               }
484            }
485           donesearch:
486
487            if( !ismatch && int_pin != 0 && int_name == 255 )
488            {
489               printk("pci : Unable to match device %d:%d with an int routing table entry\n", pbus, pslot  );
490            }
491
492         }
493      }
494   }
495}
496
497/*
498 * This routine determines the maximum bus number in the system
499 */
500void InitializePCI()
501{
502  extern void detect_host_bridge();
503  unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
504  unsigned char ucHeader;
505  unsigned char ucMaxSubordinate;
506  unsigned int  ulClass, ulDeviceID;
507
508  detect_host_bridge();
509
510  /*
511   * Scan PCI bus 0 looking for PCI-PCI bridges
512   */
513  for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
514    (void)pci_read_config_dword(0,
515                                ucSlotNumber,
516                                0,
517                                PCI_VENDOR_ID,
518                                &ulDeviceID);
519    if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
520      /*
521       * This slot is empty
522       */
523      continue;
524    }
525    (void)pci_read_config_byte(0,
526                               ucSlotNumber,
527                               0,
528                               PCI_HEADER_TYPE,
529                               &ucHeader);
530    if(ucHeader&PCI_MULTI_FUNCTION)     {
531      ucNumFuncs=PCI_MAX_FUNCTIONS;
532    }
533    else {
534      ucNumFuncs=1;
535    }
536    for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
537      (void)pci_read_config_dword(0,
538                                  ucSlotNumber,
539                                  ucFnNumber,
540                                  PCI_VENDOR_ID,
541                                  &ulDeviceID);
542      if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
543                                /*
544                                 * This slot/function is empty
545                                 */
546        continue;
547      }
548
549      /*
550       * This slot/function has a device fitted.
551       */
552      (void)pci_read_config_dword(0,
553                                  ucSlotNumber,
554                                  ucFnNumber,
555                                  PCI_CLASS_REVISION,
556                                  &ulClass);
557      ulClass >>= 16;
558      if (ulClass == PCI_CLASS_BRIDGE_PCI) {
559                                /*
560                                 * We have found a PCI-PCI bridge
561                                 */
562        (void)pci_read_config_byte(0,
563                                   ucSlotNumber,
564                                   ucFnNumber,
565                                   PCI_SUBORDINATE_BUS,
566                                   &ucMaxSubordinate);
567        if(ucMaxSubordinate>ucMaxPCIBus) {
568          ucMaxPCIBus=ucMaxSubordinate;
569        }
570      }
571    }
572  }
573}
574
575/*
576 * Return the number of PCI busses in the system
577 */
578unsigned char BusCountPCI()
579{
580  return(ucMaxPCIBus+1);
581}
Note: See TracBrowser for help on using the repository browser.