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