source: rtems/c/src/lib/libbsp/powerpc/shared/pci/pci.c @ 3605c4e

Last change on this file since 3605c4e was 3605c4e, checked in by Jennifer Averett <Jennifer.Averett@…>, on 08/05/03 at 19:54:27

2003-08-05 Till Strauman <strauman@…>

PR 437/bsps

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