revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-pc / boot / grub / netboot / pci.c
blob471c85632e197b760161042031517ff0678e0ce8
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
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2, or (at
18 * your option) any later version.
21 #include "etherboot.h"
22 #include "pci.h"
24 /*#define DEBUG 1*/
25 #define DEBUG 0
27 #ifdef CONFIG_PCI_DIRECT
28 #define PCIBIOS_SUCCESSFUL 0x00
31 * Functions for accessing PCI configuration space with type 1 accesses
34 #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
36 int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,
37 unsigned int where, unsigned char *value)
39 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
40 *value = inb(0xCFC + (where&3));
41 return PCIBIOS_SUCCESSFUL;
44 int pcibios_read_config_word (unsigned int bus,
45 unsigned int device_fn, unsigned int where, unsigned short *value)
47 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
48 *value = inw(0xCFC + (where&2));
49 return PCIBIOS_SUCCESSFUL;
52 int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,
53 unsigned int where, unsigned int *value)
55 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
56 *value = inl(0xCFC);
57 return PCIBIOS_SUCCESSFUL;
60 int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,
61 unsigned int where, unsigned char value)
63 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
64 outb(value, 0xCFC + (where&3));
65 return PCIBIOS_SUCCESSFUL;
68 int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,
69 unsigned int where, unsigned short value)
71 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
72 outw(value, 0xCFC + (where&2));
73 return PCIBIOS_SUCCESSFUL;
76 int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value)
78 outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
79 outl(value, 0xCFC);
80 return PCIBIOS_SUCCESSFUL;
83 #undef CONFIG_CMD
85 #else /* CONFIG_PCI_DIRECT not defined */
87 static struct {
88 unsigned long address;
89 unsigned short segment;
90 } bios32_indirect = { 0, KERN_CODE_SEG };
92 static long pcibios_entry;
93 static struct {
94 unsigned long address;
95 unsigned short segment;
96 } pci_indirect = { 0, KERN_CODE_SEG };
98 static unsigned long bios32_service(unsigned long service)
100 unsigned char return_code; /* %al */
101 unsigned long address; /* %ebx */
102 unsigned long length; /* %ecx */
103 unsigned long entry; /* %edx */
104 unsigned long flags;
106 save_flags(flags);
107 __asm__(
108 #ifdef ABSOLUTE_WITHOUT_ASTERISK
109 "lcall (%%edi)"
110 #else
111 "lcall *(%%edi)"
112 #endif
113 : "=a" (return_code),
114 "=b" (address),
115 "=c" (length),
116 "=d" (entry)
117 : "0" (service),
118 "1" (0),
119 "D" (&bios32_indirect));
120 restore_flags(flags);
122 switch (return_code) {
123 case 0:
124 return address + entry;
125 case 0x80: /* Not present */
126 printf("bios32_service(%d) : not present\n", service);
127 return 0;
128 default: /* Shouldn't happen */
129 printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n",
130 service, return_code);
131 return 0;
135 int pcibios_read_config_byte(unsigned int bus,
136 unsigned int device_fn, unsigned int where, unsigned char *value)
138 unsigned long ret;
139 unsigned long bx = (bus << 8) | device_fn;
140 unsigned long flags;
142 save_flags(flags);
143 __asm__(
144 #ifdef ABSOLUTE_WITHOUT_ASTERISK
145 "lcall (%%esi)\n\t"
146 #else
147 "lcall *(%%esi)\n\t"
148 #endif
149 "jc 1f\n\t"
150 "xor %%ah, %%ah\n"
151 "1:"
152 : "=c" (*value),
153 "=a" (ret)
154 : "1" (PCIBIOS_READ_CONFIG_BYTE),
155 "b" (bx),
156 "D" ((long) where),
157 "S" (&pci_indirect));
158 restore_flags(flags);
159 return (int) (ret & 0xff00) >> 8;
162 int pcibios_read_config_word(unsigned int bus,
163 unsigned int device_fn, unsigned int where, unsigned short *value)
165 unsigned long ret;
166 unsigned long bx = (bus << 8) | device_fn;
167 unsigned long flags;
169 save_flags(flags);
170 __asm__(
171 #ifdef ABSOLUTE_WITHOUT_ASTERISK
172 "lcall (%%esi)\n\t"
173 #else
174 "lcall *(%%esi)\n\t"
175 #endif
176 "jc 1f\n\t"
177 "xor %%ah, %%ah\n"
178 "1:"
179 : "=c" (*value),
180 "=a" (ret)
181 : "1" (PCIBIOS_READ_CONFIG_WORD),
182 "b" (bx),
183 "D" ((long) where),
184 "S" (&pci_indirect));
185 restore_flags(flags);
186 return (int) (ret & 0xff00) >> 8;
189 int pcibios_read_config_dword(unsigned int bus,
190 unsigned int device_fn, unsigned int where, unsigned int *value)
192 unsigned long ret;
193 unsigned long bx = (bus << 8) | device_fn;
194 unsigned long flags;
196 save_flags(flags);
197 __asm__(
198 #ifdef ABSOLUTE_WITHOUT_ASTERISK
199 "lcall (%%esi)\n\t"
200 #else
201 "lcall *(%%esi)\n\t"
202 #endif
203 "jc 1f\n\t"
204 "xor %%ah, %%ah\n"
205 "1:"
206 : "=c" (*value),
207 "=a" (ret)
208 : "1" (PCIBIOS_READ_CONFIG_DWORD),
209 "b" (bx),
210 "D" ((long) where),
211 "S" (&pci_indirect));
212 restore_flags(flags);
213 return (int) (ret & 0xff00) >> 8;
216 int pcibios_write_config_byte (unsigned int bus,
217 unsigned int device_fn, unsigned int where, unsigned char value)
219 unsigned long ret;
220 unsigned long bx = (bus << 8) | device_fn;
221 unsigned long flags;
223 save_flags(flags); cli();
224 __asm__(
225 #ifdef ABSOLUTE_WITHOUT_ASTERISK
226 "lcall (%%esi)\n\t"
227 #else
228 "lcall *(%%esi)\n\t"
229 #endif
230 "jc 1f\n\t"
231 "xor %%ah, %%ah\n"
232 "1:"
233 : "=a" (ret)
234 : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
235 "c" (value),
236 "b" (bx),
237 "D" ((long) where),
238 "S" (&pci_indirect));
239 restore_flags(flags);
240 return (int) (ret & 0xff00) >> 8;
243 int pcibios_write_config_word (unsigned int bus,
244 unsigned int device_fn, unsigned int where, unsigned short value)
246 unsigned long ret;
247 unsigned long bx = (bus << 8) | device_fn;
248 unsigned long flags;
250 save_flags(flags); cli();
251 __asm__(
252 #ifdef ABSOLUTE_WITHOUT_ASTERISK
253 "lcall (%%esi)\n\t"
254 #else
255 "lcall *(%%esi)\n\t"
256 #endif
257 "jc 1f\n\t"
258 "xor %%ah, %%ah\n"
259 "1:"
260 : "=a" (ret)
261 : "0" (PCIBIOS_WRITE_CONFIG_WORD),
262 "c" (value),
263 "b" (bx),
264 "D" ((long) where),
265 "S" (&pci_indirect));
266 restore_flags(flags);
267 return (int) (ret & 0xff00) >> 8;
270 int pcibios_write_config_dword (unsigned int bus,
271 unsigned int device_fn, unsigned int where, unsigned int value)
273 unsigned long ret;
274 unsigned long bx = (bus << 8) | device_fn;
275 unsigned long flags;
277 save_flags(flags); cli();
278 __asm__(
279 #ifdef ABSOLUTE_WITHOUT_ASTERISK
280 "lcall (%%esi)\n\t"
281 #else
282 "lcall *(%%esi)\n\t"
283 #endif
284 "jc 1f\n\t"
285 "xor %%ah, %%ah\n"
286 "1:"
287 : "=a" (ret)
288 : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
289 "c" (value),
290 "b" (bx),
291 "D" ((long) where),
292 "S" (&pci_indirect));
293 restore_flags(flags);
294 return (int) (ret & 0xff00) >> 8;
297 static void check_pcibios(void)
299 unsigned long signature;
300 unsigned char present_status;
301 unsigned char major_revision;
302 unsigned char minor_revision;
303 unsigned long flags;
304 int pack;
306 if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
307 pci_indirect.address = pcibios_entry;
309 save_flags(flags);
310 __asm__(
311 #ifdef ABSOLUTE_WITHOUT_ASTERISK
312 "lcall (%%edi)\n\t"
313 #else
314 "lcall *(%%edi)\n\t"
315 #endif
316 "jc 1f\n\t"
317 "xor %%ah, %%ah\n"
318 "1:\tshl $8, %%eax\n\t"
319 "movw %%bx, %%ax"
320 : "=d" (signature),
321 "=a" (pack)
322 : "1" (PCIBIOS_PCI_BIOS_PRESENT),
323 "D" (&pci_indirect)
324 : "bx", "cx");
325 restore_flags(flags);
327 present_status = (pack >> 16) & 0xff;
328 major_revision = (pack >> 8) & 0xff;
329 minor_revision = pack & 0xff;
330 if (present_status || (signature != PCI_SIGNATURE)) {
331 printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
332 "BIOS????\n");
333 pcibios_entry = 0;
335 #if DEBUG
336 if (pcibios_entry) {
337 printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
338 " entry at %#X\n", major_revision,
339 minor_revision, pcibios_entry);
341 #endif
345 static void pcibios_init(void)
347 union bios32 *check;
348 unsigned char sum;
349 int i, length;
350 unsigned long bios32_entry = 0;
353 * Follow the standard procedure for locating the BIOS32 Service
354 * directory by scanning the permissible address range from
355 * 0xe0000 through 0xfffff for a valid BIOS32 structure.
359 for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) {
360 if (check->fields.signature != BIOS32_SIGNATURE)
361 continue;
362 length = check->fields.length * 16;
363 if (!length)
364 continue;
365 sum = 0;
366 for (i = 0; i < length ; ++i)
367 sum += check->chars[i];
368 if (sum != 0)
369 continue;
370 if (check->fields.revision != 0) {
371 printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",
372 check->fields.revision, check);
373 continue;
375 #if DEBUG
376 printf("pcibios_init : BIOS32 Service Directory "
377 "structure at %#X\n", check);
378 #endif
379 if (!bios32_entry) {
380 if (check->fields.entry >= 0x100000) {
381 printf("pcibios_init: entry in high "
382 "memory, giving up\n");
383 return;
384 } else {
385 bios32_entry = check->fields.entry;
386 #if DEBUG
387 printf("pcibios_init : BIOS32 Service Directory"
388 " entry at %#X\n", bios32_entry);
389 #endif
390 bios32_indirect.address = bios32_entry;
394 if (bios32_entry)
395 check_pcibios();
397 #endif /* CONFIG_PCI_DIRECT not defined*/
399 static void scan_bus(struct pci_device *pcidev)
401 unsigned int devfn, l, bus, buses;
402 unsigned char hdr_type = 0;
403 unsigned short vendor, device;
404 unsigned int membase, ioaddr, romaddr;
405 int i, reg;
406 unsigned int pci_ioaddr = 0;
408 /* Scan all PCI buses, until we find our card.
409 * We could be smart only scan the required busses but that
410 * is error prone, and tricky.
411 * By scanning all possible pci busses in order we should find
412 * our card eventually.
414 buses=256;
415 for (bus = 0; bus < buses; ++bus) {
416 for (devfn = 0; devfn < 0xff; ++devfn) {
417 if (PCI_FUNC (devfn) == 0)
418 pcibios_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
419 else if (!(hdr_type & 0x80)) /* not a multi-function device */
420 continue;
421 pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l);
422 /* some broken boards return 0 if a slot is empty: */
423 if (l == 0xffffffff || l == 0x00000000) {
424 hdr_type = 0;
425 continue;
427 vendor = l & 0xffff;
428 device = (l >> 16) & 0xffff;
430 #if DEBUG
431 printf("bus %hhX, function %hhX, vendor %hX, device %hX\n",
432 bus, devfn, vendor, device);
433 #endif
434 for (i = 0; pcidev[i].vendor != 0; i++) {
435 if (vendor != pcidev[i].vendor
436 || device != pcidev[i].dev_id)
437 continue;
438 pcidev[i].devfn = devfn;
439 pcidev[i].bus = bus;
440 for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
441 pcibios_read_config_dword(bus, devfn, reg, &ioaddr);
443 if ((ioaddr & PCI_BASE_ADDRESS_IO_MASK) == 0 || (ioaddr & PCI_BASE_ADDRESS_SPACE_IO) == 0)
444 continue;
445 /* Strip the I/O address out of the returned value */
446 ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
447 /* Get the memory base address */
448 pcibios_read_config_dword(bus, devfn,
449 PCI_BASE_ADDRESS_1, &membase);
450 /* Get the ROM base address */
451 pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
452 romaddr >>= 10;
453 printf("Found %s at %#hx, ROM address %#hx\n",
454 pcidev[i].name, ioaddr, romaddr);
455 /* Take the first one or the one that matches in boot ROM address */
456 if (pci_ioaddr == 0 || romaddr == ((unsigned long) rom.rom_segment << 4)) {
457 pcidev[i].membase = membase;
458 pcidev[i].ioaddr = ioaddr;
459 return;
467 void eth_pci_init(struct pci_device *pcidev)
469 #ifndef CONFIG_PCI_DIRECT
470 pcibios_init();
471 if (!pcibios_entry) {
472 printf("pci_init: no BIOS32 detected\n");
473 return;
475 #endif
476 scan_bus(pcidev);
477 /* return values are in pcidev structures */
481 * Set device to be a busmaster in case BIOS neglected to do so.
482 * Also adjust PCI latency timer to a reasonable value, 32.
484 void adjust_pci_device(struct pci_device *p)
486 unsigned short new_command, pci_command;
487 unsigned char pci_latency;
489 pcibios_read_config_word(p->bus, p->devfn, PCI_COMMAND, &pci_command);
490 new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
491 if (pci_command != new_command) {
492 printf("The PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n",
493 pci_command, new_command, p->bus, p->devfn);
494 pcibios_write_config_word(p->bus, p->devfn, PCI_COMMAND, new_command);
496 pcibios_read_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, &pci_latency);
497 if (pci_latency < 32) {
498 printf("PCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency);
499 pcibios_write_config_byte(p->bus, p->devfn, PCI_LATENCY_TIMER, 32);