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

4.104.114.84.95
Last change on this file since a8b059cf was 6266abe, checked in by Jennifer Averett <Jennifer.Averett@…>, on 05/04/05 at 19:24:41

2005-05-04 Jennifer Averett <jennifer.averett@…>

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