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

5
Last change on this file since c3c57b1 was f770fcb, checked in by Joel Sherrill <joel@…>, on 03/03/16 at 16:36:24

Add shared PCI support and enhance pc386 to support non-legacy PCI configuration space

This patch fundamentally results from enhancements to the pc386 BSP
to support systems which do NOT have the legacy PCI BIOS. The
patch adds support for detecting when legacy PCI BIOS is not
present and then using IO space to access to PCI Configuration Space.
This resulted in dynamically selected between two implementations
of PCI and refactoring out the shared methods.

This patch adds shared implementations of pci_bus_count() and
pci_find_device(). Subsequent patches will remove implementations
of these methods in other BSPs where possible.

  • Property mode set to 100644
File size: 10.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
8#include <rtems.h>
9#include <bsp.h>
10#include <rtems/pci.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 */
18static int pcibInitialized = 0;
19static unsigned int pcibEntry;
20
21/*
22 * Array to pass data between c and __asm__ parts, at the time of
23 * writing I am not yet that familiar with extended __asm__ feature
24 * of gcc. This code is not on performance path, so we can care
25 * relatively little about performance here
26 */
27static volatile unsigned int pcibExchg[5];
28
29static int pcib_convert_err(int err);
30
31/** @brief
32 * Make device signature from bus number, device numebr and function
33 * number
34 */
35#define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
36
37/** @brief
38 * Extract valrous part from device signature
39 */
40#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
41#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
42#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
43
44/*
45 * Forward reference. Initialized at bottom.
46 */
47static const pci_config_access_functions pci_bios_indirect_functions;
48
49/* prototype before defining */
50const pci_config_access_functions *pci_bios_initialize(void);
51
52/*
53 * Detects presense of PCI BIOS, returns pointer to accessor methods.
54 */
55const pci_config_access_functions *pci_bios_initialize(void)
56{
57  unsigned char *ucp;
58  unsigned char  sum;
59  int            i;
60
61  pcibInitialized = 0;
62
63  /* First, we have to look for BIOS-32 */
64  for (ucp = (unsigned char *)0xE0000;
65       ucp < (unsigned char *)0xFFFFF;
66       ucp += 0x10) {
67    if (memcmp(ucp, "_32_", 4) != 0) {
68      continue;
69    }
70
71      /* Got signature, check length  */
72    if (*(ucp + 9) != 1) {
73      continue;
74    }
75
76    /* Verify checksum */
77    sum = 0;
78    for (i=0; i<16; i++) {
79      sum += *(ucp+i);
80    }
81
82    if (sum == 0) {
83      /* found */
84      break;
85    }
86  }
87
88  if (ucp >= (unsigned char *)0xFFFFF) {
89    /* BIOS-32 not found */
90    return NULL;
91  }
92
93  /* BIOS-32 found, let us find PCI BIOS */
94  ucp += 4;
95
96  pcibExchg[0] = *(unsigned int *)ucp;
97
98  __asm__ ("    pusha");                  /* Push all registers */
99  __asm__ ("    movl pcibExchg, %edi");   /* Move entry point to esi */
100  __asm__ ("    movl $0x49435024, %eax"); /* Move signature to eax */
101  __asm__ ("    xorl %ebx, %ebx");        /* Zero ebx */
102  __asm__ ("    pushl %cs");
103  __asm__ ("    call *%edi");             /* Call entry */
104  __asm__ ("    movl %eax, pcibExchg");
105  __asm__ ("    movl %ebx, pcibExchg+4");
106  __asm__ ("    movl %ecx, pcibExchg+8");
107  __asm__ ("    movl %edx, pcibExchg+12");
108  __asm__ ("    popa");
109
110  if ((pcibExchg[0] & 0xff) != 0) {
111    /* Not found */
112    return NULL;
113  }
114
115  /* Found PCI entry point */
116  pcibEntry = pcibExchg[1] + pcibExchg[3];
117
118  /* Let us check whether PCI bios is present */
119  pcibExchg[0] = pcibEntry;
120
121  __asm__ ("    pusha");
122  __asm__ ("    movl pcibExchg, %edi");
123  __asm__ ("    movb $0xb1, %ah");
124  __asm__ ("    movb $0x01, %al");
125  __asm__ ("    pushl %cs");
126  __asm__ ("    call *%edi");
127  __asm__ ("    movl %eax, pcibExchg");
128  __asm__ ("    movl %ebx, pcibExchg+4");
129  __asm__ ("    movl %ecx, pcibExchg+8");
130  __asm__ ("    movl %edx, pcibExchg+12");
131  __asm__ ("    popa");
132
133  if ((pcibExchg[0] & 0xff00) != 0) {
134    /* Not found */
135    return NULL;
136  }
137
138  if (pcibExchg[3] != 0x20494350) {
139    /* Signature does not match */
140    return NULL;
141  }
142
143  /* Success */
144  pcibInitialized = 1;
145
146  return &pci_bios_indirect_functions;
147}
148
149/*
150 * Read byte from config space
151 */
152static int
153pcib_conf_read8(int sig, int off, uint8_t *data)
154{
155  if (!pcibInitialized) {
156    return PCIB_ERR_UNINITIALIZED;
157  }
158
159  pcibExchg[0] = pcibEntry;
160  pcibExchg[1] = sig;
161  pcibExchg[2] = off;
162
163  __asm__ ("    pusha");
164  __asm__ ("    movl pcibExchg, %esi");
165  __asm__ ("    movb $0xb1, %ah");
166  __asm__ ("    movb $0x08, %al");
167  __asm__ ("    movl pcibExchg+4, %ebx");
168  __asm__ ("    movl pcibExchg+8, %edi");
169  __asm__ ("    pushl %cs");
170  __asm__ ("    call *%esi");
171  __asm__ ("    movl %eax, pcibExchg");
172  __asm__ ("    movl %ecx, pcibExchg+4");
173  __asm__ ("    popa");
174
175  if ((pcibExchg[0] & 0xff00) != 0) {
176    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
177  }
178
179  *data = (unsigned char)pcibExchg[1] & 0xff;
180
181  return PCIB_ERR_SUCCESS;
182}
183
184
185/*
186 * Read word from config space
187 */
188static int
189pcib_conf_read16(int sig, int off, uint16_t *data)
190{
191  if (!pcibInitialized) {
192    return PCIB_ERR_UNINITIALIZED;
193  }
194
195  pcibExchg[0] = pcibEntry;
196  pcibExchg[1] = sig;
197  pcibExchg[2] = off;
198
199  __asm__ ("    pusha");
200  __asm__ ("    movl pcibExchg, %esi");
201  __asm__ ("    movb $0xb1, %ah");
202  __asm__ ("    movb $0x09, %al");
203  __asm__ ("    movl pcibExchg+4, %ebx");
204  __asm__ ("    movl pcibExchg+8, %edi");
205  __asm__ ("    pushl %cs");
206  __asm__ ("    call *%esi");
207  __asm__ ("    movl %eax, pcibExchg");
208  __asm__ ("    movl %ecx, pcibExchg+4");
209  __asm__ ("    popa");
210
211  if ((pcibExchg[0] & 0xff00) != 0) {
212    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
213  }
214
215  *data = (unsigned short)pcibExchg[1] & 0xffff;
216
217  return PCIB_ERR_SUCCESS;
218}
219
220
221/*
222 * Read dword from config space
223 */
224static int
225pcib_conf_read32(int sig, int off, uint32_t *data)
226{
227  if (!pcibInitialized) {
228    return PCIB_ERR_UNINITIALIZED;
229  }
230
231  pcibExchg[0] = pcibEntry;
232  pcibExchg[1] = sig;
233  pcibExchg[2] = off;
234
235  __asm__ ("    pusha");
236  __asm__ ("    movl pcibExchg, %esi");
237  __asm__ ("    movb $0xb1, %ah");
238  __asm__ ("    movb $0x0a, %al");
239  __asm__ ("    movl pcibExchg+4, %ebx");
240  __asm__ ("    movl pcibExchg+8, %edi");
241  __asm__ ("    pushl %cs");
242  __asm__ ("    call *%esi");
243  __asm__ ("    movl %eax, pcibExchg");
244  __asm__ ("    movl %ecx, pcibExchg+4");
245  __asm__ ("    popa");
246
247  if ((pcibExchg[0] & 0xff00) != 0) {
248    return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
249  }
250
251  *data = (unsigned int)pcibExchg[1];
252
253  return PCIB_ERR_SUCCESS;
254}
255
256
257/*
258 * Write byte into  config space
259 */
260static int
261pcib_conf_write8(int sig, int off, uint8_t data)
262{
263  if (!pcibInitialized) {
264    return PCIB_ERR_UNINITIALIZED;
265  }
266
267  pcibExchg[0] = pcibEntry;
268  pcibExchg[1] = sig;
269  pcibExchg[2] = off;
270  pcibExchg[3] = data & 0xff;
271
272  __asm__ ("    pusha");
273  __asm__ ("    movl pcibExchg, %esi");
274  __asm__ ("    movb $0xb1, %ah");
275  __asm__ ("    movb $0x0b, %al");
276  __asm__ ("    movl pcibExchg+4, %ebx");
277  __asm__ ("    movl pcibExchg+8, %edi");
278  __asm__ ("    movl pcibExchg+12, %ecx");
279  __asm__ ("    pushl %cs");
280  __asm__ ("    call *%esi");
281  __asm__ ("    movl %eax, pcibExchg");
282  __asm__ ("    popa");
283
284  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
285}
286
287/*
288 * Write word into config space
289 */
290static int
291pcib_conf_write16(int sig, int off, uint16_t data)
292{
293  if (!pcibInitialized) {
294    return PCIB_ERR_UNINITIALIZED;
295  }
296
297  pcibExchg[0] = pcibEntry;
298  pcibExchg[1] = sig;
299  pcibExchg[2] = off;
300  pcibExchg[3] = data & 0xffff;
301
302  __asm__ ("    pusha");
303  __asm__ ("    movl pcibExchg, %esi");
304  __asm__ ("    movb $0xb1, %ah");
305  __asm__ ("    movb $0x0c, %al");
306  __asm__ ("    movl pcibExchg+4, %ebx");
307  __asm__ ("    movl pcibExchg+8, %edi");
308  __asm__ ("    movl pcibExchg+12, %ecx");
309  __asm__ ("    pushl %cs");
310  __asm__ ("    call *%esi");
311  __asm__ ("    movl %eax, pcibExchg");
312  __asm__ ("    popa");
313
314  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
315}
316
317
318
319/*
320 * Write dword into config space
321 */
322static int
323pcib_conf_write32(int sig, int off, uint32_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  pcibExchg[3] = data;
333
334  __asm__ ("    pusha");
335  __asm__ ("    movl pcibExchg, %esi");
336  __asm__ ("    movb $0xb1, %ah");
337  __asm__ ("    movb $0x0d, %al");
338  __asm__ ("    movl pcibExchg+4, %ebx");
339  __asm__ ("    movl pcibExchg+8, %edi");
340  __asm__ ("    movl pcibExchg+12, %ecx");
341  __asm__ ("    pushl %cs");
342  __asm__ ("    call *%esi");
343  __asm__ ("    movl %eax, pcibExchg");
344  __asm__ ("    popa");
345
346  return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
347}
348
349
350static int
351pcib_convert_err(int err)
352{
353  switch(err & 0xff){
354    case 0:
355      return PCIB_ERR_SUCCESS;
356    case 0x81:
357      return PCIB_ERR_NOFUNC;
358    case 0x83:
359      return PCIB_ERR_BADVENDOR;
360    case 0x86:
361      return PCIB_ERR_DEVNOTFOUND;
362    case 0x87:
363      return PCIB_ERR_BADREG;
364    default:
365      break;
366  }
367  return PCIB_ERR_NOFUNC;
368}
369
370static int
371BSP_pci_read_config_byte(
372  unsigned char bus,
373  unsigned char slot,
374  unsigned char fun,
375  unsigned char offset,
376  unsigned char *val
377)
378{
379  int sig;
380
381  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
382  pcib_conf_read8(sig, offset, val);
383  return PCIBIOS_SUCCESSFUL;
384}
385
386static int
387BSP_pci_read_config_word(
388  unsigned char bus,
389  unsigned char slot,
390  unsigned char fun,
391  unsigned char offset,
392  unsigned short *val
393)
394{
395  int sig;
396
397  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
398  pcib_conf_read16(sig, offset, val);
399  return PCIBIOS_SUCCESSFUL;
400}
401
402static int
403BSP_pci_read_config_dword(
404  unsigned char bus,
405  unsigned char slot,
406  unsigned char fun,
407  unsigned char offset,
408  uint32_t     *val
409)
410{
411  int sig;
412
413  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
414  pcib_conf_read32(sig, offset, val);
415  return PCIBIOS_SUCCESSFUL;
416}
417
418static int
419BSP_pci_write_config_byte(
420  unsigned char bus,
421  unsigned char slot,
422  unsigned char fun,
423  unsigned char offset,
424  unsigned char val
425)
426{
427  int sig;
428
429  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
430  pcib_conf_write8(sig, offset, val);
431  return PCIBIOS_SUCCESSFUL;
432}
433
434static int
435BSP_pci_write_config_word(
436  unsigned char bus,
437  unsigned char slot,
438  unsigned char fun,
439  unsigned char offset,
440  unsigned short val
441)
442{
443  int sig;
444
445  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
446  pcib_conf_write16(sig, offset, val);
447  return PCIBIOS_SUCCESSFUL;
448}
449
450static int
451BSP_pci_write_config_dword(
452  unsigned char bus,
453  unsigned char slot,
454  unsigned char fun,
455  unsigned char offset,
456  uint32_t      val
457)
458{
459  int sig;
460
461  sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
462  pcib_conf_write32(sig, offset, val);
463  return PCIBIOS_SUCCESSFUL;
464}
465
466static const pci_config_access_functions pci_bios_indirect_functions = {
467  BSP_pci_read_config_byte,
468  BSP_pci_read_config_word,
469  BSP_pci_read_config_dword,
470  BSP_pci_write_config_byte,
471  BSP_pci_write_config_word,
472  BSP_pci_write_config_dword
473};
Note: See TracBrowser for help on using the repository browser.