]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. | |
24 | * | |
25 | * HISTORY | |
26 | * 23 Nov 98 sdouglas created from objc version. | |
27 | */ | |
28 | ||
29 | #include <IOKit/system.h> | |
30 | ||
31 | #include <libkern/c++/OSContainers.h> | |
32 | #include <IOKit/IODeviceMemory.h> | |
33 | #include <IOKit/IODeviceTreeSupport.h> | |
34 | #include <IOKit/IOLib.h> | |
35 | ||
36 | #include <architecture/i386/kernBootStruct.h> | |
37 | #include <architecture/i386/pio.h> | |
38 | ||
39 | #include "AppleI386PCI.h" | |
40 | ||
41 | #include <assert.h> | |
42 | ||
43 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
44 | ||
45 | #define super IOPCIBridge | |
46 | ||
47 | OSDefineMetaClassAndStructors(AppleI386PCI, IOPCIBridge) | |
48 | ||
49 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
50 | ||
51 | bool AppleI386PCI::start( IOService * provider ) | |
52 | { | |
53 | OSData * prop; | |
54 | PCI_bus_info_t * info; | |
55 | ||
56 | if( 0 == (lock = IOSimpleLockAlloc())) | |
57 | return( false ); | |
58 | ||
59 | prop = (OSData *) provider->getProperty("pci-bus-info"); | |
60 | if( 0 == prop) | |
61 | return( false); | |
62 | ||
63 | info = (PCI_bus_info_t *) prop->getBytesNoCopy(); | |
64 | ||
65 | maxBusNum = info->maxBusNum; | |
66 | maxDevNum = 0; | |
67 | majorVersion = info->majorVersion; | |
68 | minorVersion = info->minorVersion; | |
69 | BIOS16Present = info->BIOSPresent; | |
70 | BIOS32Present = false; | |
71 | BIOS32Entry = 0x00000000; | |
72 | configMethod1 = info->u_bus.s.configMethod1; | |
73 | configMethod2 = info->u_bus.s.configMethod2; | |
74 | specialCycle1 = info->u_bus.s.specialCycle1; | |
75 | specialCycle2 = info->u_bus.s.specialCycle2; | |
76 | ||
77 | /* | |
78 | if ((BIOS16Present) & !(configMethod1 | configMethod2)) { | |
79 | // This is a PCI system, but neither method is supported | |
80 | // Lets try them both just in case (ala NEC ExpressII P60) | |
81 | if (!(configMethod1 = [self test_M1])) | |
82 | configMethod2 = [self test_M2]; | |
83 | } | |
84 | */ | |
85 | ||
86 | #define IFYES(b, s) ((b) ? s : "") | |
87 | IOLog("PCI Ver=%x.%02x BusCount=%d Features=[ %s%s%s%s%s%s]\n", | |
88 | majorVersion, minorVersion, maxBusNum+1, | |
89 | IFYES(BIOS16Present, "BIOS16 "), IFYES(BIOS32Present, "BIOS32 "), | |
90 | IFYES(configMethod1, "CM1 "), IFYES(configMethod2, "CM2 "), | |
91 | IFYES(specialCycle1, "SC1 "), IFYES(specialCycle2, "SC2 ") ); | |
92 | ||
93 | if (configMethod1) | |
94 | maxDevNum = 31; | |
95 | else if (configMethod2) | |
96 | maxDevNum = 15; | |
97 | else | |
98 | return( false ); | |
99 | ||
100 | ioMemory = IODeviceMemory::withRange( 0, 65536 ); | |
101 | if( !ioMemory) | |
102 | return( false); | |
103 | ioMemory->setMapping( kernel_task, 0 ); /* mapped to zero in IO space */ | |
104 | ||
105 | return( super::start( provider)); | |
106 | } | |
107 | ||
108 | bool AppleI386PCI::configure( IOService * provider ) | |
109 | { | |
110 | bool ok; | |
111 | ||
112 | ok = addBridgeMemoryRange( 0x80000000, 0x7f000000, true ); | |
113 | ok = addBridgeIORange( 0, 0x10000 ); | |
114 | ||
115 | return( super::configure( provider )); | |
116 | } | |
117 | ||
118 | void AppleI386PCI::free() | |
119 | { | |
120 | if( ioMemory) | |
121 | ioMemory->release(); | |
122 | if( lock) | |
123 | IOSimpleLockFree( lock); | |
124 | ||
125 | super::free(); | |
126 | } | |
127 | ||
128 | IODeviceMemory * AppleI386PCI::ioDeviceMemory( void ) | |
129 | { | |
130 | return( ioMemory); | |
131 | } | |
132 | ||
133 | ||
134 | UInt8 AppleI386PCI::firstBusNum( void ) | |
135 | { | |
136 | return( 0 ); | |
137 | } | |
138 | ||
139 | UInt8 AppleI386PCI::lastBusNum( void ) | |
140 | { | |
141 | return( firstBusNum() ); | |
142 | } | |
143 | ||
144 | IOPCIAddressSpace AppleI386PCI::getBridgeSpace( void ) | |
145 | { | |
146 | IOPCIAddressSpace space; | |
147 | ||
148 | space.bits = 0; | |
149 | ||
150 | return( space ); | |
151 | } | |
152 | ||
153 | /* defines for Configuration Method #1 (PCI 2.0 Spec, sec 3.6.4.1.1) */ | |
154 | #define PCI_CONFIG_ADDRESS 0x0cf8 | |
155 | #define PCI_CONFIG_DATA 0x0cfc | |
156 | ||
157 | /* defines for Configuration Method #2 (PCI 2.0 Spec, sec 3.6.4.1.3) */ | |
158 | #define PCI_CSE_REGISTER 0x0cf8 | |
159 | #define PCI_BUS_FORWARD 0x0cfa | |
160 | ||
161 | #define PCI_DEFAULT_DATA 0xffffffff | |
162 | ||
163 | #if 0 | |
164 | ||
165 | - (BOOL) test_M1 | |
166 | { | |
167 | unsigned long address, data; | |
168 | ||
169 | for (address = 0x80000000; address < 0x80010000; address += 0x800) { | |
170 | outl (PCI_CONFIG_ADDRESS, address); | |
171 | if (inl (PCI_CONFIG_ADDRESS) != address) { | |
172 | return NO; | |
173 | } | |
174 | data = inl(PCI_CONFIG_DATA); | |
175 | if ((data != PCI_DEFAULT_DATA) && (data != 0x00)) { | |
176 | outl (PCI_CONFIG_ADDRESS, 0); | |
177 | return YES; | |
178 | } | |
179 | } | |
180 | ||
181 | outl (PCI_CONFIG_ADDRESS, 0); | |
182 | return NO; | |
183 | } | |
184 | ||
185 | - (BOOL) test_M2 | |
186 | { | |
187 | unsigned long address, data; | |
188 | ||
189 | /* Enable configuration space at I/O ports Cxxx. */ | |
190 | ||
191 | outb (PCI_CSE_REGISTER, 0xF0); | |
192 | if (inb (PCI_CSE_REGISTER) != 0xF0) { | |
193 | return NO; | |
194 | } | |
195 | ||
196 | outb (PCI_BUS_FORWARD, 0x00); | |
197 | if (inb (PCI_BUS_FORWARD) != 0x00) { | |
198 | return NO; | |
199 | } | |
200 | /* Search all devices on the bus. */ | |
201 | for (address = 0xc000; address <= 0xcfff; address += 0x100) { | |
202 | data = inl(address); | |
203 | if ((data != PCI_DEFAULT_DATA) && (data != 0x00)) { | |
204 | outb (PCI_CSE_REGISTER, 0); | |
205 | return YES; | |
206 | } | |
207 | } | |
208 | ||
209 | outb (PCI_CSE_REGISTER, 0); | |
210 | return NO; | |
211 | } | |
212 | #endif | |
213 | ||
214 | UInt32 AppleI386PCI::configRead32Method1( IOPCIAddressSpace space, | |
215 | UInt8 offset ) | |
216 | { | |
217 | IOPCIAddressSpace addrCycle; | |
218 | UInt32 data = PCI_DEFAULT_DATA; | |
219 | ||
220 | addrCycle = space; | |
221 | addrCycle.s.reloc = 1; | |
222 | addrCycle.s.registerNum = offset; | |
223 | ||
224 | outl( PCI_CONFIG_ADDRESS, addrCycle.bits); | |
225 | if (inl( PCI_CONFIG_ADDRESS) == addrCycle.bits) | |
226 | data = inl( PCI_CONFIG_DATA); | |
227 | ||
228 | outl( PCI_CONFIG_ADDRESS, 0); | |
229 | ||
230 | return( data ); | |
231 | } | |
232 | ||
233 | ||
234 | void AppleI386PCI::configWrite32Method1( IOPCIAddressSpace space, | |
235 | UInt8 offset, UInt32 data ) | |
236 | { | |
237 | IOPCIAddressSpace addrCycle; | |
238 | ||
239 | addrCycle = space; | |
240 | addrCycle.s.reloc = 1; | |
241 | addrCycle.s.registerNum = offset; | |
242 | ||
243 | outl( PCI_CONFIG_ADDRESS, addrCycle.bits); | |
244 | if (inl( PCI_CONFIG_ADDRESS) == addrCycle.bits) | |
245 | outl(PCI_CONFIG_DATA, data); | |
246 | ||
247 | outl( PCI_CONFIG_ADDRESS, 0); | |
248 | } | |
249 | ||
250 | UInt16 AppleI386PCI::configRead16Method1( IOPCIAddressSpace space, | |
251 | UInt8 offset ) | |
252 | { | |
253 | IOPCIAddressSpace addrCycle; | |
254 | UInt16 data = 0xffff; | |
255 | ||
256 | addrCycle = space; | |
257 | addrCycle.s.reloc = 1; | |
258 | addrCycle.s.registerNum = offset; | |
259 | ||
260 | outl( PCI_CONFIG_ADDRESS, addrCycle.bits); | |
261 | if (inl( PCI_CONFIG_ADDRESS) == addrCycle.bits) | |
262 | data = inw( PCI_CONFIG_DATA); | |
263 | ||
264 | outl( PCI_CONFIG_ADDRESS, 0); | |
265 | ||
266 | return( data ); | |
267 | } | |
268 | ||
269 | ||
270 | void AppleI386PCI::configWrite16Method1( IOPCIAddressSpace space, | |
271 | UInt8 offset, UInt16 data ) | |
272 | { | |
273 | IOPCIAddressSpace addrCycle; | |
274 | ||
275 | addrCycle = space; | |
276 | addrCycle.s.reloc = 1; | |
277 | addrCycle.s.registerNum = offset; | |
278 | ||
279 | outl( PCI_CONFIG_ADDRESS, addrCycle.bits); | |
280 | if (inl( PCI_CONFIG_ADDRESS) == addrCycle.bits) | |
281 | outw(PCI_CONFIG_DATA, data); | |
282 | ||
283 | outl( PCI_CONFIG_ADDRESS, 0); | |
284 | } | |
285 | ||
286 | UInt8 AppleI386PCI::configRead8Method1( IOPCIAddressSpace space, | |
287 | UInt8 offset ) | |
288 | { | |
289 | IOPCIAddressSpace addrCycle; | |
290 | UInt8 data = 0xff; | |
291 | ||
292 | addrCycle = space; | |
293 | addrCycle.s.reloc = 1; | |
294 | addrCycle.s.registerNum = offset; | |
295 | ||
296 | outl( PCI_CONFIG_ADDRESS, addrCycle.bits); | |
297 | if (inl( PCI_CONFIG_ADDRESS) == addrCycle.bits) | |
298 | data = inb( PCI_CONFIG_DATA); | |
299 | ||
300 | outl( PCI_CONFIG_ADDRESS, 0); | |
301 | ||
302 | return( data ); | |
303 | } | |
304 | ||
305 | ||
306 | void AppleI386PCI::configWrite8Method1( IOPCIAddressSpace space, | |
307 | UInt8 offset, UInt8 data ) | |
308 | { | |
309 | IOPCIAddressSpace addrCycle; | |
310 | ||
311 | addrCycle = space; | |
312 | addrCycle.s.reloc = 1; | |
313 | addrCycle.s.registerNum = offset; | |
314 | ||
315 | outl( PCI_CONFIG_ADDRESS, addrCycle.bits); | |
316 | if (inl( PCI_CONFIG_ADDRESS) == addrCycle.bits) | |
317 | outb(PCI_CONFIG_DATA, data); | |
318 | ||
319 | outl( PCI_CONFIG_ADDRESS, 0); | |
320 | } | |
321 | ||
322 | UInt32 AppleI386PCI::configRead32Method2( IOPCIAddressSpace space, | |
323 | UInt8 offset ) | |
324 | { | |
325 | UInt32 data = PCI_DEFAULT_DATA; | |
326 | UInt8 cse; | |
327 | ||
328 | if( space.s.deviceNum > 15) | |
329 | return( data); | |
330 | ||
331 | cse = 0xf0 | (space.s.functionNum << 1); | |
332 | outb( PCI_CSE_REGISTER, cse); | |
333 | if (inb( PCI_CSE_REGISTER) == cse) { | |
334 | outb( PCI_BUS_FORWARD, space.s.busNum); | |
335 | if (inb( PCI_BUS_FORWARD) == space.s.busNum) { | |
336 | data = inl( 0xc000 | |
337 | | (offset & 0xfc) | |
338 | | (space.s.deviceNum << 8)); | |
339 | } | |
340 | outb( PCI_BUS_FORWARD, 0x00); | |
341 | } | |
342 | outb( PCI_CSE_REGISTER, 0x00); | |
343 | ||
344 | return( data ); | |
345 | } | |
346 | ||
347 | ||
348 | void AppleI386PCI::configWrite32Method2( IOPCIAddressSpace space, | |
349 | UInt8 offset, UInt32 data ) | |
350 | { | |
351 | UInt8 cse; | |
352 | ||
353 | if( space.s.deviceNum > 15) | |
354 | return; | |
355 | ||
356 | cse = 0xf0 | (space.s.functionNum << 1); | |
357 | outb( PCI_CSE_REGISTER, cse); | |
358 | if (inb( PCI_CSE_REGISTER) == cse) { | |
359 | outb( PCI_BUS_FORWARD, space.s.busNum); | |
360 | if (inb( PCI_BUS_FORWARD) == space.s.busNum) { | |
361 | outl( 0xc000 | |
362 | | (offset & 0xfc) | |
363 | | (space.s.deviceNum << 8), data); | |
364 | } | |
365 | outb( PCI_BUS_FORWARD, 0x00); | |
366 | } | |
367 | outb( PCI_CSE_REGISTER, 0x00); | |
368 | } | |
369 | ||
370 | UInt16 AppleI386PCI::configRead16Method2( IOPCIAddressSpace space, | |
371 | UInt8 offset ) | |
372 | { | |
373 | UInt16 data = 0xffff; | |
374 | UInt8 cse; | |
375 | ||
376 | if( space.s.deviceNum > 15) | |
377 | return( data); | |
378 | ||
379 | cse = 0xf0 | (space.s.functionNum << 1); | |
380 | outb( PCI_CSE_REGISTER, cse); | |
381 | if (inb( PCI_CSE_REGISTER) == cse) { | |
382 | outb( PCI_BUS_FORWARD, space.s.busNum); | |
383 | if (inb( PCI_BUS_FORWARD) == space.s.busNum) { | |
384 | data = inw( 0xc000 | |
385 | | (offset & 0xfe) | |
386 | | (space.s.deviceNum << 8)); | |
387 | } | |
388 | outb( PCI_BUS_FORWARD, 0x00); | |
389 | } | |
390 | outb( PCI_CSE_REGISTER, 0x00); | |
391 | ||
392 | return( data ); | |
393 | } | |
394 | ||
395 | ||
396 | void AppleI386PCI::configWrite16Method2( IOPCIAddressSpace space, | |
397 | UInt8 offset, UInt16 data ) | |
398 | { | |
399 | UInt8 cse; | |
400 | ||
401 | if( space.s.deviceNum > 15) | |
402 | return; | |
403 | ||
404 | cse = 0xf0 | (space.s.functionNum << 1); | |
405 | outb( PCI_CSE_REGISTER, cse); | |
406 | if (inb( PCI_CSE_REGISTER) == cse) { | |
407 | outb( PCI_BUS_FORWARD, space.s.busNum); | |
408 | if (inb( PCI_BUS_FORWARD) == space.s.busNum) { | |
409 | outw( 0xc000 | |
410 | | (offset & 0xfe) | |
411 | | (space.s.deviceNum << 8), data); | |
412 | } | |
413 | outb( PCI_BUS_FORWARD, 0x00); | |
414 | } | |
415 | outb( PCI_CSE_REGISTER, 0x00); | |
416 | } | |
417 | ||
418 | ||
419 | UInt8 AppleI386PCI::configRead8Method2( IOPCIAddressSpace space, | |
420 | UInt8 offset ) | |
421 | { | |
422 | UInt16 data = 0xffff; | |
423 | UInt8 cse; | |
424 | ||
425 | if( space.s.deviceNum > 15) | |
426 | return( data); | |
427 | ||
428 | cse = 0xf0 | (space.s.functionNum << 1); | |
429 | outb( PCI_CSE_REGISTER, cse); | |
430 | if (inb( PCI_CSE_REGISTER) == cse) { | |
431 | outb( PCI_BUS_FORWARD, space.s.busNum); | |
432 | if (inb( PCI_BUS_FORWARD) == space.s.busNum) { | |
433 | data = inb( 0xc000 | |
434 | | (offset) | |
435 | | (space.s.deviceNum << 8)); | |
436 | } | |
437 | outb( PCI_BUS_FORWARD, 0x00); | |
438 | } | |
439 | outb( PCI_CSE_REGISTER, 0x00); | |
440 | ||
441 | return( data ); | |
442 | } | |
443 | ||
444 | ||
445 | void AppleI386PCI::configWrite8Method2( IOPCIAddressSpace space, | |
446 | UInt8 offset, UInt8 data ) | |
447 | { | |
448 | UInt8 cse; | |
449 | ||
450 | if( space.s.deviceNum > 15) | |
451 | return; | |
452 | ||
453 | cse = 0xf0 | (space.s.functionNum << 1); | |
454 | outb( PCI_CSE_REGISTER, cse); | |
455 | if (inb( PCI_CSE_REGISTER) == cse) { | |
456 | outb( PCI_BUS_FORWARD, space.s.busNum); | |
457 | if (inb( PCI_BUS_FORWARD) == space.s.busNum) { | |
458 | outb( 0xc000 | |
459 | | (offset) | |
460 | | (space.s.deviceNum << 8), data); | |
461 | } | |
462 | outb( PCI_BUS_FORWARD, 0x00); | |
463 | } | |
464 | outb( PCI_CSE_REGISTER, 0x00); | |
465 | } | |
466 | ||
467 | ||
468 | UInt32 AppleI386PCI::configRead32( IOPCIAddressSpace space, | |
469 | UInt8 offset ) | |
470 | { | |
471 | IOInterruptState ints; | |
472 | UInt32 retval; | |
473 | ||
474 | ints = IOSimpleLockLockDisableInterrupt( lock ); | |
475 | ||
476 | if( configMethod1) | |
477 | retval = configRead32Method1( space, offset ); | |
478 | else | |
479 | retval = configRead32Method2( space, offset ); | |
480 | ||
481 | IOSimpleLockUnlockEnableInterrupt( lock, ints ); | |
482 | return(retval); | |
483 | } | |
484 | ||
485 | void AppleI386PCI::configWrite32( IOPCIAddressSpace space, | |
486 | UInt8 offset, UInt32 data ) | |
487 | { | |
488 | IOInterruptState ints; | |
489 | ||
490 | ints = IOSimpleLockLockDisableInterrupt( lock ); | |
491 | ||
492 | if( configMethod1) | |
493 | configWrite32Method1( space, offset, data ); | |
494 | else | |
495 | configWrite32Method2( space, offset, data ); | |
496 | ||
497 | IOSimpleLockUnlockEnableInterrupt( lock, ints ); | |
498 | } | |
499 | ||
500 | UInt16 AppleI386PCI::configRead16( IOPCIAddressSpace space, | |
501 | UInt8 offset ) | |
502 | { | |
503 | IOInterruptState ints; | |
504 | UInt16 retval; | |
505 | ||
506 | ints = IOSimpleLockLockDisableInterrupt( lock ); | |
507 | ||
508 | if( configMethod1) | |
509 | retval = configRead16Method1( space, offset ); | |
510 | else | |
511 | retval = configRead16Method2( space, offset ); | |
512 | ||
513 | IOSimpleLockUnlockEnableInterrupt( lock, ints ); | |
514 | return(retval); | |
515 | } | |
516 | ||
517 | void AppleI386PCI::configWrite16( IOPCIAddressSpace space, | |
518 | UInt8 offset, UInt16 data ) | |
519 | { | |
520 | IOInterruptState ints; | |
521 | ||
522 | ints = IOSimpleLockLockDisableInterrupt( lock ); | |
523 | ||
524 | if( configMethod1) | |
525 | configWrite16Method1( space, offset, data ); | |
526 | else | |
527 | configWrite16Method2( space, offset, data ); | |
528 | ||
529 | IOSimpleLockUnlockEnableInterrupt( lock, ints ); | |
530 | } | |
531 | ||
532 | UInt8 AppleI386PCI::configRead8( IOPCIAddressSpace space, | |
533 | UInt8 offset ) | |
534 | { | |
535 | IOInterruptState ints; | |
536 | UInt8 retval; | |
537 | ||
538 | ints = IOSimpleLockLockDisableInterrupt( lock ); | |
539 | ||
540 | if( configMethod1) | |
541 | retval = configRead8Method1( space, offset ); | |
542 | else | |
543 | retval = configRead8Method2( space, offset ); | |
544 | ||
545 | IOSimpleLockUnlockEnableInterrupt( lock, ints ); | |
546 | return(retval); | |
547 | } | |
548 | ||
549 | void AppleI386PCI::configWrite8( IOPCIAddressSpace space, | |
550 | UInt8 offset, UInt8 data ) | |
551 | { | |
552 | IOInterruptState ints; | |
553 | ||
554 | ints = IOSimpleLockLockDisableInterrupt( lock ); | |
555 | ||
556 | if( configMethod1) | |
557 | configWrite8Method1( space, offset, data ); | |
558 | else | |
559 | configWrite8Method2( space, offset, data ); | |
560 | ||
561 | IOSimpleLockUnlockEnableInterrupt( lock, ints ); | |
562 | } | |
563 |