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

4.104.114.84.95
Last change on this file since 513b6c4b was 513b6c4b, checked in by Joel Sherrill <joel.sherrill@…>, on 09/27/04 at 21:44:10

2003-11-01 Greg Menke <gregory.menke@…>

PR 606/bsps

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