source: rtems/c/src/lib/libbsp/i386/shared/pci/pcibios.c @ 2d5c486

4.115
Last change on this file since 2d5c486 was 2573e69, checked in by Till Strauman <strauman@…>, on 12/24/14 at 03:27:25

pc386: scan all functions of multi-function PCI devices

The current algorithm scans all PCI busses (0..ff)
and all devices (0..31) on each bus for bridges
and determines the maximum of all subordinate
busses encountered.

However, the algorithm does not scan all functions
present in multi-function devices -- I have a PCI express
root complex (82801H) where multiple (non-zero index)
functions are 'PCI bridges' whose subordinate bus number is
missed by the original algorithm.

This commit makes sure that the scan
is extended to all functions of multi-function
devices.

See #2067

  • Property mode set to 100644
File size: 13.9 KB
RevLine 
[0ebbf66]1/*
2 * This software is Copyright (C) 1998 by T.sqware - all rights limited
3 * It is provided in to the public domain "as is", can be freely modified
4 * as far as this copyight notice is kept unchanged, but does not imply
5 * an endorsement by T.sqware of the product in which it is included.
6 */
7
8#include <rtems.h>
9#include <bsp.h>
10#include <pcibios.h>
11
[6266abe]12#include <string.h>  /* memcpy */
[6ce94bc3]13
[0ebbf66]14/*
15 * This is simpliest possible PCI BIOS, it assumes that addressing
[6266abe]16 * is flat and that stack is big enough
17 */
[d7034e1]18
[0ebbf66]19
20static int pcibInitialized = 0;
21static unsigned int pcibEntry;
22
23/*
[00882105]24 * Array to pass data between c and __asm__ parts, at the time of
25 * writing I am not yet that familiar with extended __asm__ feature
[6266abe]26 * of gcc. This code is not on performance path, so we can care
27 * relatively little about performance here
[0ebbf66]28 */
29static volatile unsigned int pcibExchg[5];
30
31static int pcib_convert_err(int err);
32
33/*
[6266abe]34 * Detects presense of PCI BIOS, returns
[0ebbf66]35 * error code
36 */
[6266abe]37int
[bdc2572]38pci_initialize(void)
[0ebbf66]39{
40  unsigned char *ucp;
41  unsigned char sum;
42  int      i;
43
44  pcibInitialized = 0;
45
46  /* First, we have to look for BIOS-32 */
[6266abe]47  for (ucp = (unsigned char *)0xE0000;
48       ucp < (unsigned char *)0xFFFFF;
49       ucp += 0x10) {
50    if (memcmp(ucp, "_32_", 4) != 0) {
51      continue;
52    }
[0ebbf66]53
54      /* Got signature, check length  */
[6266abe]55    if (*(ucp + 9) != 1) {
56      continue;
[0ebbf66]57    }
58
[6266abe]59    /* Verify checksum */
60    sum = 0;
61    for (i=0; i<16; i++) {
62      sum += *(ucp+i);
63    }
64
65    if (sum == 0) {
66      /* found */
67      break;
[0ebbf66]68    }
[6266abe]69  }
70
71  if (ucp >= (unsigned char *)0xFFFFF) {
72    /* BIOS-32 not found */
73    return PCIB_ERR_NOTPRESENT;
74  }
[0ebbf66]75
76  /* BIOS-32 found, let us find PCI BIOS */
77  ucp += 4;
78
79  pcibExchg[0] = *(unsigned int *)ucp;
80
[00882105]81  __asm__ ("    pusha");                  /* Push all registers */
82  __asm__ ("    movl pcibExchg, %edi");   /* Move entry point to esi */
83  __asm__ ("    movl $0x49435024, %eax"); /* Move signature to eax */
84  __asm__ ("    xorl %ebx, %ebx");        /* Zero ebx */
85  __asm__ ("    pushl %cs");
86  __asm__ ("    call *%edi");             /* Call entry */
87  __asm__ ("    movl %eax, pcibExchg");
88  __asm__ ("    movl %ebx, pcibExchg+4");
89  __asm__ ("    movl %ecx, pcibExchg+8");
90  __asm__ ("    movl %edx, pcibExchg+12");
91  __asm__ ("    popa");
[0ebbf66]92
[6266abe]93  if ((pcibExchg[0] & 0xff) != 0) {
94    /* Not found */
95    return PCIB_ERR_NOTPRESENT;
96  }
[0ebbf66]97
98  /* Found PCI entry point */
99  pcibEntry = pcibExchg[1] + pcibExchg[3];
100
101  /* Let us check whether PCI bios is present */
102  pcibExchg[0] = pcibEntry;
[6266abe]103
[00882105]104  __asm__ ("    pusha");
105  __asm__ ("    movl pcibExchg, %edi");
106  __asm__ ("    movb $0xb1, %ah");
107  __asm__ ("    movb $0x01, %al");
108  __asm__ ("    pushl %cs");
109  __asm__ ("    call *%edi");
110  __asm__ ("    movl %eax, pcibExchg");
111  __asm__ ("    movl %ebx, pcibExchg+4");
112  __asm__ ("    movl %ecx, pcibExchg+8");
113  __asm__ ("    movl %edx, pcibExchg+12");
114  __asm__ ("    popa");
[0ebbf66]115
[6266abe]116  if ((pcibExchg[0] & 0xff00) != 0) {
117    /* Not found */
118    return PCIB_ERR_NOTPRESENT;
119  }
[0ebbf66]120
[6266abe]121  if (pcibExchg[3] != 0x20494350) {
122    /* Signature does not match */
123    return PCIB_ERR_NOTPRESENT;
124  }
[0ebbf66]125
126  /* Success */
[6266abe]127
[0ebbf66]128  pcibInitialized = 1;
129  return PCIB_ERR_SUCCESS;
130}
131
[6266abe]132/*
133 * Find specified device and return its signature: combination
[0ebbf66]134 * of bus number, device number and function number
135 */
[32f2304a]136static int
[0ebbf66]137pcib_find_by_devid(int vendorId, int devId, int idx, int *sig)
138{
[6266abe]139  if (!pcibInitialized) {
140    return PCIB_ERR_UNINITIALIZED;
141  }
[0ebbf66]142
143  pcibExchg[0] = pcibEntry;
144  pcibExchg[1] = vendorId;
145  pcibExchg[2] = devId;
146  pcibExchg[3] = idx;
147
[00882105]148  __asm__ ("    pusha");
149  __asm__ ("    movl pcibExchg, %edi");
150  __asm__ ("    movb $0xb1, %ah");
151  __asm__ ("    movb $0x02, %al");
152  __asm__ ("    movl pcibExchg+4, %edx");
153  __asm__ ("    movl pcibExchg+8, %ecx");
154  __asm__ ("    movl pcibExchg+12, %esi");
155  __asm__ ("    pushl %cs");
156  __asm__ ("    call *%edi");
157  __asm__ ("    movl %eax, pcibExchg");
158  __asm__ ("    movl %ebx, pcibExchg+4");
159  __asm__ ("    popa");
[0ebbf66]160
161  *sig = pcibExchg[1] & 0xffff;
162
163  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
164}
165
[c2701a0]166int
167pci_find_device(
168  unsigned short vendorid,
169  unsigned short deviceid,
170  int instance,
171  int *pbus,
172  int *pdev,
173  int *pfun
174)
175{
176  int status;
[a6e2293]177  int sig = 0;
[c2701a0]178
179  status = pcib_find_by_devid( vendorid, deviceid, instance, &sig );
180
181  *pbus = PCIB_DEVSIG_BUS(sig);
182  *pdev = PCIB_DEVSIG_DEV(sig);
183  *pfun = PCIB_DEVSIG_FUNC(sig);
[b365d4d]184  return status ? -1 : 0;
[c2701a0]185}
186
[6266abe]187/*
188 * Find specified class code return device signature: combination
[0ebbf66]189 * of bus number, device number and function number
190 */
191int
192pcib_find_by_class(int classCode, int idx, int *sig)
193{
[6266abe]194  if (!pcibInitialized) {
195    return PCIB_ERR_UNINITIALIZED;
196  }
[0ebbf66]197
198  pcibExchg[0] = pcibEntry;
199  pcibExchg[1] = classCode;
200  pcibExchg[2] = idx;
201
[00882105]202  __asm__ ("    pusha");
203  __asm__ ("    movl pcibExchg, %edi");
204  __asm__ ("    movb $0xb1, %ah");
205  __asm__ ("    movb $0x03, %al");
206  __asm__ ("    movl pcibExchg+4, %ecx");
207  __asm__ ("    movl pcibExchg+8, %esi");
208  __asm__ ("    pushl %cs");
209  __asm__ ("    call *%edi");
210  __asm__ ("    movl %eax, pcibExchg");
211  __asm__ ("    movl %ebx, pcibExchg+4");
212  __asm__ ("    popa");
[0ebbf66]213
[6266abe]214  if ((pcibExchg[0] & 0xff00) != 0) {
215    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
216  }
[0ebbf66]217
218  *sig = pcibExchg[1] & 0xffff;
219
220  return PCIB_ERR_SUCCESS;
221}
[6266abe]222
[718c36d]223static uint8_t ucBusCount = 0xff;
[d7034e1]224
[bdc2572]225unsigned char
[f9abe50]226pci_bus_count(void)
[d7034e1]227{
[6266abe]228  if ( ucBusCount == 0xff ) {
229    unsigned char bus;
230    unsigned char dev;
[2573e69]231    unsigned char fun;
232    unsigned char nfn;
[6266abe]233    unsigned char hd = 0;
[8149a2de]234    uint32_t d = 0;
[6266abe]235    int sig;
236
237    ucBusCount = 0;
238
239    for (bus=0; bus< 0xff; bus++) {
240      for (dev=0; dev<PCI_MAX_DEVICES; dev++) {
241        sig = PCIB_DEVSIG_MAKE(bus,dev,0);
242        pcib_conf_read32(sig, PCI_VENDOR_ID, &d);
243
[2573e69]244        if ( -1 == d ) {
245          continue;
246        }
247
248        pcib_conf_read8(sig, PCI_HEADER_TYPE, &hd);
249        nfn = (hd & 0x80) ? PCI_MAX_FUNCTIONS : 1;
250
251        for ( fun=0; fun<nfn; fun++ ) {
252
253          sig = PCIB_DEVSIG_MAKE(bus,dev,fun);
254          pcib_conf_read32(sig, PCI_VENDOR_ID, &d);
255          if ( -1 == d )
256            continue;
257
258          pcib_conf_read32(sig, PCI_CLASS_REVISION, &d);
259
260          if ( (d >> 16) == PCI_CLASS_BRIDGE_PCI ) {
261            pcib_conf_read8(sig, PCI_SUBORDINATE_BUS, &hd);
[6266abe]262
[2573e69]263            if ( hd > ucBusCount )
264              ucBusCount = hd;
265          }
[6266abe]266
267        }
[d7034e1]268      }
[6266abe]269    }
[d7034e1]270
[6266abe]271    if ( ucBusCount == 0 ) {
272      printk("pci_bus_count() found 0 busses, assuming 1\n");
273      ucBusCount = 1;
274    } else if ( ucBusCount == 0xff ) {
275      printk("pci_bus_count() found 0xff busses, assuming 1\n");
276      ucBusCount = 1;
277    }
278  }
[d7034e1]279
[6266abe]280  return ucBusCount;
[d7034e1]281}
282
[6266abe]283/*
[0ebbf66]284 * Generate Special Cycle
285 */
286int
287pcib_special_cycle(int busNo, int data)
288{
[6266abe]289  if (!pcibInitialized) {
290    return PCIB_ERR_UNINITIALIZED;
291  }
[0ebbf66]292
293  pcibExchg[0] = pcibEntry;
294  pcibExchg[1] = busNo << 8;
295  pcibExchg[2] = data;
296
[00882105]297  __asm__ ("    pusha");
298  __asm__ ("    movl pcibExchg, %edi");
299  __asm__ ("    movb $0xb1, %ah");
300  __asm__ ("    movb $0x06, %al");
301  __asm__ ("    movl pcibExchg+4, %ebx");
302  __asm__ ("    movl pcibExchg+8, %edx");
303  __asm__ ("    pushl %cs");
304  __asm__ ("    call *%edi");
305  __asm__ ("    movl %eax, pcibExchg");
306  __asm__ ("    movl %ebx, pcibExchg+4");
307  __asm__ ("    popa");
[0ebbf66]308
309  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
310}
311
[6266abe]312
313/*
[0ebbf66]314 * Read byte from config space
315 */
316int
[8149a2de]317pcib_conf_read8(int sig, int off, uint8_t *data)
[0ebbf66]318{
[6266abe]319  if (!pcibInitialized) {
320    return PCIB_ERR_UNINITIALIZED;
321  }
[0ebbf66]322
323  pcibExchg[0] = pcibEntry;
324  pcibExchg[1] = sig;
325  pcibExchg[2] = off;
326
[00882105]327  __asm__ ("    pusha");
328  __asm__ ("    movl pcibExchg, %esi");
329  __asm__ ("    movb $0xb1, %ah");
330  __asm__ ("    movb $0x08, %al");
331  __asm__ ("    movl pcibExchg+4, %ebx");
332  __asm__ ("    movl pcibExchg+8, %edi");
333  __asm__ ("    pushl %cs");
334  __asm__ ("    call *%esi");
335  __asm__ ("    movl %eax, pcibExchg");
336  __asm__ ("    movl %ecx, pcibExchg+4");
337  __asm__ ("    popa");
[0ebbf66]338
[6266abe]339  if ((pcibExchg[0] & 0xff00) != 0) {
340    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
341  }
[0ebbf66]342
343  *data = (unsigned char)pcibExchg[1] & 0xff;
344
345  return PCIB_ERR_SUCCESS;
346}
347
[6266abe]348
349/*
[0ebbf66]350 * Read word from config space
351 */
352int
[8149a2de]353pcib_conf_read16(int sig, int off, uint16_t *data)
[0ebbf66]354{
[6266abe]355  if (!pcibInitialized) {
356    return PCIB_ERR_UNINITIALIZED;
357  }
[0ebbf66]358
359  pcibExchg[0] = pcibEntry;
360  pcibExchg[1] = sig;
361  pcibExchg[2] = off;
362
[00882105]363  __asm__ ("    pusha");
364  __asm__ ("    movl pcibExchg, %esi");
365  __asm__ ("    movb $0xb1, %ah");
366  __asm__ ("    movb $0x09, %al");
367  __asm__ ("    movl pcibExchg+4, %ebx");
368  __asm__ ("    movl pcibExchg+8, %edi");
369  __asm__ ("    pushl %cs");
370  __asm__ ("    call *%esi");
371  __asm__ ("    movl %eax, pcibExchg");
372  __asm__ ("    movl %ecx, pcibExchg+4");
373  __asm__ ("    popa");
[0ebbf66]374
[6266abe]375  if ((pcibExchg[0] & 0xff00) != 0) {
376    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
377  }
[0ebbf66]378
379  *data = (unsigned short)pcibExchg[1] & 0xffff;
380
381  return PCIB_ERR_SUCCESS;
382}
383
[6266abe]384
385/*
[0ebbf66]386 * Read dword from config space
387 */
388int
[8149a2de]389pcib_conf_read32(int sig, int off, uint32_t *data)
[0ebbf66]390{
[6266abe]391  if (!pcibInitialized) {
392    return PCIB_ERR_UNINITIALIZED;
393  }
[0ebbf66]394
395  pcibExchg[0] = pcibEntry;
396  pcibExchg[1] = sig;
397  pcibExchg[2] = off;
398
[00882105]399  __asm__ ("    pusha");
400  __asm__ ("    movl pcibExchg, %esi");
401  __asm__ ("    movb $0xb1, %ah");
402  __asm__ ("    movb $0x0a, %al");
403  __asm__ ("    movl pcibExchg+4, %ebx");
404  __asm__ ("    movl pcibExchg+8, %edi");
405  __asm__ ("    pushl %cs");
406  __asm__ ("    call *%esi");
407  __asm__ ("    movl %eax, pcibExchg");
408  __asm__ ("    movl %ecx, pcibExchg+4");
409  __asm__ ("    popa");
[0ebbf66]410
[6266abe]411  if ((pcibExchg[0] & 0xff00) != 0) {
412    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
413  }
[0ebbf66]414
415  *data = (unsigned int)pcibExchg[1];
416
417  return PCIB_ERR_SUCCESS;
418}
419
[6266abe]420
421/*
[0ebbf66]422 * Write byte into  config space
423 */
424int
[8149a2de]425pcib_conf_write8(int sig, int off, uint8_t data)
[0ebbf66]426{
[6266abe]427  if (!pcibInitialized) {
428    return PCIB_ERR_UNINITIALIZED;
429  }
[0ebbf66]430
431  pcibExchg[0] = pcibEntry;
432  pcibExchg[1] = sig;
433  pcibExchg[2] = off;
434  pcibExchg[3] = data & 0xff;
435
[00882105]436  __asm__ ("    pusha");
437  __asm__ ("    movl pcibExchg, %esi");
438  __asm__ ("    movb $0xb1, %ah");
439  __asm__ ("    movb $0x0b, %al");
440  __asm__ ("    movl pcibExchg+4, %ebx");
441  __asm__ ("    movl pcibExchg+8, %edi");
442  __asm__ ("    movl pcibExchg+12, %ecx");
443  __asm__ ("    pushl %cs");
444  __asm__ ("    call *%esi");
445  __asm__ ("    movl %eax, pcibExchg");
446  __asm__ ("    popa");
[0ebbf66]447
448  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
449}
450
[6266abe]451/*
[0ebbf66]452 * Write word into config space
453 */
454int
[8149a2de]455pcib_conf_write16(int sig, int off, uint16_t data)
[0ebbf66]456{
[6266abe]457  if (!pcibInitialized) {
458    return PCIB_ERR_UNINITIALIZED;
459  }
[0ebbf66]460
461  pcibExchg[0] = pcibEntry;
462  pcibExchg[1] = sig;
463  pcibExchg[2] = off;
464  pcibExchg[3] = data & 0xffff;
465
[00882105]466  __asm__ ("    pusha");
467  __asm__ ("    movl pcibExchg, %esi");
468  __asm__ ("    movb $0xb1, %ah");
469  __asm__ ("    movb $0x0c, %al");
470  __asm__ ("    movl pcibExchg+4, %ebx");
471  __asm__ ("    movl pcibExchg+8, %edi");
472  __asm__ ("    movl pcibExchg+12, %ecx");
473  __asm__ ("    pushl %cs");
474  __asm__ ("    call *%esi");
475  __asm__ ("    movl %eax, pcibExchg");
476  __asm__ ("    popa");
[0ebbf66]477
478  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
479}
480
[d7034e1]481
[6266abe]482
483/*
[0ebbf66]484 * Write dword into config space
485 */
486int
[8149a2de]487pcib_conf_write32(int sig, int off, uint32_t data)
[0ebbf66]488{
[6266abe]489  if (!pcibInitialized){
[0ebbf66]490      return PCIB_ERR_UNINITIALIZED;
[6266abe]491  }
[0ebbf66]492
493  pcibExchg[0] = pcibEntry;
494  pcibExchg[1] = sig;
495  pcibExchg[2] = off;
496  pcibExchg[3] = data;
497
[00882105]498  __asm__ ("    pusha");
499  __asm__ ("    movl pcibExchg, %esi");
500  __asm__ ("    movb $0xb1, %ah");
501  __asm__ ("    movb $0x0d, %al");
502  __asm__ ("    movl pcibExchg+4, %ebx");
503  __asm__ ("    movl pcibExchg+8, %edi");
504  __asm__ ("    movl pcibExchg+12, %ecx");
505  __asm__ ("    pushl %cs");
506  __asm__ ("    call *%esi");
507  __asm__ ("    movl %eax, pcibExchg");
508  __asm__ ("    popa");
[0ebbf66]509
510  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
511}
[6266abe]512
[6128a4a]513
[0ebbf66]514static int
515pcib_convert_err(int err)
516{
[6266abe]517  switch(err & 0xff){
[0ebbf66]518    case 0:
519      return PCIB_ERR_SUCCESS;
520    case 0x81:
521      return PCIB_ERR_NOFUNC;
522    case 0x83:
523      return PCIB_ERR_BADVENDOR;
524    case 0x86:
525      return PCIB_ERR_DEVNOTFOUND;
526    case 0x87:
527      return PCIB_ERR_BADREG;
528    default:
529      break;
[6266abe]530  }
[0ebbf66]531  return PCIB_ERR_NOFUNC;
532}
[d7034e1]533
[6266abe]534static int
[60b728b5]535BSP_pci_read_config_byte(
[6266abe]536  unsigned char bus,
537  unsigned char slot,
538  unsigned char fun,
539  unsigned char offset,
540  unsigned char *val
[3495c57]541)
[6266abe]542{
543  int sig;
[d7034e1]544
[6266abe]545  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
546  pcib_conf_read8(sig, offset, val);
547  return PCIBIOS_SUCCESSFUL;
548}
[d7034e1]549
[6266abe]550static int
[60b728b5]551BSP_pci_read_config_word(
[6266abe]552  unsigned char bus,
553  unsigned char slot,
554  unsigned char fun,
555  unsigned char offset,
556  unsigned short *val
[3495c57]557)
[6266abe]558{
559  int sig;
[d7034e1]560
[6266abe]561  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
562  pcib_conf_read16(sig, offset, val);
563  return PCIBIOS_SUCCESSFUL;
564}
565
566static int
[60b728b5]567BSP_pci_read_config_dword(
[6266abe]568  unsigned char bus,
569  unsigned char slot,
570  unsigned char fun,
571  unsigned char offset,
[8149a2de]572  uint32_t     *val
[3495c57]573)
[6266abe]574{
575  int sig;
576
577  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
578  pcib_conf_read32(sig, offset, val);
579  return PCIBIOS_SUCCESSFUL;
580}
581
582static int
[60b728b5]583BSP_pci_write_config_byte(
[6266abe]584  unsigned char bus,
585  unsigned char slot,
586  unsigned char fun,
587  unsigned char offset,
588  unsigned char val
[3495c57]589)
[6266abe]590{
591  int sig;
592
593  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
594  pcib_conf_write8(sig, offset, val);
595  return PCIBIOS_SUCCESSFUL;
596}
597
598static int
[60b728b5]599BSP_pci_write_config_word(
[6266abe]600  unsigned char bus,
601  unsigned char slot,
602  unsigned char fun,
603  unsigned char offset,
604  unsigned short val
[3495c57]605)
[6266abe]606{
607  int sig;
608
609  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
610  pcib_conf_write16(sig, offset, val);
611  return PCIBIOS_SUCCESSFUL;
612}
613
614static int
[60b728b5]615BSP_pci_write_config_dword(
[6266abe]616  unsigned char bus,
617  unsigned char slot,
618  unsigned char fun,
619  unsigned char offset,
[8149a2de]620  uint32_t      val
[3495c57]621)
[6266abe]622{
623  int sig;
624
625  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
626  pcib_conf_write32(sig, offset, val);
627  return PCIBIOS_SUCCESSFUL;
628}
[d7034e1]629
[6266abe]630const pci_config_access_functions pci_indirect_functions = {
[60b728b5]631  BSP_pci_read_config_byte,
632  BSP_pci_read_config_word,
633  BSP_pci_read_config_dword,
634  BSP_pci_write_config_byte,
635  BSP_pci_write_config_word,
636  BSP_pci_write_config_dword
[6266abe]637};
638
[32c347d]639rtems_pci_config_t BSP_pci_configuration = {
[6266abe]640  (volatile unsigned char*)0,
641  (volatile unsigned char*)0,
642  &pci_indirect_functions
643};
Note: See TracBrowser for help on using the repository browser.