]> git.saurik.com Git - apple/xnu.git/blob - iokit/Families/IOPCIBus/IOPCIBridge.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Families / IOPCIBus / IOPCIBridge.cpp
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-2000 Apple Computer, Inc. All rights reserved.
24 *
25 * HISTORY
26 *
27 * 23 Nov 98 sdouglas created from objc version.
28 *
29 */
30
31 #include <IOKit/system.h>
32
33 #include <IOKit/pci/IOPCIBridge.h>
34 #include <IOKit/pci/IOPCIDevice.h>
35 #include <IOKit/pci/IOAGPDevice.h>
36 #include <IOKit/IODeviceTreeSupport.h>
37 #include <IOKit/IORangeAllocator.h>
38 #include <IOKit/IOPlatformExpert.h>
39 #include <IOKit/IOLib.h>
40 #include <IOKit/assert.h>
41 #include <IOKit/IOCatalogue.h>
42
43 #include <libkern/c++/OSContainers.h>
44
45 extern "C" {
46 #include <machine/machine_routines.h>
47 };
48
49
50 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
51
52 #define super IOService
53
54 OSDefineMetaClassAndAbstractStructors( IOPCIBridge, IOService )
55 OSMetaClassDefineReservedUnused(IOPCIBridge, 0);
56 OSMetaClassDefineReservedUnused(IOPCIBridge, 1);
57 OSMetaClassDefineReservedUnused(IOPCIBridge, 2);
58 OSMetaClassDefineReservedUnused(IOPCIBridge, 3);
59 OSMetaClassDefineReservedUnused(IOPCIBridge, 4);
60 OSMetaClassDefineReservedUnused(IOPCIBridge, 5);
61 OSMetaClassDefineReservedUnused(IOPCIBridge, 6);
62 OSMetaClassDefineReservedUnused(IOPCIBridge, 7);
63 OSMetaClassDefineReservedUnused(IOPCIBridge, 8);
64 OSMetaClassDefineReservedUnused(IOPCIBridge, 9);
65 OSMetaClassDefineReservedUnused(IOPCIBridge, 10);
66 OSMetaClassDefineReservedUnused(IOPCIBridge, 11);
67 OSMetaClassDefineReservedUnused(IOPCIBridge, 12);
68 OSMetaClassDefineReservedUnused(IOPCIBridge, 13);
69 OSMetaClassDefineReservedUnused(IOPCIBridge, 14);
70 OSMetaClassDefineReservedUnused(IOPCIBridge, 15);
71 OSMetaClassDefineReservedUnused(IOPCIBridge, 16);
72 OSMetaClassDefineReservedUnused(IOPCIBridge, 17);
73 OSMetaClassDefineReservedUnused(IOPCIBridge, 18);
74 OSMetaClassDefineReservedUnused(IOPCIBridge, 19);
75 OSMetaClassDefineReservedUnused(IOPCIBridge, 20);
76 OSMetaClassDefineReservedUnused(IOPCIBridge, 21);
77 OSMetaClassDefineReservedUnused(IOPCIBridge, 22);
78 OSMetaClassDefineReservedUnused(IOPCIBridge, 23);
79 OSMetaClassDefineReservedUnused(IOPCIBridge, 24);
80 OSMetaClassDefineReservedUnused(IOPCIBridge, 25);
81 OSMetaClassDefineReservedUnused(IOPCIBridge, 26);
82 OSMetaClassDefineReservedUnused(IOPCIBridge, 27);
83 OSMetaClassDefineReservedUnused(IOPCIBridge, 28);
84 OSMetaClassDefineReservedUnused(IOPCIBridge, 29);
85 OSMetaClassDefineReservedUnused(IOPCIBridge, 30);
86 OSMetaClassDefineReservedUnused(IOPCIBridge, 31);
87
88 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
89
90 // 1 log, 2 disable DT
91 int gIOPCIDebug = 0;
92
93 #ifdef __I386__
94 static void setupIntelPIC(IOPCIDevice * nub);
95 #endif
96
97 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
98 // stub driver has two power states, off and on
99
100 enum { kIOPCIBridgePowerStateCount = 2 };
101
102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
103
104 bool IOPCIBridge::start( IOService * provider )
105 {
106 static const IOPMPowerState powerStates[ kIOPCIBridgePowerStateCount ] = {
107 { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
108 { 1, IOPMPowerOn, IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
109 };
110
111 if( !super::start( provider))
112 return( false);
113
114 // empty ranges to start
115 bridgeMemoryRanges = IORangeAllocator::withRange( 0, 1, 8,
116 IORangeAllocator::kLocking );
117 assert( bridgeMemoryRanges );
118 setProperty( "Bridge Memory Ranges", bridgeMemoryRanges );
119
120 bridgeIORanges = IORangeAllocator::withRange( 0, 1, 8,
121 IORangeAllocator::kLocking );
122 assert( bridgeIORanges );
123 setProperty( "Bridge IO Ranges", bridgeIORanges );
124
125 if( !configure( provider))
126 return( false);
127
128 // initialize superclass variables
129 PMinit();
130 // register as controlling driver
131 registerPowerDriver( this, (IOPMPowerState *) powerStates,
132 kIOPCIBridgePowerStateCount);
133 // join the tree
134 provider->joinPMtree( this);
135 // clamp power on
136 temporaryPowerClampOn();
137
138 probeBus( provider, firstBusNum() );
139
140 return( true );
141 }
142
143 IOReturn IOPCIBridge::setDevicePowerState( IOPCIDevice * device,
144 unsigned long powerState )
145 {
146 if( powerState)
147 return( restoreDeviceState( device));
148 else
149 return( saveDeviceState( device));
150 }
151
152 enum { kSavedConfigSize = 64 };
153 enum { kSavedConfigs = 16 };
154
155 IOReturn IOPCIBridge::saveDeviceState( IOPCIDevice * device,
156 IOOptionBits options = 0 )
157 {
158 int i;
159
160 if( !device->savedConfig)
161 device->savedConfig = IONew( UInt32, kSavedConfigSize );
162 if( !device->savedConfig)
163 return( kIOReturnNotReady );
164
165 for( i = 1; i < kSavedConfigs; i++)
166 device->savedConfig[i] = device->configRead32( i * 4 );
167
168 return( kIOReturnSuccess );
169 }
170
171 IOReturn IOPCIBridge::restoreDeviceState( IOPCIDevice * device,
172 IOOptionBits options = 0 )
173 {
174 int i;
175
176 if( !device->savedConfig)
177 return( kIOReturnNotReady );
178
179 for( i = 2; i < kSavedConfigs; i++)
180 device->configWrite32( i * 4, device->savedConfig[ i ]);
181
182 device->configWrite32( kIOPCIConfigCommand, device->savedConfig[1]);
183
184 IODelete( device->savedConfig, UInt32, kSavedConfigSize);
185 device->savedConfig = 0;
186
187 return( kIOReturnSuccess );
188 }
189
190
191 bool IOPCIBridge::configure( IOService * provider )
192 {
193 return( true );
194 }
195
196 static SInt32 PCICompare( UInt32 /* cellCount */, UInt32 cleft[], UInt32 cright[] )
197 {
198 IOPCIPhysicalAddress * left = (IOPCIPhysicalAddress *) cleft;
199 IOPCIPhysicalAddress * right = (IOPCIPhysicalAddress *) cright;
200 static const UInt8 spacesEq[] = { 0, 1, 2, 2 };
201
202 if( spacesEq[ left->physHi.s.space ] != spacesEq[ right->physHi.s.space ])
203 return( -1);
204
205 return( left->physLo - right->physLo );
206 }
207
208 void IOPCIBridge::nvLocation( IORegistryEntry * entry,
209 UInt8 * busNum, UInt8 * deviceNum, UInt8 * functionNum )
210 {
211 IOPCIDevice * nub;
212
213 nub = OSDynamicCast( IOPCIDevice, entry );
214 assert( nub );
215
216 *busNum = nub->space.s.busNum;
217 *deviceNum = nub->space.s.deviceNum;
218 *functionNum = nub->space.s.functionNum;
219 }
220
221 void IOPCIBridge::spaceFromProperties( OSDictionary * propTable,
222 IOPCIAddressSpace * space )
223 {
224 OSData * regProp;
225 IOPCIAddressSpace * inSpace;
226
227 space->bits = 0;
228
229 if( (regProp = (OSData *) propTable->getObject("reg"))) {
230
231 inSpace = (IOPCIAddressSpace *) regProp->getBytesNoCopy();
232 space->s.busNum = inSpace->s.busNum;
233 space->s.deviceNum = inSpace->s.deviceNum;
234 space->s.functionNum = inSpace->s.functionNum;
235 }
236 }
237
238 IORegistryEntry * IOPCIBridge::findMatching( OSIterator * kids,
239 IOPCIAddressSpace space )
240 {
241 IORegistryEntry * found = 0;
242 IOPCIAddressSpace regSpace;
243
244 if( kids) {
245 kids->reset();
246 while( (0 == found)
247 && (found = (IORegistryEntry *) kids->getNextObject())) {
248
249 spaceFromProperties( found->getPropertyTable(), &regSpace);
250 if( space.bits != regSpace.bits)
251 found = 0;
252 }
253 }
254 return( found );
255 }
256
257 OSDictionary * IOPCIBridge::constructProperties( IOPCIAddressSpace space )
258 {
259 OSDictionary * propTable;
260 UInt32 value;
261 UInt8 byte;
262 UInt16 vendor, device;
263 OSData * prop;
264 const char * name;
265 const OSSymbol * nameProp;
266 char * nameStr;
267 char * compatBuf;
268 char * nextCompat;
269
270 struct IOPCIGenericNames {
271 const char * name;
272 UInt32 mask;
273 UInt32 classCode;
274 };
275 static const IOPCIGenericNames genericNames[] = {
276 { "display", 0xffffff, 0x000100 },
277 { "scsi", 0xffff00, 0x010000 },
278 { "ethernet", 0xffff00, 0x020000 },
279 { "display", 0xff0000, 0x030000 },
280 { "pci-bridge", 0xffff00, 0x060400 },
281 { 0, 0, 0 }
282 };
283 const IOPCIGenericNames * nextName;
284
285 compatBuf = (char *) IOMalloc( 256 );
286
287 propTable = OSDictionary::withCapacity( 8 );
288
289 if( compatBuf && propTable) {
290
291 prop = OSData::withBytes( &space, sizeof( space) );
292 if( prop) {
293 propTable->setObject("reg", prop );
294 prop->release();
295 }
296
297 value = configRead32( space, kIOPCIConfigVendorID );
298 vendor = value;
299 device = value >> 16;
300
301 prop = OSData::withBytes( &vendor, 2 );
302 if( prop) {
303 propTable->setObject("vendor-id", prop );
304 prop->release();
305 }
306
307 prop = OSData::withBytes( &device, 2 );
308 if( prop) {
309 propTable->setObject("device-id", prop );
310 prop->release();
311 }
312
313 value = configRead32( space, kIOPCIConfigRevisionID );
314 byte = value & 0xff;
315 prop = OSData::withBytes( &byte, 1 );
316 if( prop) {
317 propTable->setObject("revision-id", prop );
318 prop->release();
319 }
320
321 // make generic name
322 value >>= 8;
323 name = 0;
324 for( nextName = genericNames;
325 (0 == name) && nextName->name;
326 nextName++ ) {
327 if( (value & nextName->mask) == nextName->classCode)
328 name = nextName->name;
329 }
330
331 // start compatible list
332 nextCompat = compatBuf;
333 sprintf( nextCompat, "pci%x,%x", vendor, device);
334 nameStr = nextCompat;
335
336 value = configRead32( space, kIOPCIConfigSubSystemVendorID );
337 if( value) {
338 vendor = value;
339 device = value >> 16;
340
341 prop = OSData::withBytes( &vendor, 2 );
342 if( prop) {
343 propTable->setObject("subsystem-vendor-id", prop );
344 prop->release();
345 }
346 prop = OSData::withBytes( &device, 2 );
347 if( prop) {
348 propTable->setObject("subsystem-id", prop );
349 prop->release();
350 }
351
352 nextCompat += strlen( nextCompat ) + 1;
353 sprintf( nextCompat, "pci%x,%x", vendor, device);
354 nameStr = nextCompat;
355 }
356
357 nextCompat += strlen( nextCompat ) + 1;
358 prop = OSData::withBytes( compatBuf, nextCompat - compatBuf);
359 if( prop) {
360 propTable->setObject( "compatible", prop );
361 prop->release();
362 }
363
364 if( 0 == name)
365 name = nameStr;
366
367 nameProp = OSSymbol::withCString( name );
368 if( nameProp) {
369 propTable->setObject( gIONameKey, (OSSymbol *) nameProp);
370 nameProp->release();
371 }
372 }
373
374 if( compatBuf)
375 IOFree( compatBuf, 256 );
376
377 return( propTable );
378 }
379
380 IOPCIDevice * IOPCIBridge::createNub( OSDictionary * from )
381 {
382 return( new IOPCIDevice );
383 }
384
385 bool IOPCIBridge::initializeNub( IOPCIDevice * nub,
386 OSDictionary * from )
387 {
388 spaceFromProperties( from, &nub->space);
389 nub->parent = this;
390 if( ioDeviceMemory())
391 nub->ioMap = ioDeviceMemory()->map();
392
393 return( true );
394 }
395
396 bool IOPCIBridge::publishNub( IOPCIDevice * nub, UInt32 /* index */ )
397 {
398 char location[ 24 ];
399 bool ok;
400 OSData * data;
401 OSData * driverData;
402 UInt32 *regData, expRomReg;
403 IOMemoryMap * memoryMap;
404 IOVirtualAddress virtAddr;
405
406 if( nub) {
407 if( nub->space.s.functionNum)
408 sprintf( location, "%X,%X", nub->space.s.deviceNum,
409 nub->space.s.functionNum );
410 else
411 sprintf( location, "%X", nub->space.s.deviceNum );
412 nub->setLocation( location );
413 IODTFindSlotName( nub, nub->space.s.deviceNum );
414
415 // Look for a "driver-reg,AAPL,MacOSX,PowerPC" property.
416 if( (data = (OSData *)nub->getProperty( "driver-reg,AAPL,MacOSX,PowerPC"))) {
417 if( data->getLength() == (2 * sizeof(UInt32))) {
418 regData = (UInt32 *)data->getBytesNoCopy();
419
420 getNubResources(nub);
421 memoryMap = nub->mapDeviceMemoryWithRegister(kIOPCIConfigExpansionROMBase);
422 if( memoryMap != 0) {
423 virtAddr = memoryMap->getVirtualAddress();
424 virtAddr += regData[0];
425
426 nub->setMemoryEnable(true);
427
428 expRomReg = nub->configRead32(kIOPCIConfigExpansionROMBase);
429 nub->configWrite32(kIOPCIConfigExpansionROMBase, expRomReg | 1);
430
431 driverData = OSData::withBytesNoCopy((void *)virtAddr, regData[1]);
432 if ( driverData != 0) {
433 gIOCatalogue->addExtensionsFromArchive(driverData);
434
435 driverData->release();
436 }
437
438 nub->configWrite32(kIOPCIConfigExpansionROMBase, expRomReg);
439
440 nub->setMemoryEnable(false);
441
442 memoryMap->release();
443 }
444 }
445 }
446
447 ok = nub->attach( this );
448 if( ok)
449 nub->registerService();
450 } else
451 ok = false;
452
453 return( ok );
454 }
455
456 void IOPCIBridge::publishNubs( OSIterator * kids, UInt32 index )
457 {
458 IORegistryEntry * found;
459 IOPCIDevice * nub;
460 OSDictionary * propTable;
461
462 if( kids) {
463 kids->reset();
464 while( (found = (IORegistryEntry *) kids->getNextObject())) {
465
466 propTable = found->getPropertyTable();
467 nub = createNub( propTable );
468 if( !nub)
469 continue;
470 if( !initializeNub( nub, propTable))
471 continue;
472 if( !nub->init( found, gIODTPlane))
473 continue;
474
475 publishNub( nub, index++ );
476
477 if( 1 & gIOPCIDebug)
478 IOLog("%08lx = 0:%08lx 4:%08lx ", nub->space.bits,
479 nub->configRead32(kIOPCIConfigVendorID),
480 nub->configRead32(kIOPCIConfigCommand) );
481
482 }
483 }
484 }
485
486 UInt8 IOPCIBridge::firstBusNum( void )
487 {
488 return( 0 );
489 }
490
491 UInt8 IOPCIBridge::lastBusNum( void )
492 {
493 return( 255 );
494 }
495
496 void IOPCIBridge::probeBus( IOService * provider, UInt8 busNum )
497 {
498 IORegistryEntry * regEntry;
499 OSDictionary * propTable;
500 IOPCIDevice * nub = 0;
501 IOPCIAddressSpace space;
502 UInt32 vendor;
503 UInt8 scanDevice, scanFunction, lastFunction;
504 OSIterator * kidsIter;
505 UInt32 index = 0;
506
507 IODTSetResolving( provider, PCICompare, nvLocation );
508
509 if( 2 & gIOPCIDebug)
510 kidsIter = 0;
511 else
512 kidsIter = provider->getChildIterator( gIODTPlane );
513
514 space.bits = 0;
515 space.s.busNum = busNum;
516
517 for( scanDevice = 0; scanDevice <= 31; scanDevice++ ) {
518
519 lastFunction = 0;
520 for( scanFunction = 0; scanFunction <= lastFunction; scanFunction++ ) {
521
522 space.s.deviceNum = scanDevice;
523 space.s.functionNum = scanFunction;
524
525 if( (regEntry = findMatching( kidsIter, space ))) {
526
527
528 } else {
529 /* probe - should guard exceptions */
530 #ifdef __ppc__
531 // DEC bridge really needs safe probe
532 continue;
533 #endif
534 vendor = configRead32( space, kIOPCIConfigVendorID );
535 vendor &= 0x0000ffff;
536 if( (0 == vendor) || (0xffff == vendor))
537 continue;
538
539 // look in function 0 for multi function flag
540 if( (0 == scanFunction)
541 && (0x00800000 & configRead32( space,
542 kIOPCIConfigCacheLineSize )))
543 lastFunction = 7;
544
545 propTable = constructProperties( space );
546 if( propTable
547 && (nub = createNub( propTable))
548 && (initializeNub( nub, propTable))
549 && nub->init( propTable )) {
550 #ifdef __I386__
551 setupIntelPIC(nub);
552 #endif
553 publishNub( nub, index++);
554 }
555 }
556 }
557 }
558
559 if( kidsIter) {
560 publishNubs( kidsIter, index );
561 kidsIter->release();
562 }
563 }
564
565 bool IOPCIBridge::addBridgeMemoryRange( IOPhysicalAddress start,
566 IOPhysicalLength length, bool host )
567 {
568 IORangeAllocator * platformRanges;
569 bool ok = true;
570
571 if( host ) {
572
573 platformRanges = getPlatform()->getPhysicalRangeAllocator();
574 assert( platformRanges );
575
576 // out of the platform
577 ok = platformRanges->allocateRange( start, length );
578 if( !ok)
579 kprintf("%s: didn't get host range (%08lx:%08lx)\n", getName(),
580 start, length);
581 }
582
583 // and into the bridge
584 bridgeMemoryRanges->deallocate( start, length );
585
586 return( ok );
587 }
588
589 bool IOPCIBridge::addBridgeIORange( IOByteCount start, IOByteCount length )
590 {
591 bool ok = true;
592
593 // into the bridge
594 bridgeIORanges->deallocate( start, length );
595
596 return( ok );
597 }
598
599 bool IOPCIBridge::constructRange( IOPCIAddressSpace * flags,
600 IOPhysicalAddress phys,
601 IOPhysicalLength len,
602 OSArray * array )
603 {
604 IODeviceMemory * range;
605 IODeviceMemory * ioMemory;
606 IORangeAllocator * bridgeRanges;
607 bool ok;
608
609 if( !array)
610 return( false );
611
612 if( kIOPCIIOSpace == flags->s.space) {
613
614 bridgeRanges = bridgeIORanges;
615 if( (ioMemory = ioDeviceMemory())) {
616
617 phys &= 0x00ffffff; // seems bogus
618 range = IODeviceMemory::withSubRange( ioMemory, phys, len );
619 if( range == 0)
620 /* didn't fit */
621 range = IODeviceMemory::withRange(
622 phys + ioMemory->getPhysicalAddress(), len );
623
624 } else
625 range = 0;
626
627 } else {
628 bridgeRanges = bridgeMemoryRanges;
629 range = IODeviceMemory::withRange( phys, len );
630 }
631
632
633 if( range) {
634
635 #ifdef i386
636 // Do nothing for Intel -- I/O ports are not accessed through
637 // memory on this platform, but through I/O port instructions
638 #else
639
640 ok = bridgeRanges->allocateRange( phys, len );
641 if( !ok)
642 IOLog("%s: bad range %d(%08lx:%08lx)\n", getName(), flags->s.space,
643 phys, len);
644 #endif
645
646 range->setTag( flags->bits );
647 ok = array->setObject( range );
648 range->release();
649
650 } else
651 ok = false;
652
653 return( ok );
654 }
655
656
657 IOReturn IOPCIBridge::getDTNubAddressing( IOPCIDevice * regEntry )
658 {
659 OSArray * array;
660 IORegistryEntry * parentEntry;
661 OSData * addressProperty;
662 IOPhysicalAddress phys;
663 IOPhysicalLength len;
664 UInt32 cells = 5;
665 int i, num;
666 UInt32 * reg;
667
668 addressProperty = (OSData *) regEntry->getProperty( "assigned-addresses" );
669 if( 0 == addressProperty)
670 return( kIOReturnSuccess );
671
672 parentEntry = regEntry->getParentEntry( gIODTPlane );
673 if( 0 == parentEntry)
674 return( kIOReturnBadArgument );
675
676 array = OSArray::withCapacity( 1 );
677 if( 0 == array)
678 return( kIOReturnNoMemory );
679
680 reg = (UInt32 *) addressProperty->getBytesNoCopy();
681 num = addressProperty->getLength() / (4 * cells);
682
683 for( i = 0; i < num; i++) {
684
685 if( IODTResolveAddressCell( parentEntry, reg, &phys, &len ))
686
687 constructRange( (IOPCIAddressSpace *) reg, phys, len, array );
688
689 reg += cells;
690 }
691
692 if( array->getCount())
693 regEntry->setProperty( gIODeviceMemoryKey, array);
694
695 array->release();
696
697 return( kIOReturnSuccess);
698 }
699
700 IOReturn IOPCIBridge::getNubAddressing( IOPCIDevice * nub )
701 {
702 OSArray * array;
703 IOPhysicalAddress phys;
704 IOPhysicalLength len;
705 UInt32 save, value;
706 IOPCIAddressSpace reg;
707 UInt8 regNum;
708 bool memEna, ioEna;
709 boolean_t s;
710
711 value = nub->configRead32( kIOPCIConfigVendorID );
712 if( 0x0003106b == value ) // control doesn't play well
713 return( kIOReturnSuccess );
714
715 // only header type 0
716 value = nub->configRead32( kIOPCIConfigCacheLineSize );
717 if( value & 0x007f0000)
718 return( kIOReturnSuccess );
719
720 array = OSArray::withCapacity( 1 );
721 if( 0 == array)
722 return( kIOReturnNoMemory );
723
724 for( regNum = 0x10; regNum < 0x28; regNum += 4) {
725
726 // begin scary
727 s = ml_set_interrupts_enabled(FALSE);
728 memEna = nub->setMemoryEnable( false );
729 ioEna = nub->setIOEnable( false );
730
731 save = nub->configRead32( regNum );
732
733 nub->configWrite32( regNum, 0xffffffff );
734 value = nub->configRead32( regNum );
735
736 nub->configWrite32( regNum, save );
737 nub->setMemoryEnable( memEna );
738 nub->setIOEnable( ioEna );
739 ml_set_interrupts_enabled( s );
740 // end scary
741
742 if( 0 == value)
743 continue;
744
745 reg = nub->space;
746 reg.s.registerNum = regNum;
747
748 if( value & 1) {
749 reg.s.space = kIOPCIIOSpace;
750
751 } else {
752 reg.s.prefetch = (0 != (value & 8));
753
754 switch( value & 6) {
755 case 2: /* below 1Mb */
756 reg.s.t = 1;
757 /* fall thru */
758 case 0: /* 32-bit mem */
759 case 6: /* reserved */
760 reg.s.space = kIOPCI32BitMemorySpace;
761 break;
762
763 case 4: /* 64-bit mem */
764 reg.s.space = kIOPCI64BitMemorySpace;
765 regNum += 4;
766 break;
767 }
768 }
769
770 value &= 0xfffffff0;
771 phys = IOPhysical32( 0, save & value );
772 len = IOPhysical32( 0, -value );
773
774 if( 1 & gIOPCIDebug)
775 IOLog("Space %08lx : %08lx, %08lx\n", reg.bits, phys, len);
776
777 constructRange( &reg, phys, len, array );
778 }
779
780 if( array->getCount())
781 nub->setProperty( gIODeviceMemoryKey, array);
782
783 array->release();
784
785 return( kIOReturnSuccess);
786 }
787
788 bool IOPCIBridge::isDTNub( IOPCIDevice * nub )
789 {
790 return( 0 != nub->getParentEntry( gIODTPlane ));
791 }
792
793 IOReturn IOPCIBridge::getNubResources( IOService * service )
794 {
795 IOPCIDevice * nub = (IOPCIDevice *) service;
796 IOReturn err;
797
798 if( service->getDeviceMemory())
799 return( kIOReturnSuccess );
800
801 if( isDTNub( nub))
802 err = getDTNubAddressing( nub );
803 else
804 err = getNubAddressing( nub );
805
806 return( err);
807 }
808
809 bool IOPCIBridge::matchKeys( IOPCIDevice * nub, const char * keys,
810 UInt32 defaultMask, UInt8 regNum )
811 {
812 const char * next;
813 UInt32 mask, value, reg;
814 bool found = false;
815
816 do {
817 value = strtoul( keys, (char **) &next, 16);
818 if( next == keys)
819 break;
820
821 while( (*next) == ' ')
822 next++;
823
824 if( (*next) == '&')
825 mask = strtoul( next + 1, (char **) &next, 16);
826 else
827 mask = defaultMask;
828
829 reg = nub->configRead32( regNum );
830 found = ((value & mask) == (reg & mask));
831 keys = next;
832
833 } while( !found);
834
835 return( found );
836 }
837
838
839 bool IOPCIBridge::pciMatchNub( IOPCIDevice * nub,
840 OSDictionary * table,
841 SInt32 * score )
842 {
843 OSString * prop;
844 const char * keys;
845 bool match = true;
846 UInt8 regNum;
847 int i;
848
849 struct IOPCIMatchingKeys {
850 const char * propName;
851 UInt8 regs[ 4 ];
852 UInt32 defaultMask;
853 };
854 IOPCIMatchingKeys * look;
855 static IOPCIMatchingKeys matching[] = {
856 { kIOPCIMatchKey,
857 { 0x00 + 1, 0x2c }, 0xffffffff },
858 { kIOPCIPrimaryMatchKey,
859 { 0x00 }, 0xffffffff },
860 { kIOPCISecondaryMatchKey,
861 { 0x2c }, 0xffffffff },
862 { kIOPCIClassMatchKey,
863 { 0x08 }, 0xffffff00 }};
864
865 for( look = matching;
866 (match && (look < (&matching[4])));
867 look++ ) {
868
869 prop = (OSString *) table->getObject( look->propName );
870 if( prop) {
871 keys = prop->getCStringNoCopy();
872 match = false;
873 for( i = 0;
874 ((false == match) && (i < 4));
875 i++ ) {
876
877 regNum = look->regs[ i ];
878 match = matchKeys( nub, keys,
879 look->defaultMask, regNum & 0xfc );
880 if( 0 == (1 & regNum))
881 break;
882 }
883 }
884 }
885
886 return( match );
887 }
888
889 bool IOPCIBridge::matchNubWithPropertyTable( IOService * nub,
890 OSDictionary * table,
891 SInt32 * score )
892 {
893 bool matches;
894
895 matches = pciMatchNub( (IOPCIDevice *) nub, table, score);
896
897 return( matches );
898 }
899
900 bool IOPCIBridge::compareNubName( const IOService * nub,
901 OSString * name, OSString ** matched ) const
902 {
903 return( IODTCompareNubName( nub, name, matched ));
904 }
905
906 UInt32 IOPCIBridge::findPCICapability( IOPCIAddressSpace space,
907 UInt8 capabilityID, UInt8 * found )
908 {
909 UInt32 data = 0;
910 UInt8 offset = 0;
911
912 if( found)
913 *found = 0;
914
915 if( 0 == ((kIOPCIStatusCapabilities << 16)
916 & (configRead32( space, kIOPCIConfigCommand))))
917 return( 0 );
918
919 offset = configRead32( space, kIOPCIConfigCapabilitiesPtr );
920 while( offset) {
921 data = configRead32( space, offset );
922 if( capabilityID == (data & 0xff)) {
923 if( found)
924 *found = offset;
925 break;
926 }
927 offset = (data >> 8) & 0xfc;
928 }
929
930 return( data );
931 }
932
933 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
934
935 IOReturn IOPCIBridge::createAGPSpace( IOAGPDevice * master,
936 IOOptionBits options,
937 IOPhysicalAddress * address,
938 IOPhysicalLength * length )
939 {
940 return( kIOReturnUnsupported );
941 }
942
943 IOReturn IOPCIBridge::destroyAGPSpace( IOAGPDevice * master )
944 {
945 return( kIOReturnUnsupported );
946 }
947
948 IORangeAllocator * IOPCIBridge::getAGPRangeAllocator( IOAGPDevice * master )
949 {
950 return( 0 );
951 }
952
953 IOOptionBits IOPCIBridge::getAGPStatus( IOAGPDevice * master,
954 IOOptionBits options = 0 )
955 {
956 return( 0 );
957 }
958
959 IOReturn IOPCIBridge::commitAGPMemory( IOAGPDevice * master,
960 IOMemoryDescriptor * memory,
961 IOByteCount agpOffset,
962 IOOptionBits options )
963 {
964 return( kIOReturnUnsupported );
965 }
966
967 IOReturn IOPCIBridge::releaseAGPMemory( IOAGPDevice * master,
968 IOMemoryDescriptor * memory,
969 IOByteCount agpOffset,
970 IOOptionBits options )
971 {
972 return( kIOReturnUnsupported );
973 }
974
975 IOReturn IOPCIBridge::resetAGPDevice( IOAGPDevice * master,
976 IOOptionBits options = 0 )
977 {
978 return( kIOReturnUnsupported );
979 }
980
981 IOReturn IOPCIBridge::getAGPSpace( IOAGPDevice * master,
982 IOPhysicalAddress * address,
983 IOPhysicalLength * length )
984 {
985 return( kIOReturnUnsupported );
986 }
987
988 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
989
990 #undef super
991 #define super IOPCIBridge
992
993 OSDefineMetaClassAndStructors(IOPCI2PCIBridge, IOPCIBridge)
994 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 0);
995 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 1);
996 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 2);
997 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 3);
998 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 4);
999 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 5);
1000 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 6);
1001 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 7);
1002 OSMetaClassDefineReservedUnused(IOPCI2PCIBridge, 8);
1003
1004 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1005
1006 IOService * IOPCI2PCIBridge::probe( IOService * provider,
1007 SInt32 * score )
1008 {
1009
1010 if( 0 == (bridgeDevice = OSDynamicCast( IOPCIDevice, provider)))
1011 return( 0 );
1012
1013 *score -= 100;
1014
1015 return( this );
1016 }
1017
1018 enum {
1019 kPCI2PCIBusNumbers = 0x18,
1020 kPCI2PCIIORange = 0x1c,
1021 kPCI2PCIMemoryRange = 0x20,
1022 kPCI2PCIPrefetchMemoryRange = 0x24,
1023 kPCI2PCIUpperIORange = 0x30
1024 };
1025
1026 bool IOPCI2PCIBridge::configure( IOService * provider )
1027 {
1028 UInt32 end;
1029 UInt32 start;
1030 bool ok;
1031
1032 end = bridgeDevice->configRead32( kPCI2PCIMemoryRange );
1033 if( end ) {
1034 start = (end & 0xfff0) << 16;
1035 end |= 0x000fffff;
1036 ok = addBridgeMemoryRange( start, end - start + 1, false );
1037 }
1038
1039 end = bridgeDevice->configRead32( kPCI2PCIPrefetchMemoryRange );
1040 if( end) {
1041 start = (end & 0xfff0) << 16;
1042 end |= 0x000fffff;
1043 ok = addBridgeMemoryRange( start, end - start + 1, false );
1044 }
1045
1046 end = bridgeDevice->configRead32( kPCI2PCIIORange );
1047 if( end) {
1048 start = (end & 0xf0) << 8;
1049 end = (end & 0xffff) | 0xfff;
1050 ok = addBridgeIORange( start, end - start + 1 );
1051 }
1052
1053 saveBridgeState();
1054
1055 return( super::configure( provider ));
1056 }
1057
1058 void IOPCI2PCIBridge::saveBridgeState( void )
1059 {
1060 long cnt;
1061
1062 for (cnt = 0; cnt < kIOPCIBridgeRegs; cnt++) {
1063 bridgeState[cnt] = bridgeDevice->configRead32(cnt * 4);
1064 }
1065 }
1066
1067 void IOPCI2PCIBridge::restoreBridgeState( void )
1068 {
1069 long cnt;
1070
1071 for (cnt = 0; cnt < kIOPCIBridgeRegs; cnt++) {
1072 bridgeDevice->configWrite32(cnt * 4, bridgeState[cnt]);
1073 }
1074 }
1075
1076 UInt8 IOPCI2PCIBridge::firstBusNum( void )
1077 {
1078 UInt32 value;
1079
1080 value = bridgeDevice->configRead32( kPCI2PCIBusNumbers );
1081
1082 return( (value >> 8) & 0xff );
1083 }
1084
1085 UInt8 IOPCI2PCIBridge::lastBusNum( void )
1086 {
1087 UInt32 value;
1088
1089 value = bridgeDevice->configRead32( kPCI2PCIBusNumbers );
1090
1091 return( (value >> 16) & 0xff );
1092 }
1093
1094 IOPCIAddressSpace IOPCI2PCIBridge::getBridgeSpace( void )
1095 {
1096 return( bridgeDevice->space );
1097 }
1098
1099 UInt32 IOPCI2PCIBridge::configRead32( IOPCIAddressSpace space,
1100 UInt8 offset )
1101 {
1102 return( bridgeDevice->configRead32( space, offset ));
1103 }
1104
1105 void IOPCI2PCIBridge::configWrite32( IOPCIAddressSpace space,
1106 UInt8 offset, UInt32 data )
1107 {
1108 bridgeDevice->configWrite32( space, offset, data );
1109 }
1110
1111 UInt16 IOPCI2PCIBridge::configRead16( IOPCIAddressSpace space,
1112 UInt8 offset )
1113 {
1114 return( bridgeDevice->configRead16( space, offset ));
1115 }
1116
1117 void IOPCI2PCIBridge::configWrite16( IOPCIAddressSpace space,
1118 UInt8 offset, UInt16 data )
1119 {
1120 bridgeDevice->configWrite16( space, offset, data );
1121 }
1122
1123 UInt8 IOPCI2PCIBridge::configRead8( IOPCIAddressSpace space,
1124 UInt8 offset )
1125 {
1126 return( bridgeDevice->configRead8( space, offset ));
1127 }
1128
1129 void IOPCI2PCIBridge::configWrite8( IOPCIAddressSpace space,
1130 UInt8 offset, UInt8 data )
1131 {
1132 bridgeDevice->configWrite8( space, offset, data );
1133 }
1134
1135 IODeviceMemory * IOPCI2PCIBridge::ioDeviceMemory( void )
1136 {
1137 return( bridgeDevice->ioDeviceMemory());
1138 }
1139
1140 bool IOPCI2PCIBridge::publishNub( IOPCIDevice * nub, UInt32 index )
1141 {
1142 if( nub)
1143 nub->setProperty( "IOChildIndex" , index, 32 );
1144
1145 return( super::publishNub( nub, index ) );
1146 }
1147
1148 #ifdef __I386__
1149
1150 static void setupIntelPIC(IOPCIDevice *nub)
1151 {
1152 OSDictionary *propTable;
1153 OSArray *controller;
1154 OSArray *specifier;
1155 OSData *tmpData;
1156 long irq;
1157 extern OSSymbol *gIntelPICName;
1158
1159 propTable = nub->getPropertyTable();
1160 if (!propTable) return;
1161
1162 do {
1163 // Create the interrupt specifer array.
1164 specifier = OSArray::withCapacity(1);
1165 if ( !specifier )
1166 break;
1167 irq = nub->configRead32(kIOPCIConfigInterruptLine) & 0xf;
1168 tmpData = OSData::withBytes(&irq, sizeof(irq));
1169 if ( tmpData ) {
1170 specifier->setObject(tmpData);
1171 tmpData->release();
1172 }
1173
1174 controller = OSArray::withCapacity(1);
1175 if ( controller ) {
1176 controller->setObject(gIntelPICName);
1177
1178 // Put the two arrays into the property table.
1179 propTable->setObject(gIOInterruptControllersKey, controller);
1180 controller->release();
1181 }
1182 propTable->setObject(gIOInterruptSpecifiersKey, specifier);
1183 specifier->release();
1184 } while( false );
1185 }
1186
1187 #endif