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

Last change on this file since 12838559 was 12838559, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 13, 2003 at 5:40:41 PM

2003-06-13 Greg Menke <gregory.menke@…>

PR 405/bsps

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