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

Last change on this file since 364866d was 364866d, checked in by Joel Sherrill <joel@…>, on Mar 16, 2016 at 12:36:41 AM

pc386: Do not include rtems/pci.h from bsp.h. Add bsp/bspimpl.h

Start to migrate private symbols to bsp/bspimpl.h.

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