|
@@ -10,279 +10,202 @@
|
10
|
10
|
** /usr/src/linux/include/linux/bios32.h
|
11
|
11
|
** /usr/src/linux/drivers/net/ne.c
|
12
|
12
|
*/
|
13
|
|
-#ifdef CONFIG_PCI
|
14
|
13
|
#include "etherboot.h"
|
|
14
|
+#include "init.h"
|
15
|
15
|
#include "pci.h"
|
|
16
|
+#include "pci_io.h"
|
|
17
|
+#ifdef KEEP_IT_REAL
|
|
18
|
+#include "realmode.h"
|
|
19
|
+#endif
|
16
|
20
|
|
17
|
|
-#ifdef CONFIG_PCI_DIRECT
|
18
|
|
-#define PCIBIOS_SUCCESSFUL 0x00
|
|
21
|
+#define DEBUG_PCI_IO
|
19
|
22
|
|
20
|
|
-#define DEBUG 0
|
|
23
|
+#undef DBG
|
|
24
|
+#ifdef DEBUG_PCI_IO
|
|
25
|
+#define DBG(...) printf ( __VA_ARGS__ )
|
|
26
|
+#else
|
|
27
|
+#define DBG(...)
|
|
28
|
+#endif
|
21
|
29
|
|
22
|
|
-/*
|
23
|
|
- * Functions for accessing PCI configuration space with type 1 accesses
|
|
30
|
+/* Macros for direct PCI access */
|
|
31
|
+#define CONFIG_ADDRESS 0xcf8
|
|
32
|
+#define CONFIG_DATA 0xcfc
|
|
33
|
+#define CONFIG_CMD( pci, where ) \
|
|
34
|
+ ( 0x80000000 | (pci->busdevfn << 8) | (where & ~3) )
|
|
35
|
+
|
|
36
|
+/* Signatures for PCI BIOS */
|
|
37
|
+#define BIOS_SIG(a,b,c,d) ( ( a<<0 ) + ( b<<8 ) + ( c<<16 ) + ( d<<24 ) )
|
|
38
|
+#define PRINT_BIOS_SIG(x) ( (x) & 0xff ), ( ( (x)>>8 ) & 0xff ), \
|
|
39
|
+ ( ( (x)>>16 ) & 0xff ),( ( (x)>>24 ) & 0xff )
|
|
40
|
+#define BIOS32_SIGNATURE BIOS_SIG ( '_', '3', '2', '_' )
|
|
41
|
+#define PCI_SIGNATURE BIOS_SIG ( 'P', 'C', 'I', ' ' )
|
|
42
|
+#define PCI_SERVICE BIOS_SIG ( '$', 'P', 'C', 'I' )
|
|
43
|
+
|
|
44
|
+/* BIOS32 structure as found in PCI BIOS ROM */
|
|
45
|
+struct bios32 {
|
|
46
|
+ unsigned long signature; /* _32_ */
|
|
47
|
+ unsigned long entry; /* 32 bit physical address */
|
|
48
|
+ unsigned char revision; /* Revision level, 0 */
|
|
49
|
+ unsigned char length; /* Length in paragraphs */
|
|
50
|
+ unsigned char checksum; /* Should byte sum to zero */
|
|
51
|
+ unsigned char reserved[5]; /* Must be zero */
|
|
52
|
+};
|
|
53
|
+
|
|
54
|
+/* Values returned by BIOS32 service directory */
|
|
55
|
+#define BIOS32_SERVICE_PRESENT 0x00
|
|
56
|
+#define BIOS32_SERVICE_NOT_PRESENT 0x80
|
|
57
|
+#define CF ( 1 << 0 )
|
|
58
|
+
|
|
59
|
+/* PCI BIOS entry point */
|
|
60
|
+#ifndef KEEP_IT_REAL
|
|
61
|
+static unsigned long pcibios32_entry;
|
|
62
|
+#endif
|
|
63
|
+static int have_pcibios;
|
|
64
|
+
|
|
65
|
+/* Macro for calling a 32-bit entry point with flat physical
|
|
66
|
+ * addresses. Use in a statement such as
|
|
67
|
+ * __asm__ ( FLAT_FAR_CALL_ESI,
|
|
68
|
+ * : <output registers>
|
|
69
|
+ * : "S" ( entry_point ), <other input registers> );
|
24
|
70
|
*/
|
|
71
|
+#define FLAT_FAR_CALL_ESI "call _virt_to_phys\n\t" \
|
|
72
|
+ "pushl %%cs\n\t" \
|
|
73
|
+ "call *%%esi\n\t" \
|
|
74
|
+ "cli\n\t" \
|
|
75
|
+ "cld\n\t" \
|
|
76
|
+ "call _phys_to_virt\n\t"
|
25
|
77
|
|
26
|
|
-#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
|
|
78
|
+/*
|
|
79
|
+ * Functions for accessing PCI configuration space directly with type
|
|
80
|
+ * 1 accesses.
|
|
81
|
+ *
|
|
82
|
+ */
|
27
|
83
|
|
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;
|
|
84
|
+static inline int pcidirect_read_config_byte ( struct pci_device *pci,
|
|
85
|
+ unsigned int where,
|
|
86
|
+ uint8_t *value ) {
|
|
87
|
+ outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
|
|
88
|
+ *value = inb ( CONFIG_DATA + ( where & 3 ) );
|
|
89
|
+ return 0;
|
34
|
90
|
}
|
35
|
91
|
|
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;
|
|
92
|
+static inline int pcidirect_read_config_word ( struct pci_device *pci,
|
|
93
|
+ unsigned int where,
|
|
94
|
+ uint16_t *value ) {
|
|
95
|
+ outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
|
|
96
|
+ *value = inw ( CONFIG_DATA + ( where & 2 ) );
|
|
97
|
+ return 0;
|
42
|
98
|
}
|
43
|
99
|
|
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;
|
|
100
|
+static inline int pcidirect_read_config_dword ( struct pci_device *pci,
|
|
101
|
+ unsigned int where,
|
|
102
|
+ uint32_t *value ) {
|
|
103
|
+ outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
|
|
104
|
+ *value = inl ( CONFIG_DATA );
|
|
105
|
+ return 0;
|
50
|
106
|
}
|
51
|
107
|
|
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;
|
|
108
|
+static inline int pcidirect_write_config_byte ( struct pci_device *pci,
|
|
109
|
+ unsigned int where,
|
|
110
|
+ uint8_t value ) {
|
|
111
|
+ outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
|
|
112
|
+ outb ( value, CONFIG_DATA + ( where & 3 ) );
|
|
113
|
+ return 0;
|
58
|
114
|
}
|
59
|
115
|
|
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;
|
|
116
|
+static inline int pcidirect_write_config_word ( struct pci_device *pci,
|
|
117
|
+ unsigned int where,
|
|
118
|
+ uint16_t value ) {
|
|
119
|
+ outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
|
|
120
|
+ outw ( value, CONFIG_DATA + ( where & 2 ) );
|
|
121
|
+ return 0;
|
66
|
122
|
}
|
67
|
123
|
|
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;
|
|
124
|
+static inline int pcidirect_write_config_dword ( struct pci_device *pci,
|
|
125
|
+ unsigned int where,
|
|
126
|
+ uint32_t value ) {
|
|
127
|
+ outl ( CONFIG_CMD ( pci, where ), CONFIG_ADDRESS );
|
|
128
|
+ outl ( value, CONFIG_DATA );
|
|
129
|
+ return 0;
|
73
|
130
|
}
|
74
|
131
|
|
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
|
|
-/* Macro for calling the BIOS32 service. This replaces the old
|
84
|
|
- * bios32_call function. Use in a statement such as
|
85
|
|
- * __asm__ ( BIOS32_CALL,
|
86
|
|
- * : <output registers>
|
87
|
|
- * : "S" ( bios32_entry ), <other input registers> );
|
|
132
|
+/*
|
|
133
|
+ * Functions for accessing PCI configuration space directly via the
|
|
134
|
+ * PCI BIOS.
|
|
135
|
+ *
|
|
136
|
+ * Under -DKEEP_IT_REAL, we use INT 1A, otherwise we use the BIOS32
|
|
137
|
+ * interface.
|
88
|
138
|
*/
|
89
|
|
-#define BIOS32_CALL "call _virt_to_phys\n\t" \
|
90
|
|
- "pushl %%cs\n\t" \
|
91
|
|
- "call *%%esi\n\t" \
|
92
|
|
- "cli\n\t" \
|
93
|
|
- "cld\n\t" \
|
94
|
|
- "call _phys_to_virt\n\t"
|
95
|
|
-
|
96
|
|
-static unsigned long bios32_entry;
|
97
|
|
-static unsigned long pcibios_entry;
|
98
|
|
-
|
99
|
|
-static unsigned long bios32_service(unsigned long service)
|
100
|
|
-{
|
101
|
|
- unsigned char return_code; /* %al */
|
102
|
|
- unsigned long address; /* %ebx */
|
103
|
|
- unsigned long length; /* %ecx */
|
104
|
|
- unsigned long entry; /* %edx */
|
105
|
|
-
|
106
|
|
- __asm__(BIOS32_CALL
|
107
|
|
- : "=a" (return_code),
|
108
|
|
- "=b" (address),
|
109
|
|
- "=c" (length),
|
110
|
|
- "=d" (entry)
|
111
|
|
- : "0" (service),
|
112
|
|
- "1" (0),
|
113
|
|
- "S" (bios32_entry));
|
114
|
|
-
|
115
|
|
- switch (return_code) {
|
116
|
|
- case 0:
|
117
|
|
- return address + entry;
|
118
|
|
- case 0x80: /* Not present */
|
119
|
|
- printf("bios32_service(%d) : not present\n", service);
|
120
|
|
- return 0;
|
121
|
|
- default: /* Shouldn't happen */
|
122
|
|
- printf("bios32_service(%d) : returned %#X????\n",
|
123
|
|
- service, return_code);
|
124
|
|
- return 0;
|
125
|
|
- }
|
126
|
|
-}
|
127
|
|
-
|
128
|
|
-int pcibios_read_config_byte(unsigned int bus,
|
129
|
|
- unsigned int device_fn, unsigned int where, uint8_t *value)
|
130
|
|
-{
|
131
|
|
- unsigned long ret;
|
132
|
|
- unsigned long bx = (bus << 8) | device_fn;
|
133
|
|
-
|
134
|
|
- __asm__(BIOS32_CALL
|
135
|
|
- "jc 1f\n\t"
|
136
|
|
- "xor %%ah, %%ah\n"
|
137
|
|
- "1:"
|
138
|
|
- : "=c" (*value),
|
139
|
|
- "=a" (ret)
|
140
|
|
- : "1" (PCIBIOS_READ_CONFIG_BYTE),
|
141
|
|
- "b" (bx),
|
142
|
|
- "D" ((long) where),
|
143
|
|
- "S" (pcibios_entry));
|
144
|
|
- return (int) (ret & 0xff00) >> 8;
|
145
|
|
-}
|
146
|
|
-
|
147
|
|
-int pcibios_read_config_word(unsigned int bus,
|
148
|
|
- unsigned int device_fn, unsigned int where, uint16_t *value)
|
149
|
|
-{
|
150
|
|
- unsigned long ret;
|
151
|
|
- unsigned long bx = (bus << 8) | device_fn;
|
152
|
|
-
|
153
|
|
- __asm__(BIOS32_CALL
|
154
|
|
- "jc 1f\n\t"
|
155
|
|
- "xor %%ah, %%ah\n"
|
156
|
|
- "1:"
|
157
|
|
- : "=c" (*value),
|
158
|
|
- "=a" (ret)
|
159
|
|
- : "1" (PCIBIOS_READ_CONFIG_WORD),
|
160
|
|
- "b" (bx),
|
161
|
|
- "D" ((long) where),
|
162
|
|
- "S" (pcibios_entry));
|
163
|
|
- return (int) (ret & 0xff00) >> 8;
|
164
|
|
-}
|
165
|
139
|
|
166
|
|
-int pcibios_read_config_dword(unsigned int bus,
|
167
|
|
- unsigned int device_fn, unsigned int where, uint32_t *value)
|
168
|
|
-{
|
169
|
|
- unsigned long ret;
|
170
|
|
- unsigned long bx = (bus << 8) | device_fn;
|
171
|
|
-
|
172
|
|
- __asm__(BIOS32_CALL
|
173
|
|
- "jc 1f\n\t"
|
174
|
|
- "xor %%ah, %%ah\n"
|
175
|
|
- "1:"
|
176
|
|
- : "=c" (*value),
|
177
|
|
- "=a" (ret)
|
178
|
|
- : "1" (PCIBIOS_READ_CONFIG_DWORD),
|
179
|
|
- "b" (bx),
|
180
|
|
- "D" ((long) where),
|
181
|
|
- "S" (pcibios_entry));
|
182
|
|
- return (int) (ret & 0xff00) >> 8;
|
183
|
|
-}
|
184
|
|
-
|
185
|
|
-int pcibios_write_config_byte (unsigned int bus,
|
186
|
|
- unsigned int device_fn, unsigned int where, uint8_t value)
|
187
|
|
-{
|
188
|
|
- unsigned long ret;
|
189
|
|
- unsigned long bx = (bus << 8) | device_fn;
|
190
|
|
-
|
191
|
|
- __asm__(BIOS32_CALL
|
192
|
|
- "jc 1f\n\t"
|
193
|
|
- "xor %%ah, %%ah\n"
|
194
|
|
- "1:"
|
195
|
|
- : "=a" (ret)
|
196
|
|
- : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
|
197
|
|
- "c" (value),
|
198
|
|
- "b" (bx),
|
199
|
|
- "D" ((long) where),
|
200
|
|
- "S" (pcibios_entry));
|
201
|
|
- return (int) (ret & 0xff00) >> 8;
|
202
|
|
-}
|
203
|
|
-
|
204
|
|
-int pcibios_write_config_word (unsigned int bus,
|
205
|
|
- unsigned int device_fn, unsigned int where, uint16_t value)
|
206
|
|
-{
|
207
|
|
- unsigned long ret;
|
208
|
|
- unsigned long bx = (bus << 8) | device_fn;
|
209
|
|
-
|
210
|
|
- __asm__(BIOS32_CALL
|
211
|
|
- "jc 1f\n\t"
|
212
|
|
- "xor %%ah, %%ah\n"
|
213
|
|
- "1:"
|
214
|
|
- : "=a" (ret)
|
215
|
|
- : "0" (PCIBIOS_WRITE_CONFIG_WORD),
|
216
|
|
- "c" (value),
|
217
|
|
- "b" (bx),
|
218
|
|
- "D" ((long) where),
|
219
|
|
- "S" (pcibios_entry));
|
220
|
|
- return (int) (ret & 0xff00) >> 8;
|
221
|
|
-}
|
|
140
|
+#ifdef KEEP_IT_REAL
|
|
141
|
+
|
|
142
|
+static void find_pcibios16 ( void ) {
|
|
143
|
+ uint16_t present;
|
|
144
|
+ uint32_t signature;
|
|
145
|
+ uint16_t flags;
|
|
146
|
+ uint16_t revision;
|
|
147
|
+
|
|
148
|
+ /* PCI BIOS installation check */
|
|
149
|
+ REAL_EXEC ( rm_pcibios_check,
|
|
150
|
+ "int $0x1a\n\t"
|
|
151
|
+ "pushfw\n\t"
|
|
152
|
+ "popw %%cx\n\t",
|
|
153
|
+ 4,
|
|
154
|
+ OUT_CONSTRAINTS ( "=a" ( present ), "=b" ( revision ),
|
|
155
|
+ "=c" ( flags ), "=d" ( signature ) ),
|
|
156
|
+ IN_CONSTRAINTS ( "a" ( ( PCIBIOS_PCI_FUNCTION_ID << 8 ) +
|
|
157
|
+ PCIBIOS_PCI_BIOS_PRESENT ) ),
|
|
158
|
+ CLOBBER ( "esi", "edi", "ebp" ) );
|
|
159
|
+
|
|
160
|
+ if ( ( flags & CF ) ||
|
|
161
|
+ ( ( present >> 8 ) != 0 ) ||
|
|
162
|
+ ( signature != PCI_SIGNATURE ) ) {
|
|
163
|
+ DBG ( "PCI BIOS installation check failed\n" );
|
|
164
|
+ return;
|
|
165
|
+ }
|
222
|
166
|
|
223
|
|
-int pcibios_write_config_dword (unsigned int bus,
|
224
|
|
- unsigned int device_fn, unsigned int where, uint32_t value)
|
225
|
|
-{
|
226
|
|
- unsigned long ret;
|
227
|
|
- unsigned long bx = (bus << 8) | device_fn;
|
228
|
|
-
|
229
|
|
- __asm__(BIOS32_CALL
|
230
|
|
- "jc 1f\n\t"
|
231
|
|
- "xor %%ah, %%ah\n"
|
232
|
|
- "1:"
|
233
|
|
- : "=a" (ret)
|
234
|
|
- : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
|
235
|
|
- "c" (value),
|
236
|
|
- "b" (bx),
|
237
|
|
- "D" ((long) where),
|
238
|
|
- "S" (pcibios_entry));
|
239
|
|
- return (int) (ret & 0xff00) >> 8;
|
|
167
|
+ /* We have a PCI BIOS */
|
|
168
|
+ have_pcibios = 1;
|
|
169
|
+ return;
|
240
|
170
|
}
|
241
|
171
|
|
242
|
|
-static void check_pcibios(void)
|
243
|
|
-{
|
244
|
|
- unsigned long signature;
|
245
|
|
- unsigned char present_status;
|
246
|
|
- unsigned char major_revision;
|
247
|
|
- unsigned char minor_revision;
|
248
|
|
- int pack;
|
249
|
|
-
|
250
|
|
- if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
|
251
|
|
- __asm__(BIOS32_CALL
|
252
|
|
- "jc 1f\n\t"
|
253
|
|
- "xor %%ah, %%ah\n"
|
254
|
|
- "1:\tshl $8, %%eax\n\t"
|
255
|
|
- "movw %%bx, %%ax"
|
256
|
|
- : "=d" (signature),
|
257
|
|
- "=a" (pack)
|
258
|
|
- : "1" (PCIBIOS_PCI_BIOS_PRESENT),
|
259
|
|
- "S" (pcibios_entry)
|
260
|
|
- : "bx", "cx");
|
261
|
|
-
|
262
|
|
- present_status = (pack >> 16) & 0xff;
|
263
|
|
- major_revision = (pack >> 8) & 0xff;
|
264
|
|
- minor_revision = pack & 0xff;
|
265
|
|
- if (present_status || (signature != PCI_SIGNATURE)) {
|
266
|
|
- printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
|
267
|
|
- "BIOS????\n");
|
268
|
|
- pcibios_entry = 0;
|
269
|
|
- }
|
270
|
|
-#if DEBUG
|
271
|
|
- if (pcibios_entry) {
|
272
|
|
- printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
|
273
|
|
- " entry at %#X\n", major_revision,
|
274
|
|
- minor_revision, pcibios_entry);
|
275
|
|
- }
|
276
|
|
-#endif
|
277
|
|
- }
|
278
|
|
-}
|
|
172
|
+INIT_FN ( INIT_PCIBIOS, find_pcibios16, NULL, NULL );
|
|
173
|
+
|
|
174
|
+#define pcibios16_read_write( command, pci, where, value ) \
|
|
175
|
+ ( { \
|
|
176
|
+ uint32_t discard_b, discard_D; \
|
|
177
|
+ uint16_t ret; \
|
|
178
|
+ \
|
|
179
|
+ REAL_EXEC ( __FUNCTION__ , \
|
|
180
|
+ "int $0x1a\n\t" \
|
|
181
|
+ "jc 1f\n\t" \
|
|
182
|
+ "xorl %%eax, %%eax\n\t" \
|
|
183
|
+ "\n1:\n\t", \
|
|
184
|
+ 5, \
|
|
185
|
+ OUT_CONSTRAINTS ( "=a" ( ret ), \
|
|
186
|
+ "=b" ( discard_b ), \
|
|
187
|
+ "=c" ( value ), \
|
|
188
|
+ "=D" ( discard_D ) ), \
|
|
189
|
+ IN_CONSTRAINTS ( "a" ( command + \
|
|
190
|
+ ( PCIBIOS_PCI_FUNCTION_ID << 8 ) ), \
|
|
191
|
+ "b" ( pci->busdevfn ), \
|
|
192
|
+ "c" ( value ), \
|
|
193
|
+ "D" ( where ) ), \
|
|
194
|
+ CLOBBER ( "edx", "ebp" ) ); \
|
|
195
|
+ \
|
|
196
|
+ ( ret >> 8 ); \
|
|
197
|
+ } )
|
|
198
|
+#define pcibios_read_write pcibios16_read_write
|
|
199
|
+
|
|
200
|
+#else /* KEEP_IT_REAL */
|
279
|
201
|
|
280
|
|
-static void pcibios_init(void)
|
281
|
|
-{
|
282
|
|
- union bios32 *check;
|
283
|
|
- unsigned char sum;
|
284
|
|
- int i, length;
|
285
|
|
- bios32_entry = 0;
|
|
202
|
+/*
|
|
203
|
+ * Locate the BIOS32 service directory by scanning for a valid BIOS32
|
|
204
|
+ * structure
|
|
205
|
+ *
|
|
206
|
+ */
|
|
207
|
+static struct bios32 * find_bios32 ( void ) {
|
|
208
|
+ uint32_t address;
|
286
|
209
|
|
287
|
210
|
/*
|
288
|
211
|
* Follow the standard procedure for locating the BIOS32 Service
|
|
@@ -290,63 +213,231 @@ static void pcibios_init(void)
|
290
|
213
|
* 0xe0000 through 0xfffff for a valid BIOS32 structure.
|
291
|
214
|
*
|
292
|
215
|
*/
|
|
216
|
+ for ( address = 0xe0000 ; address < 0xffff0 ; address += 16 ) {
|
|
217
|
+ struct bios32 * candidate = phys_to_virt ( address );
|
|
218
|
+ unsigned int length, i;
|
|
219
|
+ unsigned char sum;
|
293
|
220
|
|
294
|
|
- for (check = phys_to_virt(0xe0000); (void *)check <= phys_to_virt(0xffff0); ++check) {
|
295
|
|
- if (check->fields.signature != BIOS32_SIGNATURE)
|
|
221
|
+ if ( candidate->signature != BIOS32_SIGNATURE )
|
296
|
222
|
continue;
|
297
|
|
- length = check->fields.length * 16;
|
298
|
|
- if (!length)
|
|
223
|
+
|
|
224
|
+ length = candidate->length * 16;
|
|
225
|
+ if ( ! length )
|
299
|
226
|
continue;
|
300
|
|
- sum = 0;
|
301
|
|
- for (i = 0; i < length ; ++i)
|
302
|
|
- sum += check->chars[i];
|
303
|
|
- if (sum != 0)
|
|
227
|
+
|
|
228
|
+ for ( sum = 0, i = 0 ; i < length ; i++ )
|
|
229
|
+ sum += ( ( char * ) candidate ) [i];
|
|
230
|
+ if ( sum != 0 )
|
304
|
231
|
continue;
|
305
|
|
- if (check->fields.revision != 0) {
|
306
|
|
- printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",
|
307
|
|
- check->fields.revision, check);
|
|
232
|
+
|
|
233
|
+ if ( candidate->revision != 0 ) {
|
|
234
|
+ DBG ( "unsupported BIOS32 revision %d at %#x\n",
|
|
235
|
+ candidate->revision, address );
|
308
|
236
|
continue;
|
309
|
237
|
}
|
310
|
|
-#if DEBUG
|
311
|
|
- printf("pcibios_init : BIOS32 Service Directory "
|
312
|
|
- "structure at %#X\n", check);
|
313
|
|
-#endif
|
314
|
|
- if (!bios32_entry) {
|
315
|
|
- if (check->fields.entry >= 0x100000) {
|
316
|
|
- printf("pcibios_init: entry in high "
|
317
|
|
- "memory, giving up\n");
|
318
|
|
- return;
|
319
|
|
- } else {
|
320
|
|
- bios32_entry = check->fields.entry;
|
321
|
|
-#if DEBUG
|
322
|
|
- printf("pcibios_init : BIOS32 Service Directory"
|
323
|
|
- " entry at %#X\n", bios32_entry);
|
324
|
|
-#endif
|
325
|
|
- }
|
326
|
|
- }
|
|
238
|
+
|
|
239
|
+ DBG ( "BIOS32 Service Directory structure at %#x\n", address );
|
|
240
|
+
|
|
241
|
+ return candidate;
|
327
|
242
|
}
|
328
|
|
- if (bios32_entry)
|
329
|
|
- check_pcibios();
|
|
243
|
+
|
|
244
|
+ return NULL;
|
330
|
245
|
}
|
331
|
|
-#endif /* CONFIG_PCI_DIRECT not defined*/
|
332
|
246
|
|
333
|
|
-unsigned long pcibios_bus_base(unsigned int bus __unused)
|
334
|
|
-{
|
335
|
|
- /* architecturally this must be 0 */
|
336
|
|
- return 0;
|
|
247
|
+/*
|
|
248
|
+ * Look up a service in the BIOS32 service directory
|
|
249
|
+ *
|
|
250
|
+ */
|
|
251
|
+static unsigned long find_bios32_service ( struct bios32 * bios32,
|
|
252
|
+ unsigned long service ) {
|
|
253
|
+ uint8_t return_code;
|
|
254
|
+ uint32_t address;
|
|
255
|
+ uint32_t length;
|
|
256
|
+ uint32_t entry;
|
|
257
|
+ uint32_t discard;
|
|
258
|
+
|
|
259
|
+ __asm__ ( FLAT_FAR_CALL_ESI
|
|
260
|
+ : "=a" ( return_code ), "=b" ( address ),
|
|
261
|
+ "=c" ( length ), "=d" ( entry ), "=S" ( discard )
|
|
262
|
+ : "a" ( service ), "b" ( 0 ), "S" ( bios32->entry )
|
|
263
|
+ : "edi", "ebp" );
|
|
264
|
+
|
|
265
|
+ switch ( return_code ) {
|
|
266
|
+ case BIOS32_SERVICE_PRESENT:
|
|
267
|
+ return ( address + entry );
|
|
268
|
+ case BIOS32_SERVICE_NOT_PRESENT:
|
|
269
|
+ DBG ( "BIOS32 service %c%c%c%c : not present\n",
|
|
270
|
+ PRINT_BIOS_SIG ( service ) );
|
|
271
|
+ return 0;
|
|
272
|
+ default: /* Shouldn't happen */
|
|
273
|
+ DBG ( "BIOS32 returned %#x for service %c%c%c%c!\n",
|
|
274
|
+ return_code, PRINT_BIOS_SIG ( service ) );
|
|
275
|
+ return 0;
|
|
276
|
+ }
|
337
|
277
|
}
|
338
|
278
|
|
339
|
|
-void find_pci(int type, struct pci_device *dev)
|
340
|
|
-{
|
341
|
|
-#ifndef CONFIG_PCI_DIRECT
|
342
|
|
- if (!pcibios_entry) {
|
343
|
|
- pcibios_init();
|
|
279
|
+static void find_pcibios32 ( void ) {
|
|
280
|
+ struct bios32 *bios32;
|
|
281
|
+ uint32_t signature;
|
|
282
|
+ uint16_t present;
|
|
283
|
+ uint32_t flags;
|
|
284
|
+ uint16_t revision;
|
|
285
|
+ uint32_t discard;
|
|
286
|
+
|
|
287
|
+ /* Locate BIOS32 service directory */
|
|
288
|
+ bios32 = find_bios32 ();
|
|
289
|
+ if ( ! bios32 ) {
|
|
290
|
+ DBG ( "No BIOS32\n" );
|
|
291
|
+ return;
|
|
292
|
+ }
|
|
293
|
+
|
|
294
|
+ /* Locate PCI BIOS service */
|
|
295
|
+ pcibios32_entry = find_bios32_service ( bios32, PCI_SERVICE );
|
|
296
|
+ if ( ! pcibios32_entry ) {
|
|
297
|
+ DBG ( "No PCI BIOS\n" );
|
|
298
|
+ return;
|
344
|
299
|
}
|
345
|
|
- if (!pcibios_entry) {
|
346
|
|
- printf("pci_init: no BIOS32 detected\n");
|
|
300
|
+
|
|
301
|
+ /* PCI BIOS installation check */
|
|
302
|
+ __asm__ ( FLAT_FAR_CALL_ESI
|
|
303
|
+ "pushfl\n\t"
|
|
304
|
+ "popl %%ecx\n\t"
|
|
305
|
+ : "=a" ( present ), "=b" ( revision ), "=c" ( flags ),
|
|
306
|
+ "=d" ( signature ), "=S" ( discard )
|
|
307
|
+ : "a" ( ( PCIBIOS_PCI_FUNCTION_ID << 8 )
|
|
308
|
+ + PCIBIOS_PCI_BIOS_PRESENT ),
|
|
309
|
+ "S" ( pcibios32_entry )
|
|
310
|
+ : "edi", "ebp" );
|
|
311
|
+
|
|
312
|
+ if ( ( flags & CF ) ||
|
|
313
|
+ ( ( present >> 8 ) != 0 ) ||
|
|
314
|
+ ( signature != PCI_SIGNATURE ) ) {
|
|
315
|
+ DBG ( "PCI BIOS installation check failed\n" );
|
347
|
316
|
return;
|
348
|
317
|
}
|
349
|
|
-#endif
|
350
|
|
- return scan_pci_bus(type, dev);
|
|
318
|
+
|
|
319
|
+ /* We have a PCI BIOS */
|
|
320
|
+ have_pcibios = 1;
|
|
321
|
+ return;
|
|
322
|
+}
|
|
323
|
+
|
|
324
|
+INIT_FN ( INIT_PCIBIOS, find_pcibios32, NULL, NULL );
|
|
325
|
+
|
|
326
|
+#define pcibios32_read_write( command, pci, where, value ) \
|
|
327
|
+ ( { \
|
|
328
|
+ uint32_t discard_b, discard_D, discard_S; \
|
|
329
|
+ uint16_t ret; \
|
|
330
|
+ \
|
|
331
|
+ __asm__ ( FLAT_FAR_CALL_ESI \
|
|
332
|
+ "jc 1f\n\t" \
|
|
333
|
+ "xorl %%eax, %%eax\n\t" \
|
|
334
|
+ "\n1:\n\t" \
|
|
335
|
+ : "=a" ( ret ), "=b" ( discard_b ), \
|
|
336
|
+ "=c" ( value ), \
|
|
337
|
+ "=S" ( discard_S ), "=D" ( discard_D ) \
|
|
338
|
+ : "a" ( ( PCIBIOS_PCI_FUNCTION_ID << 8 ) \
|
|
339
|
+ + command ), \
|
|
340
|
+ "b" ( pci->busdevfn ), "c" ( value ), \
|
|
341
|
+ "D" ( where ), "S" ( pcibios32_entry ) \
|
|
342
|
+ : "edx", "ebp" ); \
|
|
343
|
+ \
|
|
344
|
+ ( ret >> 8 ); \
|
|
345
|
+ } )
|
|
346
|
+#define pcibios_read_write pcibios32_read_write
|
|
347
|
+
|
|
348
|
+#endif /* KEEP_IT_REAL */
|
|
349
|
+
|
|
350
|
+static inline int pcibios_read_config_byte ( struct pci_device *pci,
|
|
351
|
+ unsigned int where,
|
|
352
|
+ uint8_t *value ) {
|
|
353
|
+ return pcibios_read_write ( PCIBIOS_READ_CONFIG_BYTE,
|
|
354
|
+ pci, where, *value );
|
|
355
|
+}
|
|
356
|
+
|
|
357
|
+static inline int pcibios_read_config_word ( struct pci_device *pci,
|
|
358
|
+ unsigned int where,
|
|
359
|
+ uint16_t *value ) {
|
|
360
|
+ return pcibios_read_write ( PCIBIOS_READ_CONFIG_WORD,
|
|
361
|
+ pci, where, *value );
|
|
362
|
+}
|
|
363
|
+
|
|
364
|
+static inline int pcibios_read_config_dword ( struct pci_device *pci,
|
|
365
|
+ unsigned int where,
|
|
366
|
+ uint32_t *value ) {
|
|
367
|
+ return pcibios_read_write ( PCIBIOS_READ_CONFIG_DWORD,
|
|
368
|
+ pci, where, *value );
|
|
369
|
+}
|
|
370
|
+
|
|
371
|
+static inline int pcibios_write_config_byte ( struct pci_device *pci,
|
|
372
|
+ unsigned int where,
|
|
373
|
+ uint8_t value ) {
|
|
374
|
+ return pcibios_read_write ( PCIBIOS_WRITE_CONFIG_BYTE,
|
|
375
|
+ pci, where, value );
|
|
376
|
+}
|
|
377
|
+
|
|
378
|
+static inline int pcibios_write_config_word ( struct pci_device *pci,
|
|
379
|
+ unsigned int where,
|
|
380
|
+ uint16_t value ) {
|
|
381
|
+ return pcibios_read_write ( PCIBIOS_WRITE_CONFIG_WORD,
|
|
382
|
+ pci, where, value );
|
|
383
|
+}
|
|
384
|
+
|
|
385
|
+static inline int pcibios_write_config_dword ( struct pci_device *pci,
|
|
386
|
+ unsigned int where,
|
|
387
|
+ uint32_t value ) {
|
|
388
|
+ return pcibios_read_write ( PCIBIOS_WRITE_CONFIG_DWORD,
|
|
389
|
+ pci, where, value );
|
|
390
|
+}
|
|
391
|
+
|
|
392
|
+/*
|
|
393
|
+ * Functions for accessing PCI configuration space via the PCI BIOS if
|
|
394
|
+ * present, otherwise directly via type 1 accesses.
|
|
395
|
+ *
|
|
396
|
+ */
|
|
397
|
+
|
|
398
|
+int pci_read_config_byte ( struct pci_device *pci, unsigned int where,
|
|
399
|
+ uint8_t *value ) {
|
|
400
|
+ return have_pcibios ?
|
|
401
|
+ pcibios_read_config_byte ( pci, where, value ) :
|
|
402
|
+ pcidirect_read_config_byte ( pci, where, value );
|
|
403
|
+}
|
|
404
|
+
|
|
405
|
+int pci_read_config_word ( struct pci_device *pci, unsigned int where,
|
|
406
|
+ uint16_t *value ) {
|
|
407
|
+ return have_pcibios ?
|
|
408
|
+ pcibios_read_config_word ( pci, where, value ) :
|
|
409
|
+ pcidirect_read_config_word ( pci, where, value );
|
|
410
|
+}
|
|
411
|
+
|
|
412
|
+int pci_read_config_dword ( struct pci_device *pci, unsigned int where,
|
|
413
|
+ uint32_t *value ) {
|
|
414
|
+ return have_pcibios ?
|
|
415
|
+ pcibios_read_config_dword ( pci, where, value ) :
|
|
416
|
+ pcidirect_read_config_dword ( pci, where, value );
|
|
417
|
+}
|
|
418
|
+
|
|
419
|
+int pci_write_config_byte ( struct pci_device *pci, unsigned int where,
|
|
420
|
+ uint8_t value ) {
|
|
421
|
+ return have_pcibios ?
|
|
422
|
+ pcibios_write_config_byte ( pci, where, value ) :
|
|
423
|
+ pcidirect_write_config_byte ( pci, where, value );
|
|
424
|
+}
|
|
425
|
+
|
|
426
|
+int pci_write_config_word ( struct pci_device *pci, unsigned int where,
|
|
427
|
+ uint16_t value ) {
|
|
428
|
+ return have_pcibios ?
|
|
429
|
+ pcibios_write_config_word ( pci, where, value ) :
|
|
430
|
+ pcidirect_write_config_word ( pci, where, value );
|
|
431
|
+}
|
|
432
|
+
|
|
433
|
+int pci_write_config_dword ( struct pci_device *pci, unsigned int where,
|
|
434
|
+ uint32_t value ) {
|
|
435
|
+ return have_pcibios ?
|
|
436
|
+ pcibios_write_config_dword ( pci, where, value ) :
|
|
437
|
+ pcidirect_write_config_dword ( pci, where, value );
|
|
438
|
+}
|
|
439
|
+
|
|
440
|
+unsigned long pci_bus_base ( struct pci_device *pci __unused ) {
|
|
441
|
+ /* architecturally this must be 0 */
|
|
442
|
+ return 0;
|
351
|
443
|
}
|
352
|
|
-#endif /* CONFIG_PCI */
|