source: rtems/c/src/lib/libbsp/i386/shared/pci/pcibios.c @ 2573e69

4.115
Last change on this file since 2573e69 was 2573e69, checked in by Till Strauman <strauman@…>, on Dec 24, 2014 at 3:27:25 AM

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
Line 
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
12#include <string.h>  /* memcpy */
13
14/*
15 * This is simpliest possible PCI BIOS, it assumes that addressing
16 * is flat and that stack is big enough
17 */
18
19
20static int pcibInitialized = 0;
21static unsigned int pcibEntry;
22
23/*
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
26 * of gcc. This code is not on performance path, so we can care
27 * relatively little about performance here
28 */
29static volatile unsigned int pcibExchg[5];
30
31static int pcib_convert_err(int err);
32
33/*
34 * Detects presense of PCI BIOS, returns
35 * error code
36 */
37int
38pci_initialize(void)
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 */
47  for (ucp = (unsigned char *)0xE0000;
48       ucp < (unsigned char *)0xFFFFF;
49       ucp += 0x10) {
50    if (memcmp(ucp, "_32_", 4) != 0) {
51      continue;
52    }
53
54      /* Got signature, check length  */
55    if (*(ucp + 9) != 1) {
56      continue;
57    }
58
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;
68    }
69  }
70
71  if (ucp >= (unsigned char *)0xFFFFF) {
72    /* BIOS-32 not found */
73    return PCIB_ERR_NOTPRESENT;
74  }
75
76  /* BIOS-32 found, let us find PCI BIOS */
77  ucp += 4;
78
79  pcibExchg[0] = *(unsigned int *)ucp;
80
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");
92
93  if ((pcibExchg[0] & 0xff) != 0) {
94    /* Not found */
95    return PCIB_ERR_NOTPRESENT;
96  }
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;
103
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");
115
116  if ((pcibExchg[0] & 0xff00) != 0) {
117    /* Not found */
118    return PCIB_ERR_NOTPRESENT;
119  }
120
121  if (pcibExchg[3] != 0x20494350) {
122    /* Signature does not match */
123    return PCIB_ERR_NOTPRESENT;
124  }
125
126  /* Success */
127
128  pcibInitialized = 1;
129  return PCIB_ERR_SUCCESS;
130}
131
132/*
133 * Find specified device and return its signature: combination
134 * of bus number, device number and function number
135 */
136static int
137pcib_find_by_devid(int vendorId, int devId, int idx, int *sig)
138{
139  if (!pcibInitialized) {
140    return PCIB_ERR_UNINITIALIZED;
141  }
142
143  pcibExchg[0] = pcibEntry;
144  pcibExchg[1] = vendorId;
145  pcibExchg[2] = devId;
146  pcibExchg[3] = idx;
147
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");
160
161  *sig = pcibExchg[1] & 0xffff;
162
163  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
164}
165
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;
177  int sig = 0;
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);
184  return status ? -1 : 0;
185}
186
187/*
188 * Find specified class code return device signature: combination
189 * of bus number, device number and function number
190 */
191int
192pcib_find_by_class(int classCode, int idx, int *sig)
193{
194  if (!pcibInitialized) {
195    return PCIB_ERR_UNINITIALIZED;
196  }
197
198  pcibExchg[0] = pcibEntry;
199  pcibExchg[1] = classCode;
200  pcibExchg[2] = idx;
201
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");
213
214  if ((pcibExchg[0] & 0xff00) != 0) {
215    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
216  }
217
218  *sig = pcibExchg[1] & 0xffff;
219
220  return PCIB_ERR_SUCCESS;
221}
222
223static uint8_t ucBusCount = 0xff;
224
225unsigned char
226pci_bus_count(void)
227{
228  if ( ucBusCount == 0xff ) {
229    unsigned char bus;
230    unsigned char dev;
231    unsigned char fun;
232    unsigned char nfn;
233    unsigned char hd = 0;
234    uint32_t d = 0;
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
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);
262
263            if ( hd > ucBusCount )
264              ucBusCount = hd;
265          }
266
267        }
268      }
269    }
270
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  }
279
280  return ucBusCount;
281}
282
283/*
284 * Generate Special Cycle
285 */
286int
287pcib_special_cycle(int busNo, int data)
288{
289  if (!pcibInitialized) {
290    return PCIB_ERR_UNINITIALIZED;
291  }
292
293  pcibExchg[0] = pcibEntry;
294  pcibExchg[1] = busNo << 8;
295  pcibExchg[2] = data;
296
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");
308
309  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
310}
311
312
313/*
314 * Read byte from config space
315 */
316int
317pcib_conf_read8(int sig, int off, uint8_t *data)
318{
319  if (!pcibInitialized) {
320    return PCIB_ERR_UNINITIALIZED;
321  }
322
323  pcibExchg[0] = pcibEntry;
324  pcibExchg[1] = sig;
325  pcibExchg[2] = off;
326
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");
338
339  if ((pcibExchg[0] & 0xff00) != 0) {
340    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
341  }
342
343  *data = (unsigned char)pcibExchg[1] & 0xff;
344
345  return PCIB_ERR_SUCCESS;
346}
347
348
349/*
350 * Read word from config space
351 */
352int
353pcib_conf_read16(int sig, int off, uint16_t *data)
354{
355  if (!pcibInitialized) {
356    return PCIB_ERR_UNINITIALIZED;
357  }
358
359  pcibExchg[0] = pcibEntry;
360  pcibExchg[1] = sig;
361  pcibExchg[2] = off;
362
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");
374
375  if ((pcibExchg[0] & 0xff00) != 0) {
376    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
377  }
378
379  *data = (unsigned short)pcibExchg[1] & 0xffff;
380
381  return PCIB_ERR_SUCCESS;
382}
383
384
385/*
386 * Read dword from config space
387 */
388int
389pcib_conf_read32(int sig, int off, uint32_t *data)
390{
391  if (!pcibInitialized) {
392    return PCIB_ERR_UNINITIALIZED;
393  }
394
395  pcibExchg[0] = pcibEntry;
396  pcibExchg[1] = sig;
397  pcibExchg[2] = off;
398
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");
410
411  if ((pcibExchg[0] & 0xff00) != 0) {
412    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
413  }
414
415  *data = (unsigned int)pcibExchg[1];
416
417  return PCIB_ERR_SUCCESS;
418}
419
420
421/*
422 * Write byte into  config space
423 */
424int
425pcib_conf_write8(int sig, int off, uint8_t data)
426{
427  if (!pcibInitialized) {
428    return PCIB_ERR_UNINITIALIZED;
429  }
430
431  pcibExchg[0] = pcibEntry;
432  pcibExchg[1] = sig;
433  pcibExchg[2] = off;
434  pcibExchg[3] = data & 0xff;
435
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");
447
448  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
449}
450
451/*
452 * Write word into config space
453 */
454int
455pcib_conf_write16(int sig, int off, uint16_t data)
456{
457  if (!pcibInitialized) {
458    return PCIB_ERR_UNINITIALIZED;
459  }
460
461  pcibExchg[0] = pcibEntry;
462  pcibExchg[1] = sig;
463  pcibExchg[2] = off;
464  pcibExchg[3] = data & 0xffff;
465
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");
477
478  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
479}
480
481
482
483/*
484 * Write dword into config space
485 */
486int
487pcib_conf_write32(int sig, int off, uint32_t data)
488{
489  if (!pcibInitialized){
490      return PCIB_ERR_UNINITIALIZED;
491  }
492
493  pcibExchg[0] = pcibEntry;
494  pcibExchg[1] = sig;
495  pcibExchg[2] = off;
496  pcibExchg[3] = data;
497
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");
509
510  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
511}
512
513
514static int
515pcib_convert_err(int err)
516{
517  switch(err & 0xff){
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;
530  }
531  return PCIB_ERR_NOFUNC;
532}
533
534static int
535BSP_pci_read_config_byte(
536  unsigned char bus,
537  unsigned char slot,
538  unsigned char fun,
539  unsigned char offset,
540  unsigned char *val
541)
542{
543  int sig;
544
545  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
546  pcib_conf_read8(sig, offset, val);
547  return PCIBIOS_SUCCESSFUL;
548}
549
550static int
551BSP_pci_read_config_word(
552  unsigned char bus,
553  unsigned char slot,
554  unsigned char fun,
555  unsigned char offset,
556  unsigned short *val
557)
558{
559  int sig;
560
561  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
562  pcib_conf_read16(sig, offset, val);
563  return PCIBIOS_SUCCESSFUL;
564}
565
566static int
567BSP_pci_read_config_dword(
568  unsigned char bus,
569  unsigned char slot,
570  unsigned char fun,
571  unsigned char offset,
572  uint32_t     *val
573)
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
583BSP_pci_write_config_byte(
584  unsigned char bus,
585  unsigned char slot,
586  unsigned char fun,
587  unsigned char offset,
588  unsigned char val
589)
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
599BSP_pci_write_config_word(
600  unsigned char bus,
601  unsigned char slot,
602  unsigned char fun,
603  unsigned char offset,
604  unsigned short val
605)
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
615BSP_pci_write_config_dword(
616  unsigned char bus,
617  unsigned char slot,
618  unsigned char fun,
619  unsigned char offset,
620  uint32_t      val
621)
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}
629
630const pci_config_access_functions pci_indirect_functions = {
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
637};
638
639rtems_pci_config_t BSP_pci_configuration = {
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.