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