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

4.104.115
Last change on this file since 60b728b5 was 60b728b5, checked in by Ralf Corsepius <ralf.corsepius@…>, on 10/01/09 at 12:26:49

2009-10-01 Ralf Corsépius <ralf.corsepius@…>

PR 1445/BSPs

  • shared/pci/pcibios.c: Rename indirect_pci_* into BSP_pci_*.
  • Property mode set to 100644
File size: 13.3 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 ? -1 : 0;
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 uint8_t ucBusCount = 0xff;
228
229unsigned char
230pci_bus_count(void)
231{
232  if ( ucBusCount == 0xff ) {
233    unsigned char bus;
234    unsigned char dev;
235    unsigned char hd = 0;
236    uint32_t 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, rval;
277
278   rval = pcib_find_by_devid(vendorid, deviceid, instance, &sig);
279
280   if ( PCIB_ERR_SUCCESS == rval ) {
281                *pbus = PCIB_DEVSIG_BUS(sig);
282                *pdev = PCIB_DEVSIG_DEV(sig);
283                *pfun = PCIB_DEVSIG_FUNC(sig);
284   }
285
286   return rval;
287}
288
289/*
290 * Generate Special Cycle
291 */
292int
293pcib_special_cycle(int busNo, int data)
294{
295  if (!pcibInitialized) {
296    return PCIB_ERR_UNINITIALIZED;
297  }
298
299  pcibExchg[0] = pcibEntry;
300  pcibExchg[1] = busNo << 8;
301  pcibExchg[2] = data;
302
303  asm("    pusha");
304  asm("    movl pcibExchg, %edi");
305  asm("    movb $0xb1, %ah");
306  asm("    movb $0x06, %al");
307  asm("    movl pcibExchg+4, %ebx");
308  asm("    movl pcibExchg+8, %edx");
309  asm("    pushl %cs");
310  asm("    call *%edi");
311  asm("    movl %eax, pcibExchg");
312  asm("    movl %ebx, pcibExchg+4");
313  asm("    popa");
314
315  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
316}
317
318
319/*
320 * Read byte from config space
321 */
322int
323pcib_conf_read8(int sig, int off, uint8_t *data)
324{
325  if (!pcibInitialized) {
326    return PCIB_ERR_UNINITIALIZED;
327  }
328
329  pcibExchg[0] = pcibEntry;
330  pcibExchg[1] = sig;
331  pcibExchg[2] = off;
332
333  asm("    pusha");
334  asm("    movl pcibExchg, %esi");
335  asm("    movb $0xb1, %ah");
336  asm("    movb $0x08, %al");
337  asm("    movl pcibExchg+4, %ebx");
338  asm("    movl pcibExchg+8, %edi");
339  asm("    pushl %cs");
340  asm("    call *%esi");
341  asm("    movl %eax, pcibExchg");
342  asm("    movl %ecx, pcibExchg+4");
343  asm("    popa");
344
345  if ((pcibExchg[0] & 0xff00) != 0) {
346    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
347  }
348
349  *data = (unsigned char)pcibExchg[1] & 0xff;
350
351  return PCIB_ERR_SUCCESS;
352}
353
354
355/*
356 * Read word from config space
357 */
358int
359pcib_conf_read16(int sig, int off, uint16_t *data)
360{
361  if (!pcibInitialized) {
362    return PCIB_ERR_UNINITIALIZED;
363  }
364
365  pcibExchg[0] = pcibEntry;
366  pcibExchg[1] = sig;
367  pcibExchg[2] = off;
368
369  asm("    pusha");
370  asm("    movl pcibExchg, %esi");
371  asm("    movb $0xb1, %ah");
372  asm("    movb $0x09, %al");
373  asm("    movl pcibExchg+4, %ebx");
374  asm("    movl pcibExchg+8, %edi");
375  asm("    pushl %cs");
376  asm("    call *%esi");
377  asm("    movl %eax, pcibExchg");
378  asm("    movl %ecx, pcibExchg+4");
379  asm("    popa");
380
381  if ((pcibExchg[0] & 0xff00) != 0) {
382    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
383  }
384
385  *data = (unsigned short)pcibExchg[1] & 0xffff;
386
387  return PCIB_ERR_SUCCESS;
388}
389
390
391/*
392 * Read dword from config space
393 */
394int
395pcib_conf_read32(int sig, int off, uint32_t *data)
396{
397  if (!pcibInitialized) {
398    return PCIB_ERR_UNINITIALIZED;
399  }
400
401  pcibExchg[0] = pcibEntry;
402  pcibExchg[1] = sig;
403  pcibExchg[2] = off;
404
405  asm("    pusha");
406  asm("    movl pcibExchg, %esi");
407  asm("    movb $0xb1, %ah");
408  asm("    movb $0x0a, %al");
409  asm("    movl pcibExchg+4, %ebx");
410  asm("    movl pcibExchg+8, %edi");
411  asm("    pushl %cs");
412  asm("    call *%esi");
413  asm("    movl %eax, pcibExchg");
414  asm("    movl %ecx, pcibExchg+4");
415  asm("    popa");
416
417  if ((pcibExchg[0] & 0xff00) != 0) {
418    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
419  }
420
421  *data = (unsigned int)pcibExchg[1];
422
423  return PCIB_ERR_SUCCESS;
424}
425
426
427/*
428 * Write byte into  config space
429 */
430int
431pcib_conf_write8(int sig, int off, uint8_t data)
432{
433  if (!pcibInitialized) {
434    return PCIB_ERR_UNINITIALIZED;
435  }
436
437  pcibExchg[0] = pcibEntry;
438  pcibExchg[1] = sig;
439  pcibExchg[2] = off;
440  pcibExchg[3] = data & 0xff;
441
442  asm("    pusha");
443  asm("    movl pcibExchg, %esi");
444  asm("    movb $0xb1, %ah");
445  asm("    movb $0x0b, %al");
446  asm("    movl pcibExchg+4, %ebx");
447  asm("    movl pcibExchg+8, %edi");
448  asm("    movl pcibExchg+12, %ecx");
449  asm("    pushl %cs");
450  asm("    call *%esi");
451  asm("    movl %eax, pcibExchg");
452  asm("    popa");
453
454  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
455}
456
457/*
458 * Write word into config space
459 */
460int
461pcib_conf_write16(int sig, int off, uint16_t data)
462{
463  if (!pcibInitialized) {
464    return PCIB_ERR_UNINITIALIZED;
465  }
466
467  pcibExchg[0] = pcibEntry;
468  pcibExchg[1] = sig;
469  pcibExchg[2] = off;
470  pcibExchg[3] = data & 0xffff;
471
472  asm("    pusha");
473  asm("    movl pcibExchg, %esi");
474  asm("    movb $0xb1, %ah");
475  asm("    movb $0x0c, %al");
476  asm("    movl pcibExchg+4, %ebx");
477  asm("    movl pcibExchg+8, %edi");
478  asm("    movl pcibExchg+12, %ecx");
479  asm("    pushl %cs");
480  asm("    call *%esi");
481  asm("    movl %eax, pcibExchg");
482  asm("    popa");
483
484  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
485}
486
487
488
489/*
490 * Write dword into config space
491 */
492int
493pcib_conf_write32(int sig, int off, uint32_t data)
494{
495  if (!pcibInitialized){
496      return PCIB_ERR_UNINITIALIZED;
497  }
498
499  pcibExchg[0] = pcibEntry;
500  pcibExchg[1] = sig;
501  pcibExchg[2] = off;
502  pcibExchg[3] = data;
503
504  asm("    pusha");
505  asm("    movl pcibExchg, %esi");
506  asm("    movb $0xb1, %ah");
507  asm("    movb $0x0d, %al");
508  asm("    movl pcibExchg+4, %ebx");
509  asm("    movl pcibExchg+8, %edi");
510  asm("    movl pcibExchg+12, %ecx");
511  asm("    pushl %cs");
512  asm("    call *%esi");
513  asm("    movl %eax, pcibExchg");
514  asm("    popa");
515
516  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
517}
518
519
520static int
521pcib_convert_err(int err)
522{
523  switch(err & 0xff){
524    case 0:
525      return PCIB_ERR_SUCCESS;
526    case 0x81:
527      return PCIB_ERR_NOFUNC;
528    case 0x83:
529      return PCIB_ERR_BADVENDOR;
530    case 0x86:
531      return PCIB_ERR_DEVNOTFOUND;
532    case 0x87:
533      return PCIB_ERR_BADREG;
534    default:
535      break;
536  }
537  return PCIB_ERR_NOFUNC;
538}
539
540static int
541BSP_pci_read_config_byte(
542  unsigned char bus,
543  unsigned char slot,
544  unsigned char fun,
545  unsigned char offset,
546  unsigned char *val
547)
548{
549  int sig;
550
551  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
552  pcib_conf_read8(sig, offset, val);
553  return PCIBIOS_SUCCESSFUL;
554}
555
556static int
557BSP_pci_read_config_word(
558  unsigned char bus,
559  unsigned char slot,
560  unsigned char fun,
561  unsigned char offset,
562  unsigned short *val
563)
564{
565  int sig;
566
567  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
568  pcib_conf_read16(sig, offset, val);
569  return PCIBIOS_SUCCESSFUL;
570}
571
572static int
573BSP_pci_read_config_dword(
574  unsigned char bus,
575  unsigned char slot,
576  unsigned char fun,
577  unsigned char offset,
578  uint32_t     *val
579)
580{
581  int sig;
582
583  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
584  pcib_conf_read32(sig, offset, val);
585  return PCIBIOS_SUCCESSFUL;
586}
587
588static int
589BSP_pci_write_config_byte(
590  unsigned char bus,
591  unsigned char slot,
592  unsigned char fun,
593  unsigned char offset,
594  unsigned char val
595)
596{
597  int sig;
598
599  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
600  pcib_conf_write8(sig, offset, val);
601  return PCIBIOS_SUCCESSFUL;
602}
603
604static int
605BSP_pci_write_config_word(
606  unsigned char bus,
607  unsigned char slot,
608  unsigned char fun,
609  unsigned char offset,
610  unsigned short val
611)
612{
613  int sig;
614
615  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
616  pcib_conf_write16(sig, offset, val);
617  return PCIBIOS_SUCCESSFUL;
618}
619
620static int
621BSP_pci_write_config_dword(
622  unsigned char bus,
623  unsigned char slot,
624  unsigned char fun,
625  unsigned char offset,
626  uint32_t      val
627)
628{
629  int sig;
630
631  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
632  pcib_conf_write32(sig, offset, val);
633  return PCIBIOS_SUCCESSFUL;
634}
635
636const pci_config_access_functions pci_indirect_functions = {
637  BSP_pci_read_config_byte,
638  BSP_pci_read_config_word,
639  BSP_pci_read_config_dword,
640  BSP_pci_write_config_byte,
641  BSP_pci_write_config_word,
642  BSP_pci_write_config_dword
643};
644
645pci_config BSP_pci_configuration = {
646  (volatile unsigned char*)0,
647  (volatile unsigned char*)0,
648  &pci_indirect_functions
649};
Note: See TracBrowser for help on using the repository browser.