1 /*
2 ** Support for NE2000 PCI clones added David Monro June 1997
3 ** Generalised to other NICs by Ken Yap July 1997
4 **
5 ** Most of this is taken from:
6 **
7 ** /usr/src/linux/drivers/pci/pci.c
8 ** /usr/src/linux/include/linux/pci.h
9 ** /usr/src/linux/arch/i386/bios32.c
10 ** /usr/src/linux/include/linux/bios32.h
11 ** /usr/src/linux/drivers/net/ne.c
12 */
13 #define PCBIOS
14 #include "grub.h"
15 #include "pci.h"
16
17 #ifdef CONFIG_PCI_DIRECT
18 #define PCIBIOS_SUCCESSFUL 0x00
19
20 #define DEBUG 0
21
22 /*
23 * Functions for accessing PCI configuration space with type 1 accesses
24 */
25
26 #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
27
pcibios_read_config_byte(unsigned int bus,unsigned int device_fn,unsigned int where,uint8_t * value)28 int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,
29 unsigned int where, uint8_t *value)
30 {
31 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
32 *value = inb(0xCFC + (where&3));
33 return PCIBIOS_SUCCESSFUL;
34 }
35
pcibios_read_config_word(unsigned int bus,unsigned int device_fn,unsigned int where,uint16_t * value)36 int pcibios_read_config_word (unsigned int bus,
37 unsigned int device_fn, unsigned int where, uint16_t *value)
38 {
39 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
40 *value = inw(0xCFC + (where&2));
41 return PCIBIOS_SUCCESSFUL;
42 }
43
pcibios_read_config_dword(unsigned int bus,unsigned int device_fn,unsigned int where,uint32_t * value)44 int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,
45 unsigned int where, uint32_t *value)
46 {
47 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
48 *value = inl(0xCFC);
49 return PCIBIOS_SUCCESSFUL;
50 }
51
pcibios_write_config_byte(unsigned int bus,unsigned int device_fn,unsigned int where,uint8_t value)52 int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,
53 unsigned int where, uint8_t value)
54 {
55 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
56 outb(value, 0xCFC + (where&3));
57 return PCIBIOS_SUCCESSFUL;
58 }
59
pcibios_write_config_word(unsigned int bus,unsigned int device_fn,unsigned int where,uint16_t value)60 int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,
61 unsigned int where, uint16_t value)
62 {
63 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
64 outw(value, 0xCFC + (where&2));
65 return PCIBIOS_SUCCESSFUL;
66 }
67
pcibios_write_config_dword(unsigned int bus,unsigned int device_fn,unsigned int where,uint32_t value)68 int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, uint32_t value)
69 {
70 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
71 outl(value, 0xCFC);
72 return PCIBIOS_SUCCESSFUL;
73 }
74
75 #undef CONFIG_CMD
76
77 #else /* CONFIG_PCI_DIRECT not defined */
78
79 #if !defined(PCBIOS)
80 #error "The pcibios can only be used when the PCBIOS support is compiled in"
81 #endif
82
83
84 #define KERN_CODE_SEG 0X8
85 /* Stuff for asm */
86 #define save_flags(x) \
87 __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
88
89 #define cli() __asm__ __volatile__ ("cli": : :"memory")
90
91 #define restore_flags(x) \
92 __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
93
94
95
96 static struct {
97 unsigned long address;
98 unsigned short segment;
99 } bios32_indirect = { 0, KERN_CODE_SEG };
100
101 static long pcibios_entry = 0;
102 static struct {
103 unsigned long address;
104 unsigned short segment;
105 } pci_indirect = { 0, KERN_CODE_SEG };
106
bios32_service(unsigned long service)107 static unsigned long bios32_service(unsigned long service)
108 {
109 unsigned char return_code; /* %al */
110 unsigned long address; /* %ebx */
111 unsigned long length; /* %ecx */
112 unsigned long entry; /* %edx */
113 unsigned long flags;
114
115 save_flags(flags);
116 __asm__(
117 #ifdef ABSOLUTE_WITHOUT_ASTERISK
118 "lcall (%%edi)"
119 #else
120 "lcall *(%%edi)"
121 #endif
122 : "=a" (return_code),
123 "=b" (address),
124 "=c" (length),
125 "=d" (entry)
126 : "0" (service),
127 "1" (0),
128 "D" (&bios32_indirect));
129 restore_flags(flags);
130
131 switch (return_code) {
132 case 0:
133 return address + entry;
134 case 0x80: /* Not present */
135 printf("bios32_service(%d) : not present\n", service);
136 return 0;
137 default: /* Shouldn't happen */
138 printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n",
139 service, return_code);
140 return 0;
141 }
142 }
143
pcibios_read_config_byte(unsigned int bus,unsigned int device_fn,unsigned int where,uint8_t * value)144 int pcibios_read_config_byte(unsigned int bus,
145 unsigned int device_fn, unsigned int where, uint8_t *value)
146 {
147 unsigned long ret;
148 unsigned long bx = (bus << 8) | device_fn;
149 unsigned long flags;
150
151 save_flags(flags);
152 __asm__(
153 #ifdef ABSOLUTE_WITHOUT_ASTERISK
154 "lcall (%%esi)\n\t"
155 #else
156 "lcall *(%%esi)\n\t"
157 #endif
158 "jc 1f\n\t"
159 "xor %%ah, %%ah\n"
160 "1:"
161 : "=c" (*value),
162 "=a" (ret)
163 : "1" (PCIBIOS_READ_CONFIG_BYTE),
164 "b" (bx),
165 "D" ((long) where),
166 "S" (&pci_indirect));
167 restore_flags(flags);
168 return (int) (ret & 0xff00) >> 8;
169 }
170
pcibios_read_config_word(unsigned int bus,unsigned int device_fn,unsigned int where,uint16_t * value)171 int pcibios_read_config_word(unsigned int bus,
172 unsigned int device_fn, unsigned int where, uint16_t *value)
173 {
174 unsigned long ret;
175 unsigned long bx = (bus << 8) | device_fn;
176 unsigned long flags;
177
178 save_flags(flags);
179 __asm__(
180 #ifdef ABSOLUTE_WITHOUT_ASTERISK
181 "lcall (%%esi)\n\t"
182 #else
183 "lcall *(%%esi)\n\t"
184 #endif
185 "jc 1f\n\t"
186 "xor %%ah, %%ah\n"
187 "1:"
188 : "=c" (*value),
189 "=a" (ret)
190 : "1" (PCIBIOS_READ_CONFIG_WORD),
191 "b" (bx),
192 "D" ((long) where),
193 "S" (&pci_indirect));
194 restore_flags(flags);
195 return (int) (ret & 0xff00) >> 8;
196 }
197
pcibios_read_config_dword(unsigned int bus,unsigned int device_fn,unsigned int where,uint32_t * value)198 int pcibios_read_config_dword(unsigned int bus,
199 unsigned int device_fn, unsigned int where, uint32_t *value)
200 {
201 unsigned long ret;
202 unsigned long bx = (bus << 8) | device_fn;
203 unsigned long flags;
204
205 save_flags(flags);
206 __asm__(
207 #ifdef ABSOLUTE_WITHOUT_ASTERISK
208 "lcall (%%esi)\n\t"
209 #else
210 "lcall *(%%esi)\n\t"
211 #endif
212 "jc 1f\n\t"
213 "xor %%ah, %%ah\n"
214 "1:"
215 : "=c" (*value),
216 "=a" (ret)
217 : "1" (PCIBIOS_READ_CONFIG_DWORD),
218 "b" (bx),
219 "D" ((long) where),
220 "S" (&pci_indirect));
221 restore_flags(flags);
222 return (int) (ret & 0xff00) >> 8;
223 }
224
pcibios_write_config_byte(unsigned int bus,unsigned int device_fn,unsigned int where,uint8_t value)225 int pcibios_write_config_byte (unsigned int bus,
226 unsigned int device_fn, unsigned int where, uint8_t value)
227 {
228 unsigned long ret;
229 unsigned long bx = (bus << 8) | device_fn;
230 unsigned long flags;
231
232 save_flags(flags); cli();
233 __asm__(
234 #ifdef ABSOLUTE_WITHOUT_ASTERISK
235 "lcall (%%esi)\n\t"
236 #else
237 "lcall *(%%esi)\n\t"
238 #endif
239 "jc 1f\n\t"
240 "xor %%ah, %%ah\n"
241 "1:"
242 : "=a" (ret)
243 : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
244 "c" (value),
245 "b" (bx),
246 "D" ((long) where),
247 "S" (&pci_indirect));
248 restore_flags(flags);
249 return (int) (ret & 0xff00) >> 8;
250 }
251
pcibios_write_config_word(unsigned int bus,unsigned int device_fn,unsigned int where,uint16_t value)252 int pcibios_write_config_word (unsigned int bus,
253 unsigned int device_fn, unsigned int where, uint16_t value)
254 {
255 unsigned long ret;
256 unsigned long bx = (bus << 8) | device_fn;
257 unsigned long flags;
258
259 save_flags(flags); cli();
260 __asm__(
261 #ifdef ABSOLUTE_WITHOUT_ASTERISK
262 "lcall (%%esi)\n\t"
263 #else
264 "lcall *(%%esi)\n\t"
265 #endif
266 "jc 1f\n\t"
267 "xor %%ah, %%ah\n"
268 "1:"
269 : "=a" (ret)
270 : "0" (PCIBIOS_WRITE_CONFIG_WORD),
271 "c" (value),
272 "b" (bx),
273 "D" ((long) where),
274 "S" (&pci_indirect));
275 restore_flags(flags);
276 return (int) (ret & 0xff00) >> 8;
277 }
278
pcibios_write_config_dword(unsigned int bus,unsigned int device_fn,unsigned int where,uint32_t value)279 int pcibios_write_config_dword (unsigned int bus,
280 unsigned int device_fn, unsigned int where, uint32_t value)
281 {
282 unsigned long ret;
283 unsigned long bx = (bus << 8) | device_fn;
284 unsigned long flags;
285
286 save_flags(flags); cli();
287 __asm__(
288 #ifdef ABSOLUTE_WITHOUT_ASTERISK
289 "lcall (%%esi)\n\t"
290 #else
291 "lcall *(%%esi)\n\t"
292 #endif
293 "jc 1f\n\t"
294 "xor %%ah, %%ah\n"
295 "1:"
296 : "=a" (ret)
297 : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
298 "c" (value),
299 "b" (bx),
300 "D" ((long) where),
301 "S" (&pci_indirect));
302 restore_flags(flags);
303 return (int) (ret & 0xff00) >> 8;
304 }
305
check_pcibios(void)306 static void check_pcibios(void)
307 {
308 unsigned long signature;
309 unsigned char present_status;
310 unsigned char major_revision;
311 unsigned char minor_revision;
312 unsigned long flags;
313 int pack;
314
315 if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
316 pci_indirect.address = pcibios_entry;
317
318 save_flags(flags);
319 __asm__(
320 #ifdef ABSOLUTE_WITHOUT_ASTERISK
321 "lcall (%%edi)\n\t"
322 #else
323 "lcall *(%%edi)\n\t"
324 #endif
325 "jc 1f\n\t"
326 "xor %%ah, %%ah\n"
327 "1:\tshl $8, %%eax\n\t"
328 "movw %%bx, %%ax"
329 : "=d" (signature),
330 "=a" (pack)
331 : "1" (PCIBIOS_PCI_BIOS_PRESENT),
332 "D" (&pci_indirect)
333 : "bx", "cx");
334 restore_flags(flags);
335
336 present_status = (pack >> 16) & 0xff;
337 major_revision = (pack >> 8) & 0xff;
338 minor_revision = pack & 0xff;
339 if (present_status || (signature != PCI_SIGNATURE)) {
340 printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
341 "BIOS????\n");
342 pcibios_entry = 0;
343 }
344 #if DEBUG
345 if (pcibios_entry) {
346 printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
347 " entry at %#X\n", major_revision,
348 minor_revision, pcibios_entry);
349 }
350 #endif
351 }
352 }
353
pcibios_init(void)354 static void pcibios_init(void)
355 {
356 union bios32 *check;
357 unsigned char sum;
358 int i, length;
359 unsigned long bios32_entry = 0;
360
361 EnterFunction("pcibios_init");
362 /*
363 * Follow the standard procedure for locating the BIOS32 Service
364 * directory by scanning the permissible address range from
365 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
366 *
367 */
368
369 for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
370 if (check->fields.signature != BIOS32_SIGNATURE)
371 continue;
372 length = check->fields.length * 16;
373 if (!length)
374 continue;
375 sum = 0;
376 for (i = 0; i < length ; ++i)
377 sum += check->chars[i];
378 if (sum != 0)
379 continue;
380 if (check->fields.revision != 0) {
381 printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",
382 check->fields.revision, check);
383 continue;
384 }
385 #if DEBUG
386 printf("pcibios_init : BIOS32 Service Directory "
387 "structure at %#X\n", check);
388 #endif
389 if (!bios32_entry) {
390 if (check->fields.entry >= 0x100000) {
391 printf("pcibios_init: entry in high "
392 "memory, giving up\n");
393 return;
394 } else {
395 bios32_entry = check->fields.entry;
396 #if DEBUG
397 printf("pcibios_init : BIOS32 Service Directory"
398 " entry at %#X\n", bios32_entry);
399 #endif
400 bios32_indirect.address = bios32_entry;
401 }
402 }
403 }
404 if (bios32_entry)
405 check_pcibios();
406 LeaveFunction("pcibios_init");
407 }
408
409 #endif /* CONFIG_PCI_DIRECT not defined*/
410
pcibios_bus_base(unsigned int bus __unused)411 unsigned long pcibios_bus_base(unsigned int bus __unused)
412 {
413 /* architecturally this must be 0 */
414 return 0;
415 }
416
find_pci(int type,struct pci_device * dev)417 void find_pci(int type, struct pci_device *dev)
418 {
419 EnterFunction("find_pci");
420 #ifndef CONFIG_PCI_DIRECT
421 if (!pcibios_entry) {
422 pcibios_init();
423 }
424 if (!pcibios_entry) {
425 printf("pci_init: no BIOS32 detected\n");
426 return;
427 }
428 #endif
429 LeaveFunction("find_pci");
430 return scan_pci_bus(type, dev);
431 }
432