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

4.104.114.84.95
Last change on this file since da3b8d3 was da3b8d3, checked in by Joel Sherrill <joel.sherrill@…>, on Mar 5, 2004 at 6:09:14 PM

2004-03-05 Joel Sherrill <joel@…>

  • bootloader/pci.c: Remove warnings by adding include <string.h>.
  • irq/irq.c: Clean up includes to remove warnings.
  • pci/pci.c, pci/pci.h, startup/bspstart.c: Better use of const on struct _int_map.
  • 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.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 * 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(
240  const struct _int_map *row, int pbus, int pslot, int int_pin, int int_name )
241{
242   int j,k;
243   int _nopin= -1, _noname= -1;
244
245   for(j=0; row->pin_route[j].pin > -1; j++)
246   {
247      if( row->pin_route[j].pin == int_pin ) 
248      {
249         _nopin = 0;
250         
251         for(k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ )
252         {
253            if( row->pin_route[j].int_name[k] == int_name ){ _noname=0; break; } 
254         }
255         break;
256      }
257   }
258
259   if( _nopin  ) 
260   {
261      printk("pci : Device %d:%02x supplied a bogus interrupt_pin %d\n", pbus, pslot, int_pin );
262      return -1;
263   }
264   else
265   {
266      if( _noname )
267         printk("pci : Device %d:%02x supplied a suspicious interrupt_line %d, using it anyway\n", pbus, pslot, int_name );
268   }
269   return 0;
270}
271
272
273
274
275
276struct pcibridge
277{
278      int bus,slot;
279};
280
281
282static int FindPCIbridge( int mybus, struct pcibridge *pb )
283{
284   int          pbus, pslot;
285   unsigned8    bussec, buspri;
286   unsigned16   devid, vendorid, dclass;
287
288   for(pbus=0; pbus< BusCountPCI(); pbus++)
289   {
290      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
291      { 
292         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
293         if( devid == 0xffff ) continue;
294
295         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
296         if( vendorid == 0xffff ) continue;
297
298         pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
299
300         if( dclass == PCI_CLASS_BRIDGE_PCI ) 
301         {
302            pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS,    &buspri);
303            pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS,  &bussec);
304
305#if 0
306            printk("pci : Found bridge at %d:%d, mybus %d, pribus %d, secbus %d  ", pbus, pslot, mybus, buspri, bussec );
307#endif
308            if( bussec == mybus )
309            {
310#if 0
311               printk("match\n");
312#endif
313               /* found our nearest bridge going towards the root */
314               pb->bus = pbus;
315               pb->slot = pslot;
316
317               return 0;
318            }
319#if 0
320            printk("no match\n");
321#endif
322         }
323
324
325      }
326   }
327   return -1;
328}
329
330
331
332
333
334
335
336
337void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
338{
339   unsigned char        cvalue;
340   unsigned16           devid;
341   int                  ismatch, i, j, pbus, pslot, int_pin, int_name;
342
343   /*
344   ** If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
345   ** INTERRUPT_NAME if one isn't already in place.  Then, drivers can
346   ** trivially use INTERRUPT_NAME to hook up with devices.
347   */
348
349   for(pbus=0; pbus< BusCountPCI(); pbus++)
350   {
351      for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++)
352      { 
353         pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
354         if( devid == 0xffff ) continue;
355
356         /* got a device */
357
358         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_PIN, &cvalue);
359         int_pin = cvalue;
360
361         pci_read_config_byte( pbus, pslot, 0, PCI_INTERRUPT_LINE, &cvalue);
362         int_name = cvalue;
363
364/* printk("pci : device %d:%02x devid %04x, intpin %d, intline  %d\n", pbus, pslot, devid, int_pin, int_name ); */
365
366         if( int_pin > 0 )
367         {
368            ismatch = 0;
369
370            /*
371            ** first run thru the bspmap table and see if we have an explicit configuration
372            */
373            for(i=0; bspmap[i].bus > -1; i++)
374            {
375               if( bspmap[i].bus == pbus && bspmap[i].slot == pslot )
376               {
377                  ismatch = -1;
378                  /* we have a record in the table that gives specific
379                   * pins and interrupts for devices in this slot */
380                  if( int_name == 255 )
381                  {
382                     /* find the vector associated with whatever pin the device gives us */
383                     for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
384                     {
385                        if( bspmap[i].pin_route[j].pin == int_pin )
386                        {
387                           int_name = bspmap[i].pin_route[j].int_name[0];
388                           break;
389                        }
390                     }
391                     if( int_name == -1 )
392                     {
393                        printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %d to an interrupt_line.\n", pbus, pslot, int_pin );
394                     }
395                     else
396                     {
397                        PRINT_MSG();
398                        pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
399                     }
400                  }
401                  else
402                  {
403                     test_intname( &bspmap[i],pbus,pslot,int_pin,int_name);
404                  }
405                  break;
406               }
407            }
408
409           
410            if( !ismatch )
411            {
412               /*
413               ** no match, which means we're on a bus someplace.  Work
414               ** backwards from it to one of our defined busses,
415               ** swizzling thru each bridge on the way.
416               */
417
418               /* keep pbus, pslot pointed to the device being
419               configured while we track down the bridges using
420               tbus,tslot.  We keep searching the routing table because
421               we may end up finding our bridge in it */
422
423               int tbus= pbus, tslot= pslot;
424
425               for(;;)
426               {
427
428                  for(i=0; bspmap[i].bus > -1; i++)
429                  {
430                     if( bspmap[i].bus == tbus && (bspmap[i].slot == tslot || bspmap[i].slot == -1) )
431                     {
432                        ismatch = -1;
433                        /* found a record for this bus, so swizzle the
434                         * int_pin which we then use to find the
435                         * interrupt_name.
436                         */
437
438                        if( int_name == 255 )
439                        {
440                           /*
441                           ** FIXME.  I can't believe this little hack
442                           ** is right.  It does not yield an error in
443                           ** convienently simple situations.
444                           */
445                           if( tbus ) int_pin = (*swizzler)(tslot,int_pin);
446
447
448                           /*
449                           ** int_pin points to the interrupt channel
450                           ** this card ends up delivering interrupts
451                           ** on.  Find the int_name servicing it.
452                           */
453                           for( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ )
454                           {
455                              if( bspmap[i].pin_route[j].pin == int_pin )
456                              {
457                                 int_name = bspmap[i].pin_route[j].int_name[0];
458                                 break;
459                              }
460                           }
461                           if( int_name == -1 )
462                           {
463                              printk("pci : Unable to resolve device %d:%d w/ swizzled int pin %d to an interrupt_line.\n", pbus, pslot, int_pin );
464                           }
465                           else
466                           {
467                              PRINT_MSG();
468                              pci_write_config_byte(pbus,pslot,0,PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
469                           }
470                        }
471                        else
472                        {
473                           test_intname(&bspmap[i],pbus,pslot,int_pin,int_name);
474                        }
475                        goto donesearch;
476                     }
477                  }
478
479
480                  if( !ismatch )
481                  {
482                     struct pcibridge   pb;
483
484                     /*
485                     ** Haven't found our bus in the int map, so work
486                     ** upwards thru the bridges till we find it.
487                     */
488
489                     if( FindPCIbridge( tbus, &pb )== 0 )
490                     {
491                        int_pin = (*swizzler)(tslot,int_pin);
492
493                        /* our next bridge up is on pb.bus, pb.slot- now
494                        ** instead of pointing to the device we're
495                        ** trying to configure, we move from bridge to
496                        ** bridge.
497                        */
498
499                        tbus = pb.bus;
500                        tslot = pb.slot;
501                     }
502                     else
503                     {
504                        printk("pci : No bridge from bus %d towards root found\n", tbus );
505                        goto donesearch;
506                     }
507                     
508                  }
509
510               }
511            }
512           donesearch:
513
514
515            if( !ismatch && int_pin != 0 && int_name == 255 )
516            {
517               printk("pci : Unable to match device %d:%d with an int routing table entry\n", pbus, pslot  );
518            }
519
520
521         }
522      }
523   }
524}
525
526
527
528
529
530
531
532
533
534
535/*
536 * This routine determines the maximum bus number in the system
537 */
538void InitializePCI()
539{
540  extern void detect_host_bridge();
541  unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
542  unsigned char ucHeader;
543  unsigned char ucMaxSubordinate;
544  unsigned int  ulClass, ulDeviceID;
545
546  detect_host_bridge();
547
548  /*
549   * Scan PCI bus 0 looking for PCI-PCI bridges
550   */
551  for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
552    (void)pci_read_config_dword(0,
553                                ucSlotNumber,
554                                0,
555                                PCI_VENDOR_ID,
556                                &ulDeviceID);
557    if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
558      /*
559       * This slot is empty
560       */
561      continue;
562    }
563    (void)pci_read_config_byte(0,
564                               ucSlotNumber,
565                               0,
566                               PCI_HEADER_TYPE,
567                               &ucHeader);
568    if(ucHeader&PCI_MULTI_FUNCTION)     {
569      ucNumFuncs=PCI_MAX_FUNCTIONS;
570    }
571    else {
572      ucNumFuncs=1;
573    }
574    for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
575      (void)pci_read_config_dword(0,
576                                  ucSlotNumber,
577                                  ucFnNumber,
578                                  PCI_VENDOR_ID,
579                                  &ulDeviceID);
580      if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
581                                /*
582                                 * This slot/function is empty
583                                 */
584        continue;
585      }
586
587      /*
588       * This slot/function has a device fitted.
589       */
590      (void)pci_read_config_dword(0,
591                                  ucSlotNumber,
592                                  ucFnNumber,
593                                  PCI_CLASS_REVISION,
594                                  &ulClass);
595      ulClass >>= 16;
596      if (ulClass == PCI_CLASS_BRIDGE_PCI) {
597                                /*
598                                 * We have found a PCI-PCI bridge
599                                 */
600        (void)pci_read_config_byte(0,
601                                   ucSlotNumber,
602                                   ucFnNumber,
603                                   PCI_SUBORDINATE_BUS,
604                                   &ucMaxSubordinate);
605        if(ucMaxSubordinate>ucMaxPCIBus) {
606          ucMaxPCIBus=ucMaxSubordinate;
607        }
608      }
609    }
610  }
611}
612
613/*
614 * Return the number of PCI busses in the system
615 */
616unsigned char BusCountPCI()
617{
618  return(ucMaxPCIBus+1);
619}
Note: See TracBrowser for help on using the repository browser.