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
14/*
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.
19 */
20
21#include "etherboot.h"
22#include "pci.h"
23
24/*#define	DEBUG	1*/
25#define DEBUG	0
26
27#ifdef	CONFIG_PCI_DIRECT
28#define  PCIBIOS_SUCCESSFUL                0x00
29
30/*
31 * Functions for accessing PCI configuration space with type 1 accesses
32 */
33
34#define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
35
36int pcibios_read_config_byte(unsigned int bus, unsigned int device_fn,
37			       unsigned int where, unsigned char *value)
38{
39    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
40    *value = inb(0xCFC + (where&3));
41    return PCIBIOS_SUCCESSFUL;
42}
43
44int pcibios_read_config_word (unsigned int bus,
45    unsigned int device_fn, unsigned int where, unsigned short *value)
46{
47    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
48    *value = inw(0xCFC + (where&2));
49    return PCIBIOS_SUCCESSFUL;
50}
51
52int pcibios_read_config_dword (unsigned int bus, unsigned int device_fn,
53				 unsigned int where, unsigned int *value)
54{
55    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
56    *value = inl(0xCFC);
57    return PCIBIOS_SUCCESSFUL;
58}
59
60int pcibios_write_config_byte (unsigned int bus, unsigned int device_fn,
61				 unsigned int where, unsigned char value)
62{
63    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
64    outb(value, 0xCFC + (where&3));
65    return PCIBIOS_SUCCESSFUL;
66}
67
68int pcibios_write_config_word (unsigned int bus, unsigned int device_fn,
69				 unsigned int where, unsigned short value)
70{
71    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
72    outw(value, 0xCFC + (where&2));
73    return PCIBIOS_SUCCESSFUL;
74}
75
76int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value)
77{
78    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
79    outl(value, 0xCFC);
80    return PCIBIOS_SUCCESSFUL;
81}
82
83#undef CONFIG_CMD
84
85#else	 /* CONFIG_PCI_DIRECT  not defined */
86
87static struct {
88	unsigned long address;
89	unsigned short segment;
90} bios32_indirect = { 0, KERN_CODE_SEG };
91
92static long pcibios_entry;
93static struct {
94	unsigned long address;
95	unsigned short segment;
96} pci_indirect = { 0, KERN_CODE_SEG };
97
98static unsigned long bios32_service(unsigned long service)
99{
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;
105
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);
121
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;
132	}
133}
134
135int pcibios_read_config_byte(unsigned int bus,
136        unsigned int device_fn, unsigned int where, unsigned char *value)
137{
138        unsigned long ret;
139        unsigned long bx = (bus << 8) | device_fn;
140        unsigned long flags;
141
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;
160}
161
162int pcibios_read_config_word(unsigned int bus,
163        unsigned int device_fn, unsigned int where, unsigned short *value)
164{
165        unsigned long ret;
166        unsigned long bx = (bus << 8) | device_fn;
167        unsigned long flags;
168
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;
187}
188
189int pcibios_read_config_dword(unsigned int bus,
190        unsigned int device_fn, unsigned int where, unsigned int *value)
191{
192        unsigned long ret;
193        unsigned long bx = (bus << 8) | device_fn;
194        unsigned long flags;
195
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;
214}
215
216int pcibios_write_config_byte (unsigned int bus,
217	unsigned int device_fn, unsigned int where, unsigned char value)
218{
219	unsigned long ret;
220	unsigned long bx = (bus << 8) | device_fn;
221	unsigned long flags;
222
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;
241}
242
243int pcibios_write_config_word (unsigned int bus,
244	unsigned int device_fn, unsigned int where, unsigned short value)
245{
246	unsigned long ret;
247	unsigned long bx = (bus << 8) | device_fn;
248	unsigned long flags;
249
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;
268}
269
270int pcibios_write_config_dword (unsigned int bus,
271	unsigned int device_fn, unsigned int where, unsigned int value)
272{
273	unsigned long ret;
274	unsigned long bx = (bus << 8) | device_fn;
275	unsigned long flags;
276
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;
295}
296
297static void check_pcibios(void)
298{
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;
305
306	if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
307		pci_indirect.address = pcibios_entry;
308
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);
326
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;
334		}
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);
340		}
341#endif
342	}
343}
344
345static void pcibios_init(void)
346{
347	union bios32 *check;
348	unsigned char sum;
349	int i, length;
350	unsigned long bios32_entry = 0;
351
352	/*
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.
356	 *
357	 */
358
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;
374		}
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;
391			}
392		}
393	}
394	if (bios32_entry)
395		check_pcibios();
396}
397#endif	/* CONFIG_PCI_DIRECT not defined*/
398
399static void scan_bus(struct pci_device *pcidev)
400{
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;
407
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.
413	 */
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;
426			}
427			vendor = l & 0xffff;
428			device = (l >> 16) & 0xffff;
429
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);
442
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;
460					}
461				}
462			}
463		}
464	}
465}
466
467void eth_pci_init(struct pci_device *pcidev)
468{
469#ifndef	CONFIG_PCI_DIRECT
470	pcibios_init();
471	if (!pcibios_entry) {
472		printf("pci_init: no BIOS32 detected\n");
473		return;
474	}
475#endif
476	scan_bus(pcidev);
477	/* return values are in pcidev structures */
478}
479
480/*
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.
483 */
484void adjust_pci_device(struct pci_device *p)
485{
486	unsigned short	new_command, pci_command;
487	unsigned char	pci_latency;
488
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);
495	}
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);
500	}
501}
502