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#include <IOKit/system.h>
24
25#include <IOKit/pci/IOPCIBridge.h>
26#include <IOKit/pci/IOPCIPrivate.h>
27#include <IOKit/pci/IOAGPDevice.h>
28#include <IOKit/pci/IOPCIConfigurator.h>
29#if ACPI_SUPPORT
30#include <IOKit/acpi/IOACPIPlatformDevice.h>
31#endif
32
33#include <IOKit/IODeviceTreeSupport.h>
34#include <IOKit/IOSubMemoryDescriptor.h>
35#include <IOKit/IORangeAllocator.h>
36#include <IOKit/IOPlatformExpert.h>
37#include <IOKit/pwr_mgt/IOPMPrivate.h>
38#include <IOKit/IOLib.h>
39#include <IOKit/IOKitKeys.h>
40#include <IOKit/IOMessage.h>
41#include <IOKit/assert.h>
42#include <IOKit/IOCatalogue.h>
43#include <IOKit/IOFilterInterruptEventSource.h>
44#include <IOKit/IOTimerEventSource.h>
45#include <IOKit/IOPolledInterface.h>
46#include <IOKit/IOUserClient.h>
47
48#include <libkern/c++/OSContainers.h>
49#include <libkern/OSKextLib.h>
50#include <libkern/version.h>
51
52extern "C"
53{
54#include <machine/machine_routines.h>
55};
56
57/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
58
59#ifndef VERSION_MAJOR
60#error VERSION_MAJOR
61#endif
62
63#if         VERSION_MAJOR < 10
64#define     ROM_KEXTS       1
65#endif
66
67#ifndef kIOPolledInterfaceActiveKey
68#define kIOPolledInterfaceActiveKey  "IOPolledInterfaceActive"
69#endif
70
71// #define DEADTEST		"UPS0"
72// #define DEFERTEST	1
73
74enum
75{
76    kIOPCIClassBridge           = 0x06,
77    kIOPCIClassNetwork          = 0x02,
78    kIOPCIClassGraphics         = 0x03,
79    kIOPCIClassMultimedia       = 0x04,
80
81    kIOPCISubClassBridgeHost    = 0x00,
82    kIOPCISubClassBridgeISA     = 0x01,
83    kIOPCISubClassBridgeEISA    = 0x02,
84    kIOPCISubClassBridgeMCA     = 0x03,
85    kIOPCISubClassBridgePCI     = 0x04,
86    kIOPCISubClassBridgePCMCIA  = 0x05,
87    kIOPCISubClassBridgeNuBus   = 0x06,
88    kIOPCISubClassBridgeCardBus = 0x07,
89    kIOPCISubClassBridgeRaceWay = 0x08,
90    kIOPCISubClassBridgeOther   = 0x80,
91};
92
93enum
94{
95	kCheckLinkParents = 0x00000001,
96};
97
98enum { kAERISRNum     = 4 };
99enum { kIOPCIEventNum = 8 };
100
101/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
102
103const IORegistryPlane * gIOPCIACPIPlane;
104
105static class IOPCIMessagedInterruptController  * gIOPCIMessagedInterruptController;
106
107static IOSimpleLock *      gIOPCIEventSourceLock;
108static queue_head_t        gIOPCIEventSourceQueue;
109
110static IOSimpleLock *      gIOAllPCI2PCIBridgesLock;
111static UInt32              gIOAllPCI2PCIBridgeState;
112static uint64_t            gIOPCIWakeCount = 0x100000001ULL;
113
114static IOLock *      	   gIOPCIWakeReasonLock;
115
116const OSSymbol *		   gIOPCITunnelIDKey;
117const OSSymbol *		   gIOPCITunnelledKey;
118const OSSymbol *		   gIOPCIThunderboltKey;
119const OSSymbol *		   gIOPCITunnelL1EnableKey;
120
121const OSSymbol *           gIOPlatformDeviceMessageKey;
122const OSSymbol *           gIOPlatformDeviceASPMEnableKey;
123const OSSymbol *           gIOPlatformSetDeviceInterruptsKey;
124const OSSymbol *           gIOPlatformResolvePCIInterruptKey;
125const OSSymbol *           gIOPlatformFreeDeviceResourcesKey;
126const OSSymbol *           gIOPlatformGetMessagedInterruptControllerKey;
127const OSSymbol *           gIOPlatformGetMessagedInterruptAddressKey;
128const OSSymbol *           gIOPolledInterfaceActiveKey;
129
130#if ACPI_SUPPORT
131const OSSymbol *           gIOPCIPSMethods[kIOPCIDevicePowerStateCount];
132#endif
133
134static queue_head_t        gIOAllPCIDeviceRestoreQ;
135static uint32_t            gIOPCITunnelSleep;
136static uint32_t  		   gIOPCITunnelWait;
137
138static IOWorkLoop *        gIOPCIConfigWorkLoop;
139static IOPCIConfigurator * gIOPCIConfigurator;
140
141uint32_t gIOPCIFlags = 0
142             | kIOPCIConfiguratorAllocate
143             | kIOPCIConfiguratorPFM64
144             | kIOPCIConfiguratorCheckTunnel
145             | kIOPCIConfiguratorTBMSIEnable
146#if !ACPI_SUPPORT
147			 | kIOPCIConfiguratorAER
148#endif
149//           | kIOPCIConfiguratorDeepIdle
150//           | kIOPCIConfiguratorNoSplay
151//			 | kIOPCIConfiguratorNoTB
152//           | kIOPCIConfiguratorIOLog | kIOPCIConfiguratorKPrintf
153;
154
155#define DLOG(fmt, args...)                   \
156    do {                                                    \
157        if ((gIOPCIFlags & kIOPCIConfiguratorIOLog) && !ml_at_interrupt_context())   \
158            IOLog(fmt, ## args);                            \
159        if (gIOPCIFlags & kIOPCIConfiguratorKPrintf)        \
160            kprintf(fmt, ## args);                          \
161    } while(0)
162
163
164/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
165
166enum
167{
168	// data link change, hot plug, presence detect change
169	kSlotControlEnables = ((1 << 12) | (1 << 5) | (1 << 3))
170};
171
172/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
173
174struct IOPCIAERISREntry
175{
176    uint32_t source;
177    uint32_t status;
178};
179
180struct IOPCIAERRoot
181{
182    IOPCIAERISREntry * fISRErrors;
183	uint8_t            fAERReadIndex;
184	uint8_t            fAERWriteIndex;
185};
186
187/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
188
189#undef super
190#include "vtd.c"
191
192/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
193
194#undef super
195#define super IOService
196OSDefineMetaClassAndAbstractStructorsWithInit( IOPCIBridge, IOService, IOPCIBridge::initialize() )
197
198OSMetaClassDefineReservedUsed(IOPCIBridge, 0);
199OSMetaClassDefineReservedUsed(IOPCIBridge, 1);
200OSMetaClassDefineReservedUsed(IOPCIBridge, 2);
201OSMetaClassDefineReservedUsed(IOPCIBridge, 3);
202OSMetaClassDefineReservedUsed(IOPCIBridge, 4);
203OSMetaClassDefineReservedUsed(IOPCIBridge, 5);
204OSMetaClassDefineReservedUnused(IOPCIBridge,  6);
205OSMetaClassDefineReservedUnused(IOPCIBridge,  7);
206OSMetaClassDefineReservedUnused(IOPCIBridge,  8);
207OSMetaClassDefineReservedUnused(IOPCIBridge,  9);
208OSMetaClassDefineReservedUnused(IOPCIBridge, 10);
209OSMetaClassDefineReservedUnused(IOPCIBridge, 11);
210OSMetaClassDefineReservedUnused(IOPCIBridge, 12);
211OSMetaClassDefineReservedUnused(IOPCIBridge, 13);
212OSMetaClassDefineReservedUnused(IOPCIBridge, 14);
213OSMetaClassDefineReservedUnused(IOPCIBridge, 15);
214OSMetaClassDefineReservedUnused(IOPCIBridge, 16);
215OSMetaClassDefineReservedUnused(IOPCIBridge, 17);
216OSMetaClassDefineReservedUnused(IOPCIBridge, 18);
217OSMetaClassDefineReservedUnused(IOPCIBridge, 19);
218OSMetaClassDefineReservedUnused(IOPCIBridge, 20);
219OSMetaClassDefineReservedUnused(IOPCIBridge, 21);
220OSMetaClassDefineReservedUnused(IOPCIBridge, 22);
221OSMetaClassDefineReservedUnused(IOPCIBridge, 23);
222OSMetaClassDefineReservedUnused(IOPCIBridge, 24);
223OSMetaClassDefineReservedUnused(IOPCIBridge, 25);
224OSMetaClassDefineReservedUnused(IOPCIBridge, 26);
225OSMetaClassDefineReservedUnused(IOPCIBridge, 27);
226OSMetaClassDefineReservedUnused(IOPCIBridge, 28);
227OSMetaClassDefineReservedUnused(IOPCIBridge, 29);
228OSMetaClassDefineReservedUnused(IOPCIBridge, 30);
229OSMetaClassDefineReservedUnused(IOPCIBridge, 31);
230
231/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
232
233#ifndef kIOPlatformDeviceMessageKey
234#define kIOPlatformDeviceMessageKey     			"IOPlatformDeviceMessage"
235#endif
236
237#ifndef kIOPlatformSetDeviceInterruptsKey
238#define kIOPlatformSetDeviceInterruptsKey			"SetDeviceInterrupts"
239#endif
240
241#ifndef kIOPlatformResolvePCIInterruptKey
242#define kIOPlatformResolvePCIInterruptKey			"ResolvePCIInterrupt"
243#endif
244
245#ifndef kIOPlatformFreeDeviceResourcesKey
246#define kIOPlatformFreeDeviceResourcesKey			"IOPlatformFreeDeviceResources"
247#endif
248
249#ifndef kIOPlatformGetMessagedInterruptAddressKey
250#define kIOPlatformGetMessagedInterruptAddressKey	"GetMessagedInterruptAddress"
251#endif
252
253#ifndef kIOPlatformGetMessagedInterruptControllerKey
254#define kIOPlatformGetMessagedInterruptControllerKey	"GetMessagedInterruptController"
255#endif
256
257/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
258
259void IOPCIBridge::initialize(void)
260{
261    if (!gIOAllPCI2PCIBridgesLock)
262    {
263        gIOAllPCI2PCIBridgesLock = IOSimpleLockAlloc();
264		gIOPCIEventSourceLock    = IOSimpleLockAlloc();
265        queue_init(&gIOAllPCIDeviceRestoreQ);
266        queue_init(&gIOPCIEventSourceQueue);
267        gIOPCIWakeReasonLock = IOLockAlloc();
268
269        gIOPlatformDeviceMessageKey
270        	= OSSymbol::withCStringNoCopy(kIOPlatformDeviceMessageKey);
271        gIOPlatformDeviceASPMEnableKey
272        	= OSSymbol::withCStringNoCopy(kIOPlatformDeviceASPMEnableKey);
273        gIOPlatformSetDeviceInterruptsKey
274        	= OSSymbol::withCStringNoCopy(kIOPlatformSetDeviceInterruptsKey);
275        gIOPlatformResolvePCIInterruptKey
276        	= OSSymbol::withCStringNoCopy(kIOPlatformResolvePCIInterruptKey);
277        gIOPlatformFreeDeviceResourcesKey
278        	= OSSymbol::withCStringNoCopy(kIOPlatformFreeDeviceResourcesKey);
279        gIOPlatformGetMessagedInterruptAddressKey
280        	= OSSymbol::withCStringNoCopy(kIOPlatformGetMessagedInterruptAddressKey);
281        gIOPlatformGetMessagedInterruptControllerKey
282        	= OSSymbol::withCStringNoCopy(kIOPlatformGetMessagedInterruptControllerKey);
283#if ACPI_SUPPORT
284		gIOPCIPSMethods[kIOPCIDeviceOffState]  = OSSymbol::withCStringNoCopy("_PS3");
285		gIOPCIPSMethods[kIOPCIDeviceDozeState] = OSSymbol::withCStringNoCopy("RPS3");
286		gIOPCIPSMethods[kIOPCIDeviceOnState]   = OSSymbol::withCStringNoCopy("_PS0");
287#endif
288        gIOPCIConfigWorkLoop = IOWorkLoop::workLoop();
289    }
290}
291
292IOWorkLoop * IOPCIBridge::getConfiguratorWorkLoop(void) const
293{
294    return (gIOPCIConfigWorkLoop);
295}
296
297IOReturn IOPCIBridge::configOp(IOService * device, uintptr_t op, void * result, void * arg)
298{
299	static OSSet * gIOPCIWaitingPauseSet;
300	static OSSet * gIOPCIPausedSet;
301	static OSSet * gIOPCIProbeSet;
302
303    IOReturn       ret = kIOReturnSuccess;
304    OSSet *        changed;
305	IOPCIDevice *  next;
306	uint32_t       state;
307
308    if (!gIOPCIConfigWorkLoop->inGate())
309        return (gIOPCIConfigWorkLoop->runAction((IOWorkLoop::Action) &IOPCIBridge::configOp,
310                                                device, (void *) op, result, arg));
311    if (!gIOPCIConfigurator)
312    {
313        uint32_t debug;
314
315		if (getPMRootDomain()->getProperty(kIOPMDeepIdleSupportedKey))
316		{
317			if (PE_parse_boot_argn("acpi", &debug, sizeof(debug)) && (0x10000 & debug)) {}
318			else
319			gIOPCIFlags |= kIOPCIConfiguratorDeepIdle;
320		}
321#if VERSION_MAJOR >= 13
322		gIOPCIFlags |= kIOPCIConfiguratorUsePause;
323#endif
324        if (PE_parse_boot_argn("pci", &debug, sizeof(debug)))
325            gIOPCIFlags |= debug;
326        if (PE_parse_boot_argn("npci", &debug, sizeof(debug)))
327            gIOPCIFlags &= ~debug;
328
329        gIOPCIACPIPlane             = IORegistryEntry::getPlane("IOACPIPlane");
330        gIOPCITunnelIDKey           = OSSymbol::withCStringNoCopy(kIOPCITunnelIDKey);
331        gIOPCITunnelledKey          = OSSymbol::withCStringNoCopy(kIOPCITunnelledKey);
332		gIOPCITunnelL1EnableKey     = OSSymbol::withCStringNoCopy(kIOPCITunnelL1EnableKey);
333        gIOPCIThunderboltKey        = OSSymbol::withCStringNoCopy("PCI-Thunderbolt");
334        gIOPolledInterfaceActiveKey = OSSymbol::withCStringNoCopy(kIOPolledInterfaceActiveKey);
335
336		gIOPCIWaitingPauseSet = OSSet::withCapacity(4);
337		gIOPCIPausedSet       = OSSet::withCapacity(4);
338		gIOPCIProbeSet        = OSSet::withCapacity(4);
339
340        gIOPCIConfigurator = OSTypeAlloc(IOPCIConfigurator);
341        if (!gIOPCIConfigurator || !gIOPCIConfigurator->init(gIOPCIConfigWorkLoop, gIOPCIFlags))
342            panic("!IOPCIConfigurator");
343
344#if defined(__i386__) || defined(__x86_64__)
345        if (!gIOPCIMessagedInterruptController)
346        {
347            enum {
348                // LAPIC_DEFAULT_INTERRUPT_BASE (mp.h)
349                kBaseMessagedInterruptVectors = 0x70,
350                kNumMessagedInterruptVectors = 0xFF - kBaseMessagedInterruptVectors
351            };
352            bool ok = true;
353            IOPCIMessagedInterruptController *
354            ic = new IOPCIMessagedInterruptController;
355            if (ic && !ic->init(kNumMessagedInterruptVectors, kBaseMessagedInterruptVectors))
356            {
357                ic->release();
358                ic = 0;
359            }
360			if (ic)
361			{
362				ok  = ic->reserveVectors(0x7F - kBaseMessagedInterruptVectors, 4);
363				ok &= ic->reserveVectors(0xD0 - kBaseMessagedInterruptVectors, 16);
364			}
365			if (!ic || !ok) panic("IOPCIMessagedInterruptController");
366            gIOPCIMessagedInterruptController = ic;
367        }
368#endif
369
370#if ACPI_SUPPORT
371		IOACPIPlatformDevice * acpiDevice;
372		if (!(acpiDevice = (typeof(acpiDevice)) device->getProvider()->metaCast("IOACPIPlatformDevice")))
373            panic("host!IOACPIPlatformDevice");
374		AppleVTD::install(gIOPCIConfigWorkLoop, gIOPCIFlags, acpiDevice, acpiDevice->getACPITableData("DMAR", 0));
375#endif
376    }
377
378	if (kConfigOpScan != op)
379	{
380		ret = gIOPCIConfigurator->configOp(device, op, result, arg);
381		if (kIOReturnSuccess != ret) return (ret);
382
383		next = (IOPCIDevice *) device;
384		if (kConfigOpTerminated == op)
385		{
386			gIOPCIWaitingPauseSet->removeObject(next);
387			gIOPCIPausedSet->removeObject(next);
388			gIOPCIProbeSet->removeObject(next);
389		}
390		else if (kConfigOpTestPause == op)
391		{
392			if (gIOPCIWaitingPauseSet->setObject(next))
393			{
394				next->changePowerStateToPriv(kIOPCIDevicePausedState);
395				next->powerOverrideOnPriv();
396			}
397		}
398
399		if (op != kConfigOpPaused) op = 0;
400		else
401		{
402			op = 0;
403
404			DLOG("configOp:->pause: %s(0x%qx)\n", device->getName(), device->getRegistryEntryID());
405			if (gIOPCIWaitingPauseSet->containsObject(device))
406			{
407				gIOPCIPausedSet->setObject(device);
408				gIOPCIWaitingPauseSet->removeObject(device);
409				if (!gIOPCIWaitingPauseSet->getCount()) op = kConfigOpRealloc;
410			}
411		}
412	}
413
414	while (op)
415	{
416		ret = gIOPCIConfigurator->configOp(device, op, &changed);
417		op = 0;
418		if (kIOReturnSuccess != ret) break;
419		if (!changed) break;
420
421		while ((next = (IOPCIDevice *) changed->getAnyObject()))
422		{
423			ret = gIOPCIConfigurator->configOp(next, kConfigOpGetState, &state);
424			if (kIOReturnSuccess == ret)
425			{
426				if (kPCIDeviceStateDead & state)
427				{
428					DLOG("configOp:->dead: %s(0x%qx), 0x%x\n", next->getName(), next->getRegistryEntryID(), state);
429					next->terminate();
430				}
431				else if (kPCIDeviceStateRequestPause & state)
432				{
433					DLOG("configOp:->pause: %s(0x%qx), 0x%x\n", next->getName(), next->getRegistryEntryID(), state);
434					if (gIOPCIWaitingPauseSet->setObject(next))
435					{
436						next->changePowerStateToPriv(kIOPCIDevicePausedState);
437						next->powerOverrideOnPriv();
438					}
439				}
440				else
441				{
442					DLOG("configOp:->probe: %s(0x%qx), 0x%x\n", next->getName(), next->getRegistryEntryID(), state);
443					gIOPCIProbeSet->setObject(next);
444				}
445			}
446			changed->removeObject(next);
447		}
448		changed->release();
449	}
450
451	if (!gIOPCIWaitingPauseSet->getCount())
452	{
453		while ((next = (IOPCIDevice *) gIOPCIPausedSet->getAnyObject()))
454		{
455			DLOG("configOp:<-unpause: %s(0x%qx)\n", next->getName(), next->getRegistryEntryID());
456			if (2 != next->reserved->pauseFlags)
457			{
458				next->changePowerStateToPriv(kIOPCIDeviceOnState);
459				next->powerOverrideOffPriv();
460			}
461			next->reserved->pauseFlags = 0;
462			gIOPCIPausedSet->removeObject(next);
463		}
464		while ((next = (IOPCIDevice *) gIOPCIProbeSet->getAnyObject()))
465     	{
466			DLOG("configOp:<-probe: %s(0x%qx), pm %d\n", next->getName(), next->getRegistryEntryID(), next->reserved->pciPMState);
467			if (kIOPCIDeviceOnState == next->reserved->pciPMState) deferredProbe(next);
468			else                                     next->reserved->needsProbe = true;
469			gIOPCIProbeSet->removeObject(next);
470		}
471	}
472
473    return (ret);
474}
475
476void IOPCIBridge::deferredProbe(IOPCIDevice * device)
477{
478	IOService *   client;
479	IOPCIBridge * bridge;
480
481	client = device->copyClientWithCategory(gIODefaultMatchCategoryKey);
482	if ((bridge = OSDynamicCast(IOPCIBridge, client)))
483	{
484		DLOG("configOp:<-probe: %s(0x%qx)\n", device->getName(), device->getRegistryEntryID());
485		bridge->probeBus(device, bridge->firstBusNum());
486	}
487	if (client) client->release();
488
489	device->reserved->needsProbe = false;
490}
491
492//*********************************************************************************
493
494static const IOPMPowerState gIOPCIPowerStates[kIOPCIDevicePowerStateCount] = {
495    // version, capabilityFlags, outputPowerCharacter, inputPowerRequirement, staticPower, stateOrder
496	{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
497	{ 2, 0, kIOPMSoftSleep, kIOPMSoftSleep, 0, 1, 0, 0, 0, 0, 0, 0 },
498	{ 2, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 3, 0, 0, 0, 0, 0, 0 },
499	{ 2, kIOPMConfigRetained, kIOPMConfigRetained, kIOPMConfigRetained, 0, 2, 0, 0, 0, 0, 0, 0 }
500};
501
502static const IOPMPowerState gIOPCIHostPowerStates[kIOPCIDevicePowerStateCount] = {
503    // version, capabilityFlags, outputPowerCharacter, inputPowerRequirement, staticPower, stateOrder
504	{ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
505	{ 2, 0, kIOPMSoftSleep, kIOPMSoftSleep, 0, 1, 0, 0, 0, 0, 0, 0 },
506	{ 2, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 3, 0, 0, 0, 0, 0, 0 },
507	{ 2, kIOPMConfigRetained, kIOPMConfigRetained, kIOPMPowerOn, 0, 2, 0, 0, 0, 0, 0, 0 }
508};
509
510
511// version without kIOPCIDevicePausedState
512static const IOPMPowerState gIOPCIPowerStatesV1[kIOPCIDevicePowerStateCount - 1] = {
513    // version, capabilityFlags, outputPowerCharacter, inputPowerRequirement,
514	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
515	{ 1, 0, kIOPMSoftSleep, kIOPMSoftSleep, 0, 0, 0, 0, 0, 0, 0, 0 },
516	{ 1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
517};
518
519//*********************************************************************************
520
521IOReturn
522IOPCIRegisterPowerDriver(IOService * service, bool hostbridge)
523{
524    IOReturn ret;
525	IOPMPowerState * powerStates = hostbridge
526		? (IOPMPowerState *) gIOPCIHostPowerStates
527		: (IOPMPowerState *) gIOPCIPowerStates;
528
529    ret = service->registerPowerDriver(service, powerStates, kIOPCIDevicePowerStateCount);
530	if (kIOReturnSuccess != ret)
531	{
532		ret = service->registerPowerDriver(service,
533										   (IOPMPowerState *) gIOPCIPowerStatesV1,
534										   arrayCount(gIOPCIPowerStatesV1));
535	}
536	return (ret);
537}
538
539//*********************************************************************************
540// [public] maxCapabilityForDomainState
541//
542// Finds the highest power state in the array whose input power
543// requirement is equal to the input parameter.  Where a more intelligent
544// decision is possible, override this in the subclassed driver.
545//*********************************************************************************
546
547unsigned long
548IOPCIBridge::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
549{
550	if (domainState & kIOPMPowerOn)        return (kIOPCIDeviceOnState);
551	if (domainState & kIOPMSoftSleep)      return (kIOPCIDeviceDozeState);
552	if (domainState & kIOPMConfigRetained) return (kIOPCIDevicePausedState);
553    return (kIOPCIDeviceOffState);
554}
555
556//*********************************************************************************
557// [public] initialPowerStateForDomainState
558//
559// Finds the highest power state in the array whose input power
560// requirement is equal to the input parameter.  Where a more intelligent
561// decision is possible, override this in the subclassed driver.
562//*********************************************************************************
563
564unsigned long
565IOPCIBridge::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
566{
567	if (domainState & kIOPMPowerOn)        return (kIOPCIDeviceOnState);
568	if (domainState & kIOPMSoftSleep)      return (kIOPCIDeviceDozeState);
569	if (domainState & kIOPMConfigRetained) return (kIOPCIDevicePausedState);
570    return (kIOPCIDeviceOffState);
571}
572
573//*********************************************************************************
574// [public] powerStateForDomainState
575//
576// Finds the highest power state in the array whose input power
577// requirement is equal to the input parameter.  Where a more intelligent
578// decision is possible, override this in the subclassed driver.
579//*********************************************************************************
580
581unsigned long
582IOPCIBridge::powerStateForDomainState ( IOPMPowerFlags domainState )
583{
584	if (domainState & kIOPMPowerOn)        return (kIOPCIDeviceOnState);
585	if (domainState & kIOPMSoftSleep)      return (kIOPCIDeviceDozeState);
586	if (domainState & kIOPMConfigRetained) return (kIOPCIDevicePausedState);
587    return (kIOPCIDeviceOffState);
588}
589
590//*********************************************************************************
591
592bool IOPCIBridge::start( IOService * provider )
593{
594	IOPCIDevice * pciDevice;
595
596    if (!super::start(provider))
597        return (false);
598
599    reserved = IONew(ExpansionData, 1);
600    if (reserved == 0) return (false);
601    bzero(reserved, sizeof(ExpansionData));
602
603    if (!configure(provider)) return (false);
604	pciDevice = OSDynamicCast(IOPCIDevice, provider);
605
606    // initialize superclass variables
607    PMinit();
608    // clamp power on
609//    temporaryPowerClampOn();
610    // register as controlling driver
611    IOPCIRegisterPowerDriver(this, !pciDevice);
612
613    // join the tree
614    provider->joinPMtree(this);
615
616	pciDevice = OSDynamicCast(IOPCIDevice, provider);
617    if (!pciDevice)
618    {
619        IOReturn
620        ret = configOp(this, kConfigOpAddHostBridge, 0);
621        if (kIOReturnSuccess != ret)
622            return (false);
623    }
624
625    probeBus( provider, firstBusNum() );
626
627    if ((kIOPCIConfiguratorDeepIdle & gIOPCIFlags)
628	  && (!provider->getProperty(kIOPCIHotPlugKey))
629	  && (!provider->getProperty(kIOPCITunnelLinkChangeKey))
630	  && !(getChildEntry(gIOServicePlane)))
631    {
632		DLOG("%s: no child D3\n", provider->getName());
633
634		if (pciDevice
635		 && pciDevice->hasPCIPowerManagement(kPCIPMCPMESupportFromD3Hot))
636		{
637			pciDevice->enablePCIPowerManagement(kPCIPMCSPowerStateD3);
638		}
639		powerOverrideOnPriv();
640		changePowerStateToPriv(kIOPCIDeviceOffState);
641		changePowerStateTo(kIOPCIDeviceOffState);
642	}
643
644    registerService();
645
646    return (true);
647}
648
649void IOPCIBridge::stop( IOService * provider )
650{
651    PMstop();
652    super::stop( provider);
653}
654
655void IOPCIBridge::free( void )
656{
657    if (reserved) IODelete(reserved, ExpansionData, 1);
658
659    super::free();
660}
661
662IOReturn IOPCIBridge::setDeviceASPMBits(IOPCIDevice * device, uint32_t bits)
663{
664    if (!device->reserved->expressCapability) return (kIOReturnUnsupported);
665
666    uint16_t control;
667    control = device->configRead16(device->reserved->expressCapability + 0x10);
668    control &= ~(kIOPCIExpressASPML0s | kIOPCIExpressASPML1);
669    control |= bits;
670    device->configWrite16(device->reserved->expressCapability + 0x10, control);
671
672    return (kIOReturnSuccess);
673}
674
675IOReturn IOPCIBridge::setDeviceL1PMBits(IOPCIDevice * device, uint32_t bits)
676{
677    OSData * data;
678
679    if (!device->reserved->l1pmCapability) return (kIOReturnUnsupported);
680
681	if (bits
682	 && (data = OSDynamicCast(OSData, device->getProperty(kIOPCIExpressL1PMControlKey)))
683	 && (data->getLength() >= 2*sizeof(uint32_t)))
684	{
685		uint32_t * l1bits = (typeof(l1bits)) data->getBytesNoCopy();
686		device->configWrite32(device->reserved->l1pmCapability + 0x0C, l1bits[1]);
687		device->configWrite32(device->reserved->l1pmCapability + 0x08, l1bits[0] & bits);
688	}
689	else
690	{
691		device->configWrite32(device->reserved->l1pmCapability + 0x08, 0);
692		device->configWrite32(device->reserved->l1pmCapability + 0x0C, 0);
693	}
694
695    return (kIOReturnSuccess);
696}
697
698IOReturn IOPCIBridge::setDeviceASPMState(IOPCIDevice * device,
699                                            IOService * client, IOOptionBits state)
700{
701    IOOptionBits aspmBits, l1pmBits;
702
703	if (state)
704	{
705		aspmBits = (device->reserved->aspmCaps & state);
706		l1pmBits = (device->reserved->l1pmCaps);
707	}
708	else
709	{
710        aspmBits = l1pmBits = 0;
711	}
712
713	setDeviceL1PMBits(device, l1pmBits);
714    setDeviceASPMBits(device, aspmBits);
715
716    return (kIOReturnSuccess);
717}
718
719IOReturn IOPCI2PCIBridge::setDeviceASPMState(IOPCIDevice * device,
720                                            IOService * client, IOOptionBits state)
721{
722    uint32_t aspmBits, l1pmBits;
723
724    // Need to enable upstream first then downstream, reverse for disable
725    if (state)
726    {
727		l1pmBits = (fBridgeDevice->reserved->l1pmCaps & device->reserved->l1pmCaps);
728        setDeviceL1PMBits(fBridgeDevice, l1pmBits);
729        setDeviceL1PMBits(device,       l1pmBits);
730
731		// L1 and L0s need to be supported on both ends to enable
732		aspmBits = (state
733				   & fBridgeDevice->reserved->aspmCaps
734				   & device->reserved->aspmCaps
735				   & (kIOPCIExpressASPML0s | kIOPCIExpressASPML1));
736
737        setDeviceASPMBits(fBridgeDevice, aspmBits);
738        setDeviceASPMBits(device,        aspmBits);
739    }
740    else
741    {
742        aspmBits = l1pmBits = 0;
743        setDeviceL1PMBits(device,       l1pmBits);
744        setDeviceL1PMBits(fBridgeDevice, l1pmBits);
745        setDeviceASPMBits(device,       aspmBits);
746        setDeviceASPMBits(fBridgeDevice, aspmBits);
747    }
748
749    return (kIOReturnSuccess);
750}
751
752IOReturn IOPCIBridge::enableLTR(IOPCIDevice * device, bool enable)
753{
754	return (kIOReturnSuccess);
755}
756
757IOReturn IOPCI2PCIBridge::enableLTR(IOPCIDevice * device, bool enable)
758{
759	IOReturn status;
760
761	status = fBridgeDevice->enableLTR(device, enable);
762	if (status != kIOReturnSuccess) 										return status;
763	return (device->enableLTR(device, enable));
764}
765
766IOReturn
767IOPCI2PCIBridge::setTunnelL1Enable(IOPCIDevice * device, IOService * client, bool l1Enable)
768{
769	IOReturn            ret;
770    IOPCIConfigShadow * shadow;
771    bool                was, now;
772	int32_t             incr;
773
774	if (l1Enable == device->reserved->tunnelL1Allow)        return (kIOReturnSuccess);
775
776	shadow = configShadow(device);
777
778	DLOG("setTunnelL1Enable(0x%llx) %d->%d\n",
779		 device->getRegistryEntryID(), device->reserved->tunnelL1Allow, l1Enable);
780
781	if (!shadow->tunnelRoot)                                return (kIOReturnUnsupported);
782
783	if ((client != device)
784		&& !device->isChild(client, gIOServicePlane))       return (kIOReturnNotAttached);
785
786	device->setProperty(gIOPCITunnelL1EnableKey, l1Enable ? kOSBooleanTrue : kOSBooleanFalse);
787
788	IOLockLock(gIOPCIWakeReasonLock);
789	incr  = l1Enable;
790	incr -= (kTunnelL1Disable != device->reserved->tunnelL1Allow);
791	device->reserved->tunnelL1Allow = l1Enable;
792	was = (fTunnelL1EnableCount >= 0);
793	fTunnelL1EnableCount += incr;
794	now = (fTunnelL1EnableCount >= 0);
795	IOLockUnlock(gIOPCIWakeReasonLock);
796
797	if (was == now)	ret = kIOReturnSuccess;
798	else
799	{
800		if (device == shadow->tunnelRoot)
801		{
802			IOOptionBits state = 0;
803			if (now) state |= kIOPCIExpressASPML1;
804			DLOG("set tunnel ASPM %s -> %d\n", device->getName(), state);
805			ret = device->setASPMState(this, state);
806		}
807		else
808		{
809			ret = fBridgeDevice->setTunnelL1Enable(this, now);
810		}
811	}
812
813	return (ret);
814}
815
816IOReturn IOPCIBridge::setDevicePowerState(IOPCIDevice * device, IOOptionBits options,
817                                          unsigned long prevState, unsigned long newState)
818{
819    bool noSave;
820
821	noSave = ((kIOPCIConfigShadowVolatile & options)
822		    && (kOSBooleanFalse == device->getProperty(kIOPMPCIConfigSpaceVolatileKey)));
823
824    DLOG("%s[%p]::setDevicePowerState(%ld, %ld, %d)\n", device->getName(), device, prevState, newState, noSave);
825
826	if (newState == prevState) return (kIOReturnSuccess);
827
828    switch (newState)
829    {
830        case kIOPCIDeviceOffState:
831			if (noSave) break;
832			saveDeviceState(device, options);
833		    if (kOSBooleanTrue == device->getProperty(kIOPolledInterfaceActiveKey))
834		    {
835		    	newState = kIOPCIDeviceOnState;
836			}
837			else if (kIOPCIConfiguratorDeepIdle & gIOPCIFlags)
838			{
839				newState = kIOPCIDeviceDozeState;
840			}
841			device->setPCIPowerState(newState, 0);
842            break;
843
844        case kIOPCIDeviceDozeState:
845			if (noSave) break;
846			saveDeviceState(device, options);
847			device->setPCIPowerState(newState, 0);
848            break;
849
850        case kIOPCIDeviceOnState:
851			configOp(device, kConfigOpUnpaused, 0);
852			if (noSave) break;
853			if (kIOPCIDevicePausedState != prevState)
854			{
855				if ((kIOPCIDeviceOffState == prevState)
856				 && ((kIOPCIClassGraphics == (device->savedConfig[kIOPCIConfigRevisionID >> 2] >> 24))
857				  || (kIOPCIClassMultimedia == (device->savedConfig[kIOPCIConfigRevisionID >> 2] >> 24))))
858				{
859					tunnelsWait(device);
860				}
861			}
862			device->setPCIPowerState(newState, 0);
863			if (kIOPCIDevicePausedState == prevState) break;
864            restoreDeviceState(device, options);
865            break;
866
867        case kIOPCIDevicePausedState:
868			IOLog("pci pause: %s\n", device->getName());
869			configOp(device, kConfigOpPaused, 0);
870			if (noSave) break;
871			device->setPCIPowerState(newState, 0);
872            restoreDeviceState(device, options);
873            break;
874    }
875
876    return (kIOReturnSuccess);
877}
878
879IOReturn IOPCIBridge::setDevicePowerState( IOPCIDevice * device,
880        unsigned long whatToDo )
881{
882    // Special for pci/pci-bridge devices -
883    // kSaveBridgeState(2) to save immediately, kRestoreBridgeState(3) to restore immediately
884
885    if (kRestoreBridgeState == whatToDo)
886    {
887		if (kSaveBridgeState == gIOAllPCI2PCIBridgeState)
888		{
889			restoreMachineState(kMachineRestoreBridges, 0);
890			restoreMachineState(kMachineRestoreEarlyDevices, 0);
891		}
892        gIOAllPCI2PCIBridgeState = kRestoreBridgeState;
893		gIOPCITunnelWait = gIOPCITunnelSleep;
894    }
895    else if (kSaveBridgeState == whatToDo)
896    {
897        gIOAllPCI2PCIBridgeState = whatToDo;
898		gIOPCIWakeCount++;
899    }
900	else panic("setDevicePowerState");
901
902    return (kIOReturnSuccess);
903}
904
905static void IOPCILogDevice(const char * log, IOPCIDevice * device, bool dump)
906{
907	int      slen, len, pos;
908	char *   string;
909	uint32_t offset, data = 0;
910
911	slen = 2048;
912	pos  = 0;
913	string = IONew(char, slen);
914	if (!string) return;
915	len = 256;
916	pos = snprintf(string, slen - pos, "%s : ints(%d) ", log, ml_get_interrupts_enabled());
917	if (device->getPath(string + pos, &len, gIOServicePlane)) pos += len;
918    if (dump)
919    {
920		pos += snprintf(string + pos, slen - pos, "\n        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
921		for (offset = 0; offset < 256; offset++)
922		{
923			if (0 == (offset & 3))  data = device->configRead32(offset);
924			if (0 == (offset & 15)) pos += snprintf(string + pos, slen - pos, "\n    %02X:", offset);
925			pos += snprintf(string + pos, slen - pos, " %02x", data & 0xff);
926			data >>= 8;
927		}
928	}
929	pos += snprintf(string + pos, slen - pos, "\n");
930	DLOG(string);
931	IODelete(string, char, slen);
932}
933
934IOReturn IOPCIBridge::saveDeviceState( IOPCIDevice * device,
935                                       IOOptionBits options )
936{
937    IOPCIConfigShadow * shadow;
938	IOReturn ret;
939    UInt32   flags;
940	uint32_t data;
941    int      i;
942	bool     ok;
943	uint64_t time;
944
945    if (!device->savedConfig) return (kIOReturnNotReady);
946
947	shadow = configShadow(device);
948    flags = shadow->flags;
949
950    if (kIOPCIConfigShadowValid & flags) return (kIOReturnSuccess);
951
952	DLOG("%s::saveDeviceState(0x%x)\n", device->getName(), options);
953
954    flags |= kIOPCIConfigShadowValid | options;
955    shadow->flags = flags;
956    shadow->restoreCount = 0;
957
958	if (device->getProperty(gIOPCITunnelledKey))
959	{
960		shadow->tunnelID = device->copyProperty(gIOPCITunnelIDKey, gIOServicePlane);
961	}
962
963    if (shadow->handler)
964    {
965		time = mach_absolute_time();
966        (*shadow->handler)(shadow->handlerRef, kIOMessageDeviceWillPowerOff, device, 3);
967		time = mach_absolute_time() - time;
968		absolutetime_to_nanoseconds(time, &time);
969		DLOG("%s::configHandler(kIOMessageDeviceWillPowerOff) %lld ms\n", device->getName(), time / 1000000ULL);
970    }
971
972	if (kIOPCIConfiguratorLogSaveRestore & gIOPCIFlags)
973		IOPCILogDevice("save device", device, true);
974    else if ((kIOPCIConfiguratorIOLog | kIOPCIConfiguratorKPrintf) & gIOPCIFlags)
975		IOPCILogDevice("save device", device, false);
976
977    if (kIOPCIConfigShadowHostBridge & flags) {}
978    else
979	{
980		uint32_t regCount = kIOPCIConfigEPShadowRegs;
981		if (shadow->bridge)
982		{
983			regCount = kIOPCIConfigBridgeShadowRegs;
984			shadow->bridge->saveBridgeState();
985		}
986        for (i = 0; i < regCount; i++)
987        {
988            if (kIOPCISaveRegsMask & (1 << i)) device->savedConfig[i] = device->configRead32(i * 4);
989        }
990    }
991
992	if (device->reserved->l1pmCapability)
993	{
994        shadow->savedL1PM0
995        	= device->configRead32(device->reserved->l1pmCapability + 0x08);
996        shadow->savedL1PM1
997        	= device->configRead32(device->reserved->l1pmCapability + 0x0C);
998		if (kIOPCIConfigShadowWakeL1PMDisable & shadow->flags) shadow->savedL1PM0 &= ~(0xF);
999    }
1000
1001	if (device->reserved->latencyToleranceCapability)
1002	{
1003        shadow->savedLTR
1004        	= device->configRead32(device->reserved->latencyToleranceCapability + 0x04);
1005    }
1006
1007	if (device->reserved->aerCapability)
1008	{
1009        shadow->savedAERCapsControl
1010            = device->configRead32(device->reserved->aerCapability + 0x18);
1011        shadow->savedAERSeverity
1012            = device->configRead32(device->reserved->aerCapability + 0x0C);
1013        shadow->savedAERUMask
1014            = device->configRead32(device->reserved->aerCapability + 0x08);
1015        shadow->savedAERCMask
1016            = device->configRead32(device->reserved->aerCapability + 0x14);
1017		if (device->reserved->rootPort) shadow->savedAERRootCommand
1018            = device->configRead32(device->reserved->aerCapability + 0x30);
1019    }
1020
1021    if (device->reserved->expressCapability)
1022    {
1023        shadow->savedDeviceControl
1024            = device->configRead16( device->reserved->expressCapability + 0x08 );
1025        shadow->savedLinkControl
1026            = device->configRead16( device->reserved->expressCapability + 0x10 );
1027		if ((kIOPCIConfigShadowBridgeInterrupts & shadow->flags)
1028		 || (0x100 & device->reserved->expressCapabilities))
1029        {
1030            shadow->savedSlotControl
1031                = device->configRead16( device->reserved->expressCapability + 0x18 );
1032        }
1033		if (expressV2(device))
1034		{
1035			shadow->savedDeviceControl2
1036				= device->configRead16( device->reserved->expressCapability + 0x28 );
1037			shadow->savedLinkControl2
1038				= device->configRead16( device->reserved->expressCapability + 0x30 );
1039			shadow->savedSlotControl2
1040				= device->configRead16( device->reserved->expressCapability + 0x38 );
1041		}
1042		if (kIOPCIConfigShadowSleepLinkDisable & shadow->flags)
1043		{
1044            device->configWrite16(device->reserved->expressCapability + 0x10,
1045            						(1 << 4) | shadow->savedLinkControl);
1046		}
1047		if (kIOPCIConfigShadowSleepReset & shadow->flags)
1048		{
1049			UInt16 bridgeControl;
1050			bridgeControl = device->configRead16(kPCI2PCIBridgeControl);
1051			device->configWrite16(kPCI2PCIBridgeControl, bridgeControl | 0x40);
1052			IOSleep(10);
1053			device->configWrite16(kPCI2PCIBridgeControl, bridgeControl);
1054		}
1055		if (kIOPCIConfigShadowWakeL1PMDisable & shadow->flags) shadow->savedLinkControl &= ~(0x100);
1056    }
1057
1058	IOPCIMessagedInterruptController::saveDeviceState(device, shadow);
1059
1060    if (shadow->handler)
1061    {
1062		time = mach_absolute_time();
1063        (*shadow->handler)(shadow->handlerRef, kIOMessageDeviceHasPoweredOff, device, 3);
1064		time = mach_absolute_time() - time;
1065		absolutetime_to_nanoseconds(time, &time);
1066		DLOG("%s::configHandler(kIOMessageDeviceHasPoweredOff) %lld ms\n", device->getName(), time / 1000000ULL);
1067    }
1068
1069	if (kIOPCIConfigShadowHotplug & shadow->flags)
1070	{
1071		data = device->configRead32(kIOPCIConfigVendorID);
1072#ifdef DEADTEST
1073		if (!strcmp(DEADTEST, device->getName())) data = 0xFFFFFFFF;
1074#endif
1075		ok = (data && (data != 0xFFFFFFFF));
1076		if (!ok)
1077		{
1078			DLOG("saveDeviceState kill device %s\n", device->getName());
1079			ret = configOp(device, kConfigOpKill, 0);
1080			shadow->flags &= ~kIOPCIConfigShadowValid;
1081		}
1082	}
1083
1084	if (kIOPCIConfigShadowValid & shadow->flags)
1085	{
1086		configOp(device, kConfigOpShadowed, &shadow->savedConfig[0]);
1087		restoreQEnter(device);
1088	}
1089
1090    return (kIOReturnSuccess);
1091}
1092
1093IOReturn IOPCIBridge::_restoreDeviceState(IOPCIDevice * device, IOOptionBits options)
1094{
1095    AbsoluteTime deadline, start, now = 0;
1096    IOPCIConfigShadow * shadow;
1097    uint32_t     retries;
1098    uint32_t     data;
1099    bool         ok;
1100    UInt32       flags;
1101    int          i;
1102    uint64_t     time;
1103    IOReturn     ret;
1104
1105	shadow = configShadow(device);
1106    flags = shadow->flags;
1107
1108    if (!(kIOPCIConfigShadowValid & flags))      return (kIOReturnNoResources);
1109	if (shadow->restoreCount == gIOPCIWakeCount) return (kIOReturnNoResources);
1110	shadow->restoreCount = gIOPCIWakeCount;
1111
1112    if (shadow->handler)
1113    {
1114		time = mach_absolute_time();
1115        ret = (*shadow->handler)(configShadow(device)->handlerRef,
1116                                               kIOMessageDeviceWillPowerOn, device, 3);
1117		if ((kIOPCIRestoreDeviceStateEarly & options) && (kIOReturnNotReady == ret)) return (ret);
1118		time = mach_absolute_time() - time;
1119		absolutetime_to_nanoseconds(time, &time);
1120		DLOG("%s::configHandler(kIOMessageDeviceWillPowerOn) %lld ms\n", device->getName(), time / 1000000ULL);
1121    }
1122
1123	if (!device->reserved->dead)
1124	{
1125		if (kIOReturnSuccess != device->parent->checkLink(kCheckLinkParents))
1126        {
1127            DLOG("%s: pci restore no link\n", device->getName());
1128			device->reserved->dead = true;
1129        }
1130	}
1131
1132    if ((!device->reserved->dead) && !(kIOPCIConfigShadowBridgeDriver & flags))
1133    {
1134		retries = 0;
1135		clock_get_uptime(&start);
1136        clock_interval_to_deadline(200, kMillisecondScale, &deadline);
1137        do
1138        {
1139            if (retries) IOSleep(2);
1140            data = device->configRead32(kIOPCIConfigVendorID);
1141            ok = (data && (data != 0xFFFFFFFF));
1142            if (ok) break;
1143            retries++;
1144            clock_get_uptime(&now);
1145        }
1146        while (AbsoluteTime_to_scalar(&now) < AbsoluteTime_to_scalar(&deadline));
1147
1148        if (retries)
1149        {
1150			absolutetime_to_nanoseconds(now - start, &now);
1151            DLOG("%s: pci restore waited for %qd ms %s\n",
1152                    device->getName(), now / 1000000ULL, ok ? "ok" : "fail");
1153        }
1154        if (data != device->savedConfig[kIOPCIConfigVendorID >> 2])
1155        {
1156            DLOG("%s: pci restore invalid deviceid 0x%08lx\n", device->getName(), data);
1157			device->reserved->dead = true;
1158#if !ACPI_SUPPORT
1159            if (data && (data != 0xFFFFFFFF)) panic("%s: pci restore invalid deviceid 0x%08lx\n", device->getName(), data);
1160#endif
1161        }
1162    }
1163
1164	if (!device->reserved->dead)
1165	{
1166		if (kIOPCIConfiguratorLogSaveRestore & gIOPCIFlags)
1167			IOPCILogDevice("before restore", device, true);
1168		else if ((kIOPCIConfiguratorIOLog | kIOPCIConfiguratorKPrintf) & gIOPCIFlags)
1169			IOPCILogDevice("restore device", device, false);
1170
1171		if (kIOPCIConfigShadowHostBridge & flags) {}
1172		else
1173		{
1174			uint32_t regCount = kIOPCIConfigEPShadowRegs;
1175			if (shadow->bridge)
1176			{
1177				regCount = kIOPCIConfigBridgeShadowRegs;
1178				shadow->bridge->restoreBridgeState();
1179			}
1180			for (i = (kIOPCIConfigRevisionID >> 2); i < regCount; i++)
1181			{
1182				if (kIOPCISaveRegsMask & (1 << i))
1183				    device->configWrite32( i * 4, device->savedConfig[ i ]);
1184			}
1185			device->configWrite32(kIOPCIConfigCommand, device->savedConfig[1]);
1186		}
1187
1188		if (device->reserved->l1pmCapability)
1189		{
1190			device->configWrite32(device->reserved->l1pmCapability + 0x0C,
1191								  shadow->savedL1PM1);
1192			device->configWrite32(device->reserved->l1pmCapability + 0x08,
1193								  shadow->savedL1PM0);
1194		}
1195
1196		if (device->reserved->latencyToleranceCapability)
1197		{
1198			device->configWrite32(device->reserved->latencyToleranceCapability + 0x04,
1199								  shadow->savedLTR);
1200		}
1201
1202		if (device->reserved->aerCapability)
1203		{
1204			device->configWrite32(device->reserved->aerCapability + 0x18,
1205								  shadow->savedAERCapsControl);
1206			device->configWrite32(device->reserved->aerCapability + 0x0C,
1207								  shadow->savedAERSeverity);
1208			device->configWrite32(device->reserved->aerCapability + 0x08,
1209								  shadow->savedAERUMask);
1210			device->configWrite32(device->reserved->aerCapability + 0x14,
1211								  shadow->savedAERCMask);
1212			if (device->reserved->rootPort)
1213			{
1214				device->configWrite32(device->reserved->aerCapability + 0x30, 0xFF);
1215				device->configWrite32(device->reserved->aerCapability + 0x2c,
1216									  shadow->savedAERRootCommand);
1217			}
1218		}
1219
1220		if (device->reserved->expressCapability)
1221		{
1222			device->configWrite16(device->reserved->expressCapability + 0x08,
1223									shadow->savedDeviceControl);
1224
1225			if (expressV2(device))
1226			{
1227				device->configWrite16(device->reserved->expressCapability + 0x28,
1228									  shadow->savedDeviceControl2);
1229			}
1230			device->configWrite16(device->reserved->expressCapability + 0x10,
1231									shadow->savedLinkControl);
1232			if ((kIOPCIConfigShadowBridgeInterrupts & configShadow(device)->flags)
1233			 || (0x100 & device->reserved->expressCapabilities))
1234			{
1235				device->configWrite16(device->reserved->expressCapability + 0x18,
1236										shadow->savedSlotControl);
1237			}
1238			if (expressV2(device))
1239			{
1240				device->configWrite16(device->reserved->expressCapability + 0x30,
1241									  shadow->savedLinkControl2);
1242				device->configWrite16(device->reserved->expressCapability + 0x38,
1243									  shadow->savedSlotControl2);
1244			}
1245		}
1246
1247		IOPCIMessagedInterruptController::restoreDeviceState(device, shadow);
1248
1249		if (kIOPCIConfiguratorLogSaveRestore & gIOPCIFlags)
1250			IOPCILogDevice("after restore", device, true);
1251
1252		if (configShadow(device)->handler)
1253		{
1254			time = mach_absolute_time();
1255			(*configShadow(device)->handler)(configShadow(device)->handlerRef,
1256											 kIOMessageDeviceHasPoweredOn, device, 3);
1257			time = mach_absolute_time() - time;
1258			absolutetime_to_nanoseconds(time, &time);
1259			DLOG("%s::configHandler(kIOMessageDeviceHasPoweredOn) %lld ms\n", device->getName(), time / 1000000ULL);
1260		}
1261	}
1262
1263	configOp(device, kConfigOpShadowed, NULL);
1264
1265    return (kIOReturnSuccess);
1266}
1267
1268void IOPCIBridge::restoreQEnter(IOPCIDevice * device)
1269{
1270	queue_head_t *      que = NULL;
1271    IOPCIConfigShadow * shadow;
1272
1273    shadow = configShadow(device);
1274	if (shadow->tunnelRoot)
1275	{
1276        DLOG("queued %s on %s\n", device->getName(), shadow->tunnelRoot->getName());
1277        que = &configShadow(shadow->tunnelRoot)->dependents;
1278		if (device == shadow->tunnelRoot)
1279		{
1280			IOLockLock(gIOPCIWakeReasonLock);
1281			gIOPCITunnelSleep++;
1282			IOLockUnlock(gIOPCIWakeReasonLock);
1283		}
1284	}
1285    else
1286    {
1287        que = &gIOAllPCIDeviceRestoreQ;
1288	}
1289
1290	IOSimpleLockLock(gIOAllPCI2PCIBridgesLock);
1291	queue_enter_first(que,
1292					  shadow,
1293					  IOPCIConfigShadow *,
1294					  link );
1295	IOSimpleLockUnlock(gIOAllPCI2PCIBridgesLock);
1296}
1297
1298void IOPCIBridge::restoreQRemove(IOPCIDevice * device)
1299{
1300	queue_head_t *      que = NULL;
1301    IOPCIConfigShadow * shadow;
1302
1303    shadow = configShadow(device);
1304
1305	if (!configShadow(device)->link.next) return;
1306
1307	if (shadow->tunnelRoot)
1308	{
1309        que = &configShadow(shadow->tunnelRoot)->dependents;
1310	}
1311    else
1312    {
1313        que = &gIOAllPCIDeviceRestoreQ;
1314	}
1315
1316	IOSimpleLockLock(gIOAllPCI2PCIBridgesLock);
1317	queue_remove(que,
1318				 shadow,
1319				 IOPCIConfigShadow *,
1320				 link );
1321	IOSimpleLockUnlock(gIOAllPCI2PCIBridgesLock);
1322}
1323
1324void IOPCIBridge::tunnelsWait(IOPCIDevice * device)
1325{
1326	IOLockLock(gIOPCIWakeReasonLock);
1327	DLOG("%s: tunnel stall(%d, %d)\n", device->getName(), gIOPCITunnelWait, gIOPCITunnelSleep);
1328	if (gIOPCITunnelWait)
1329	{
1330		IOLockSleep(gIOPCIWakeReasonLock, &gIOPCITunnelWait, THREAD_UNINT);
1331		DLOG("%s: tunnels done\n", device->getName());
1332	}
1333	IOLockUnlock(gIOPCIWakeReasonLock);
1334}
1335
1336IOReturn IOPCIBridge::restoreTunnelState(IOPCIDevice * rootDevice, IOOptionBits options)
1337{
1338	IOReturn            ret;
1339    IOPCIConfigShadow * root;
1340    IOPCIConfigShadow * shadow;
1341    IOPCIConfigShadow * next;
1342
1343    DLOG("restoreTunnelState(%s, %d)\n", rootDevice->getName(), options);
1344	root = configShadow(rootDevice);
1345    IOSimpleLockLock(gIOAllPCI2PCIBridgesLock);
1346
1347	next = (IOPCIConfigShadow *) queue_first(&root->dependents);
1348	while (!queue_end(&root->dependents, (queue_entry_t) next))
1349	{
1350		shadow = next;
1351		next   = (IOPCIConfigShadow *) queue_next(&shadow->link);
1352
1353		if (kMachineRestoreBridges & options)
1354		{
1355			if (!(kIOPCIConfigShadowBridge & shadow->flags))    continue;
1356		}
1357
1358		if (!(kMachineRestoreTunnels & options))
1359		{
1360			if (shadow->tunnelID) continue;
1361		}
1362
1363		IOSimpleLockUnlock(gIOAllPCI2PCIBridgesLock);
1364
1365		if (kIOPCIConfigShadowVolatile & shadow->flags)
1366		{
1367			shadow->device->setPCIPowerState(kIOPCIDeviceOnState, options);
1368
1369			ret = _restoreDeviceState(shadow->device, kIOPCIRestoreDeviceStateEarly);
1370			if (kIOReturnNotReady == ret)
1371			{
1372				ret = _restoreDeviceState(shadow->device, 0);
1373			}
1374		}
1375		if (shadow->tunnelID)
1376		{
1377			shadow->tunnelID->release();
1378			shadow->tunnelID = 0;
1379		}
1380
1381		IOSimpleLockLock(gIOAllPCI2PCIBridgesLock);
1382
1383		next   = (IOPCIConfigShadow *) queue_next(&shadow->link);
1384		queue_remove(&root->dependents,
1385					 shadow,
1386					 IOPCIConfigShadow *,
1387					 link);
1388		shadow->link.next = shadow->link.prev = NULL;
1389	}
1390
1391
1392    IOSimpleLockUnlock(gIOAllPCI2PCIBridgesLock);
1393
1394    return (kIOReturnSuccess);
1395}
1396
1397IOReturn IOPCIBridge::restoreMachineState(IOOptionBits options, IOPCIDevice * device)
1398{
1399	IOReturn            ret;
1400    IOPCIConfigShadow * shadow;
1401    IOPCIConfigShadow * next;
1402
1403    DLOG("restoreMachineState(%d)\n", options);
1404
1405    IOSimpleLockLock(gIOAllPCI2PCIBridgesLock);
1406
1407	next = (IOPCIConfigShadow *) queue_first(&gIOAllPCIDeviceRestoreQ);
1408	while (!queue_end(&gIOAllPCIDeviceRestoreQ, (queue_entry_t) next))
1409	{
1410		shadow = next;
1411		next   = (IOPCIConfigShadow *) queue_next(&shadow->link);
1412
1413		if (shadow->tunnelRoot || shadow->tunnelID) panic("tunnel");
1414
1415		if (shadow->device != device)
1416		{
1417			if (kMachineRestoreBridges & options)
1418			{
1419				if (!(kIOPCIConfigShadowBridge & shadow->flags))    continue;
1420			}
1421
1422			if (!(kIOPCIConfigShadowVolatile & shadow->flags))      continue;
1423#if ACPI_SUPPORT
1424			if (!(kMachineRestoreDehibernate & options)
1425				// skip any slow PS methods
1426				&& (shadow->device->reserved->psMethods[0] >= 0)
1427				// except for nvidia bus zero devices
1428				&& (shadow->device->space.s.busNum
1429					|| (0x10de != (shadow->savedConfig[kIOPCIConfigVendorID >> 2] & 0xffff))))
1430																	continue;
1431#endif
1432			if (kMachineRestoreEarlyDevices & options)
1433			{
1434				if (shadow->device->space.s.busNum)                 continue;
1435				if (shadow->handler)                                continue;
1436				if (shadow->device->reserved->pmSleepEnabled)       continue;
1437			}
1438		}
1439
1440		IOSimpleLockUnlock(gIOAllPCI2PCIBridgesLock);
1441
1442		shadow->device->setPCIPowerState(kIOPCIDeviceOnState, options);
1443
1444		ret = _restoreDeviceState(shadow->device, kIOPCIRestoreDeviceStateEarly);
1445
1446        IOSimpleLockLock(gIOAllPCI2PCIBridgesLock);
1447
1448		next   = (IOPCIConfigShadow *) queue_next(&shadow->link);
1449		queue_remove(&gIOAllPCIDeviceRestoreQ,
1450					 shadow,
1451					 IOPCIConfigShadow *,
1452					 link);
1453		shadow->link.next = shadow->link.prev = NULL;
1454	}
1455
1456    IOSimpleLockUnlock(gIOAllPCI2PCIBridgesLock);
1457
1458    return (kIOReturnSuccess);
1459}
1460
1461IOReturn IOPCIBridge::restoreDeviceState( IOPCIDevice * device, IOOptionBits options )
1462{
1463    IOReturn ret = kIOReturnNotFound;
1464
1465    if (!device->savedConfig)
1466        return (kIOReturnNotReady);
1467
1468    if (kSaveBridgeState == gIOAllPCI2PCIBridgeState)
1469    {
1470        ret = restoreMachineState(kMachineRestoreDehibernate | kMachineRestoreBridges, device);
1471    }
1472
1473    if (kIOReturnSuccess != ret)
1474    {
1475		if (!queue_empty(&configShadow(device)->dependents))
1476		{
1477			ret = restoreTunnelState(device, kMachineRestoreBridges);
1478			ret = restoreTunnelState(device, 0);
1479			ret = restoreTunnelState(device, kMachineRestoreTunnels);
1480			if (!queue_empty(&configShadow(device)->dependents)) panic("tunnelq");
1481
1482			IOLockLock(gIOPCIWakeReasonLock);
1483			gIOPCITunnelSleep--;
1484			if (gIOPCITunnelWait && !--gIOPCITunnelWait)
1485			{
1486				IOLockWakeup(gIOPCIWakeReasonLock, &gIOPCITunnelWait, false);
1487			}
1488			IOLockUnlock(gIOPCIWakeReasonLock);
1489		}
1490		else
1491		{
1492			restoreQRemove(device);
1493			ret = _restoreDeviceState(device, 0);
1494		}
1495    }
1496
1497    configShadow(device)->flags &= ~kIOPCIConfigShadowValid;
1498
1499    // callers expect success
1500    return (kIOReturnSuccess);
1501}
1502
1503IOReturn
1504IOPCIBridge::callPlatformFunction(const OSSymbol * functionName,
1505                                          bool waitForFunction,
1506                                          void * p1, void * p2,
1507                                          void * p3, void * p4)
1508{
1509    IOReturn result;
1510
1511    result = super::callPlatformFunction(functionName, waitForFunction,
1512                                         p1, p2, p3, p4);
1513
1514#if 0
1515    if ((kIOReturnUnsupported == result)
1516     && (gIOPlatformDeviceASPMEnableKey == functionName)
1517     && getProperty(kIOPCIDeviceASPMSupportedKey))
1518    {
1519        result = parent->setDeviceASPMState(this, (IOService *) p1, (IOOptionBits)(uintptr_t) p2);
1520    }
1521#endif
1522    if ((kIOReturnUnsupported == result)
1523     && (gIOPlatformGetMessagedInterruptControllerKey == functionName))
1524    {
1525        *(IOPCIMessagedInterruptController **)p2 =
1526                gIOPCIMessagedInterruptController;
1527    }
1528
1529    return (result);
1530}
1531
1532/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1533
1534bool IOPCIBridge::configure( IOService * provider )
1535{
1536    return (true);
1537}
1538
1539#if !defined(__LP64__) || defined(__x86_64__)
1540SInt32 IOPCIBridge::compareAddressCell( UInt32 /* cellCount */, UInt32 cleft[], UInt32 cright[] )
1541{
1542     IOPCIPhysicalAddress *  left        = (IOPCIPhysicalAddress *) cleft;
1543     IOPCIPhysicalAddress *  right       = (IOPCIPhysicalAddress *) cright;
1544     static const UInt8      spacesEq[]  = { 0, 1, 2, 2 };
1545     if (spacesEq[ left->physHi.s.space ] != spacesEq[ right->physHi.s.space ])
1546         return (-1);
1547
1548    return (left->physLo - right->physLo);
1549}
1550#else
1551SInt64 IOPCIBridge::compareAddressCell( UInt32 /* cellCount */, UInt32 cleft[], UInt32 cright[] )
1552{
1553    IOPCIPhysicalAddress *  left        = (IOPCIPhysicalAddress *) cleft;
1554    IOPCIPhysicalAddress *  right       = (IOPCIPhysicalAddress *) cright;
1555    static const UInt8      spacesEq[]  = { 0, 1, 2, 2 };
1556
1557    if (spacesEq[ left->physHi.s.space ] != spacesEq[ right->physHi.s.space ])
1558        return (-1);
1559
1560    return IOPhysical32(left->physMid, left->physLo) - IOPhysical32(right->physMid, right->physLo);
1561}
1562#endif
1563
1564void IOPCIBridge::nvLocation( IORegistryEntry * entry,
1565                              UInt8 * busNum, UInt8 * deviceNum, UInt8 * functionNum )
1566{
1567    IOPCIDevice *       nub;
1568
1569    nub = OSDynamicCast( IOPCIDevice, entry );
1570    assert( nub );
1571
1572    *busNum             = nub->space.s.busNum;
1573    *deviceNum          = nub->space.s.deviceNum;
1574    *functionNum        = nub->space.s.functionNum;
1575}
1576
1577void IOPCIBridge::spaceFromProperties( OSDictionary * propTable,
1578                                       IOPCIAddressSpace * space )
1579{
1580    OSData *                    regProp;
1581    IOPCIAddressSpace *         inSpace;
1582
1583    space->bits = 0;
1584
1585    if ((regProp = (OSData *) propTable->getObject("reg")))
1586    {
1587        inSpace = (IOPCIAddressSpace *) regProp->getBytesNoCopy();
1588        space->s.busNum = inSpace->s.busNum;
1589        space->s.deviceNum = inSpace->s.deviceNum;
1590        space->s.functionNum = inSpace->s.functionNum;
1591    }
1592}
1593
1594void IOPCIBridge::spaceFromProperties( IORegistryEntry * regEntry,
1595                                       IOPCIAddressSpace * space )
1596{
1597    OSData *                    regProp;
1598    IOPCIAddressSpace *         inSpace;
1599
1600    space->bits = 0;
1601
1602    if ((regProp = (OSData *) regEntry->copyProperty("reg")))
1603    {
1604        inSpace = (IOPCIAddressSpace *) regProp->getBytesNoCopy();
1605        space->s.busNum = inSpace->s.busNum;
1606        space->s.deviceNum = inSpace->s.deviceNum;
1607        space->s.functionNum = inSpace->s.functionNum;
1608        regProp->release();
1609    }
1610}
1611
1612IORegistryEntry * IOPCIBridge::findMatching( OSIterator * kids,
1613        IOPCIAddressSpace space )
1614{
1615    IORegistryEntry *           found = 0;
1616    IOPCIAddressSpace           regSpace;
1617
1618    if (kids)
1619    {
1620        kids->reset();
1621        while ((0 == found)
1622                && (found = (IORegistryEntry *) kids->getNextObject()))
1623        {
1624            spaceFromProperties(found, &regSpace);
1625            if (space.bits != regSpace.bits)
1626                found = 0;
1627        }
1628    }
1629    return (found);
1630}
1631
1632bool IOPCIBridge::checkProperties( IOPCIDevice * entry )
1633{
1634    uint32_t    vendor, product, classCode, revID;
1635    uint32_t    subVendor = 0, subProduct = 0;
1636    IOByteCount offset;
1637    OSData *    data;
1638
1639    if ((data = OSDynamicCast(OSData, entry->getProperty("vendor-id"))))
1640        vendor = *((uint32_t *) data->getBytesNoCopy());
1641    else
1642        return (false);
1643    if ((data = OSDynamicCast(OSData, entry->getProperty("device-id"))))
1644        product = *((uint32_t *) data->getBytesNoCopy());
1645    else
1646        return (false);
1647    if ((data = OSDynamicCast(OSData, entry->getProperty("class-code"))))
1648        classCode = *((uint32_t *) data->getBytesNoCopy());
1649    else
1650        return (false);
1651    if ((data = OSDynamicCast(OSData, entry->getProperty("revision-id"))))
1652        revID = *((uint32_t *) data->getBytesNoCopy());
1653    else
1654        return (false);
1655    if ((data = OSDynamicCast(OSData, entry->getProperty("subsystem-vendor-id"))))
1656        subVendor = *((uint32_t *) data->getBytesNoCopy());
1657    if ((data = OSDynamicCast(OSData, entry->getProperty("subsystem-id"))))
1658        subProduct = *((uint32_t *) data->getBytesNoCopy());
1659
1660    if (entry->savedConfig)
1661    {
1662        // update matching config space regs from properties
1663        entry->savedConfig[kIOPCIConfigVendorID >> 2] = (product << 16) | vendor;
1664        entry->savedConfig[kIOPCIConfigRevisionID >> 2] = (classCode << 8) | revID;
1665        if (subVendor && subProduct)
1666            entry->savedConfig[kIOPCIConfigSubSystemVendorID >> 2] = (subProduct << 16) | subVendor;
1667    }
1668
1669    if ((offset = entry->reserved->expressCapability))
1670    {
1671        uint32_t value, expressCaps;
1672
1673		expressCaps = entry->configRead16(offset + 0x02);
1674        entry->setProperty(kIOPCIExpressCapabilitiesKey, expressCaps, 32);
1675        value = entry->configRead16(offset + 0x12);
1676        entry->setProperty(kIOPCIExpressLinkStatusKey, value, 32);
1677        value = entry->configRead32(offset + 0x0c);
1678        entry->setProperty(kIOPCIExpressLinkCapabilitiesKey, value, 32);
1679		if (0x100 & expressCaps)
1680		{
1681			value = entry->configRead16(offset + 0x1a);
1682			entry->setProperty(kIOPCIExpressSlotStatusKey, value, 32);
1683			value = entry->configRead32(offset + 0x14);
1684			entry->setProperty(kIOPCIExpressSlotCapabilitiesKey, value, 32);
1685		}
1686    }
1687
1688    return (true);
1689}
1690
1691#if VERSION_MAJOR < 13
1692static char *
1693strnstr(char *s, const char *find, size_t slen)
1694{
1695  char c, sc;
1696  size_t len;
1697
1698  if ((c = *find++) != '\0') {
1699    len = strlen(find);
1700    do {
1701      do {
1702        if ((sc = *s++) == '\0' || slen-- < 1)
1703          return (NULL);
1704      } while (sc != c);
1705      if (len > slen)
1706        return (NULL);
1707    } while (strncmp(s, find, len) != 0);
1708    s--;
1709  }
1710  return (s);
1711}
1712#endif
1713
1714#ifndef kIOPMRootDomainWakeTypeNetwork
1715#define kIOPMRootDomainWakeTypeNetwork      "Network"
1716#endif
1717
1718void IOPCIBridge::updateWakeReason(IOPCIDevice * device)
1719{
1720	OSObject *   obj;
1721	OSString *   reasonProp;
1722	const char * reason;
1723	const char * propCStr;
1724	unsigned int len;
1725	char         wakeBuffer[128];
1726
1727	reason = device->getName();
1728	IOLockLock(gIOPCIWakeReasonLock);
1729	do
1730	{
1731		obj = getPMRootDomain()->copyProperty(kIOPMRootDomainWakeReasonKey);
1732		reasonProp = OSDynamicCast(OSString, obj);
1733		if (reasonProp && (len = reasonProp->getLength()))
1734		{
1735			propCStr = reasonProp->getCStringNoCopy();
1736			if (strnstr((char *) propCStr, reason, len + 1)) break;
1737			snprintf(wakeBuffer, sizeof(wakeBuffer), "%s %s", propCStr, reason);
1738			reason = wakeBuffer;
1739		}
1740	    getPMRootDomain()->setProperty(kIOPMRootDomainWakeReasonKey, reason);
1741	    if (obj) obj->release();
1742	}
1743	while (false);
1744
1745	if ((kIOPCIClassNetwork == (device->savedConfig[kIOPCIConfigRevisionID >> 2] >> 24))
1746      && (!getPMRootDomain()->getProperty(kIOPMRootDomainWakeTypeKey)))
1747	{
1748        getPMRootDomain()->setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNetwork);
1749	}
1750	IOLockUnlock(gIOPCIWakeReasonLock);
1751}
1752
1753OSDictionary * IOPCIBridge::constructProperties( IOPCIAddressSpace space )
1754{
1755    return (0);
1756}
1757
1758IOPCIDevice * IOPCIBridge::createNub( OSDictionary * from )
1759{
1760    return (new IOPCIDevice);
1761}
1762
1763bool IOPCIBridge::initializeNub( IOPCIDevice * nub,
1764                                 OSDictionary * from )
1765{
1766    spaceFromProperties( from, &nub->space);
1767    nub->parent = this;
1768
1769    if (ioDeviceMemory())
1770        nub->ioMap = ioDeviceMemory()->map();
1771
1772    return (true);
1773}
1774
1775void IOPCIBridge::removeDevice( IOPCIDevice * device, IOOptionBits options )
1776{
1777    IOReturn ret = kIOReturnSuccess;
1778
1779#if USE_MSI
1780    if (device->reserved->msiCapability && reserved->messagedInterruptController)
1781        ret = reserved->messagedInterruptController->deallocateDeviceInterrupts(device);
1782#endif /* USE_MSI */
1783
1784    getPlatform()->callPlatformFunction(gIOPlatformFreeDeviceResourcesKey,
1785									  /* waitForFunction */ false,
1786									  /* nub             */ device, NULL, NULL, NULL);
1787	restoreQRemove(device);
1788    configOp(device, kConfigOpTerminated, 0);
1789}
1790
1791bool IOPCIBridge::publishNub( IOPCIDevice * nub, UInt32 /* index */ )
1792{
1793	IOPCIDevice *               root;
1794    char                        location[ 24 ];
1795    bool                        ok;
1796#if ROM_KEXTS
1797    OSData *                    data;
1798    OSData *                    driverData;
1799    UInt32                      *regData, expRomReg;
1800    IOMemoryMap *               memoryMap;
1801    IOVirtualAddress            virtAddr;
1802#endif
1803
1804    if (nub)
1805    {
1806        if (nub->space.s.functionNum)
1807            snprintf( location, sizeof(location), "%X,%X", nub->space.s.deviceNum,
1808                     nub->space.s.functionNum );
1809        else
1810            snprintf( location, sizeof(location), "%X", nub->space.s.deviceNum );
1811        nub->setLocation( location );
1812        IODTFindSlotName( nub, nub->space.s.deviceNum );
1813
1814        // set up config space shadow
1815
1816        IOPCIConfigShadow * shadow = IONew(IOPCIConfigShadow, 1);
1817        if (shadow)
1818        {
1819            bzero(shadow, sizeof(IOPCIConfigShadow));
1820            queue_init(&shadow->dependents);
1821            shadow->device = nub;
1822			for (root = nub;
1823				 (!root->getProperty(gIOPCIThunderboltKey))
1824				 	&& (root = OSDynamicCast(IOPCIDevice, root->getParentEntry(gIODTPlane)));)
1825			    {}
1826			shadow->tunnelRoot = root;
1827			nub->reserved->tunnelL1Allow = kTunnelL1NotSet;
1828
1829            nub->savedConfig = (UInt32 *) &shadow->savedConfig[0];
1830            for (int i = 0; i < kIOPCIConfigEPShadowRegs; i++)
1831            {
1832                if (kIOPCISaveRegsMask & (1 << i))
1833                	nub->savedConfig[i] = nub->configRead32( i << 2 );
1834			}
1835        }
1836
1837        checkProperties( nub );
1838
1839        if (shadow && (kIOPCIClassBridge == (nub->savedConfig[kIOPCIConfigRevisionID >> 2] >> 24)))
1840        {
1841            shadow->flags |= kIOPCIConfigShadowBridge;
1842#if 0
1843            if (kIOPCISubClassBridgeMCA >= (0xff & (nub->savedConfig[kIOPCIConfigRevisionID >> 2] >> 16)))
1844            {
1845                shadow->flags |= kIOPCIConfigShadowHostBridge;
1846            }
1847#endif
1848        }
1849
1850#if ROM_KEXTS
1851        // look for a "driver-reg,AAPL,MacOSX,PowerPC" property.
1852
1853        if ((data = (OSData *)nub->getProperty("driver-reg,AAPL,MacOSX,PowerPC")))
1854        {
1855            if (data->getLength() == (2 * sizeof(UInt32)))
1856            {
1857                regData = (UInt32 *)data->getBytesNoCopy();
1858
1859                getNubResources(nub);
1860                memoryMap = nub->mapDeviceMemoryWithRegister(kIOPCIConfigExpansionROMBase);
1861                if (memoryMap != 0)
1862                {
1863                    virtAddr = memoryMap->getVirtualAddress();
1864                    virtAddr += regData[0];
1865
1866                    nub->setMemoryEnable(true);
1867
1868                    expRomReg = nub->configRead32(kIOPCIConfigExpansionROMBase);
1869                    nub->configWrite32(kIOPCIConfigExpansionROMBase, expRomReg | 1);
1870
1871                    driverData = OSData::withBytesNoCopy((void *)virtAddr, regData[1]);
1872                    if (driverData != 0)
1873                    {
1874                        gIOCatalogue->addExtensionsFromArchive(driverData);
1875
1876                        driverData->release();
1877                    }
1878
1879                    nub->configWrite32(kIOPCIConfigExpansionROMBase, expRomReg);
1880
1881                    nub->setMemoryEnable(false);
1882
1883                    memoryMap->release();
1884                }
1885            }
1886        }
1887#endif
1888        ok = nub->attach( this );
1889
1890        if (ok)
1891        {
1892            nub->callPlatformFunction(gIOPlatformDeviceMessageKey, false,
1893                    (void *) kIOMessageDeviceWillPowerOff, nub, (void *) 0, (void *) 0);
1894
1895            nub->callPlatformFunction(gIOPlatformDeviceMessageKey, false,
1896                    (void *) kIOMessageDeviceHasPoweredOn, nub, (void *) 0, (void *) 0);
1897
1898            nub->registerService();
1899        }
1900    }
1901    else
1902        ok = false;
1903
1904    return (ok);
1905}
1906
1907UInt8 IOPCIBridge::firstBusNum( void )
1908{
1909    return (0);
1910}
1911
1912UInt8 IOPCIBridge::lastBusNum( void )
1913{
1914    return (255);
1915}
1916
1917IOReturn IOPCIBridge::kernelRequestProbe(IOPCIDevice * device, uint32_t options)
1918{
1919    IOReturn    ret = kIOReturnUnsupported;
1920
1921	DLOG("%s::kernelRequestProbe(%x)\n", device->getName(), options);
1922
1923	if ((kIOPCIProbeOptionEject & options) && device->getProperty(kIOPCIEjectableKey))
1924	{
1925		ret = configOp(device, kConfigOpEject, 0);
1926		device = OSDynamicCast(IOPCIDevice, getProvider());
1927		if (!device)
1928			return (ret);
1929		options |= kIOPCIProbeOptionNeedsScan;
1930		options &= ~kIOPCIProbeOptionEject;
1931	}
1932
1933	if (kIOPCIProbeOptionNeedsScan & options)
1934	{
1935		bool bootDefer = (0 != device->getProperty(kIOPCITunnelBootDeferKey));
1936		if (bootDefer)
1937		{
1938			IOPCI2PCIBridge * p2pBridge;
1939			if ((p2pBridge = OSDynamicCast(IOPCI2PCIBridge, this)))
1940				p2pBridge->startBootDefer(device);
1941
1942			return (kIOReturnSuccess);
1943		}
1944
1945		ret = configOp(device, kConfigOpNeedsScan, 0);
1946	}
1947
1948    if (kIOPCIProbeOptionDone & options) ret = configOp(device, kConfigOpScan, NULL);
1949
1950    return (ret);
1951}
1952
1953IOReturn IOPCIBridge::protectDevice(IOPCIDevice * device, uint32_t space, uint32_t prot)
1954{
1955    IOReturn ret;
1956
1957	prot &= (VM_PROT_READ|VM_PROT_WRITE);
1958	prot <<= kPCIDeviceStateConfigProtectShift;
1959
1960    DLOG("%s::protectDevice(%x, %x)\n", device->getName(), space, prot);
1961
1962    ret = configOp(device, kConfigOpProtect, &prot);
1963
1964	return (ret);
1965}
1966
1967void IOPCIBridge::probeBus( IOService * provider, UInt8 busNum )
1968{
1969    IORegistryEntry *  found;
1970    OSDictionary *     propTable;
1971    IOPCIDevice *      nub = 0;
1972    OSIterator *       kidsIter;
1973    UInt32             index = 0;
1974    UInt32             idx = 0;
1975    bool               hotplugBus;
1976
1977//    kprintf("probe: %s\n", provider->getName());
1978
1979    hotplugBus = (0 != getProperty(kIOPCIHotPlugKey));
1980    if (hotplugBus && !provider->getProperty(kIOPCIOnlineKey))
1981    {
1982        DLOG("offline\n");
1983        return;
1984    }
1985
1986    IODTSetResolving(provider, &compareAddressCell, &nvLocation);
1987
1988    kidsIter = provider->getChildIterator( gIODTPlane );
1989
1990    // find and copy over any devices from the device tree
1991    OSArray * nubs = OSArray::withCapacity(0x10);
1992    assert(nubs);
1993
1994    if (kidsIter) {
1995        kidsIter->reset();
1996        while ((found = (IORegistryEntry *) kidsIter->getNextObject()))
1997        {
1998//            kprintf("probe: %s, %s\n", provider->getName(), found->getName());
1999            if (!found->getProperty("vendor-id")) continue;
2000            if (found->inPlane(gIOServicePlane))  continue;
2001            nub = OSDynamicCast(IOPCIDevice, found);
2002            if (!nub) continue;
2003            propTable = found->getPropertyTable();
2004			nub->retain();
2005			initializeNub(nub, propTable);
2006
2007            {
2008                IOByteCount capa, msiCapa;
2009				OSData *    data;
2010
2011                nubs->setObject(index++, nub);
2012
2013			    nub->reserved->headerType = (0x7F & nub->configRead8(kIOPCIConfigHeaderType));
2014                capa = 0;
2015                if (nub->extendedFindPCICapability(kIOPCIPowerManagementCapability, &capa))
2016                    nub->reserved->powerCapability = capa;
2017
2018                msiCapa = 0;
2019                nub->extendedFindPCICapability(kIOPCIMSICapability, &msiCapa);
2020                capa = 0;
2021                if ((!msiCapa
2022//                || !strcmp("ethernet", nub->getName())
2023                ) && nub->extendedFindPCICapability(kIOPCIMSIXCapability, &capa))
2024				{
2025                     nub->reserved->msiCapability = capa;
2026                     nub->reserved->msiMode      |= kMSIX;
2027                }
2028				else nub->reserved->msiCapability = msiCapa;
2029
2030                capa = 0;
2031                if (nub->extendedFindPCICapability(kIOPCIExpressLatencyTolerenceReportingCapability, &capa))
2032                    nub->reserved->latencyToleranceCapability = capa;
2033
2034                capa = 0;
2035                if (nub->extendedFindPCICapability(kIOPCIExpressL1PMSubstatesCapability, &capa))
2036                {
2037                    nub->reserved->l1pmCapability = capa;
2038                    nub->reserved->l1pmCaps = (0xFFFFFFF0 | nub->configRead32(capa + 0x04));
2039                }
2040
2041                capa = 0;
2042                if (nub->extendedFindPCICapability(kIOPCIPCIExpressCapability, &capa)) {
2043                    nub->reserved->expressCapability = capa;
2044                    nub->reserved->expressCapabilities = nub->configRead16(capa + 0x02);
2045                    nub->reserved->aspmCaps = (3 & (nub->configRead32(capa + 0xc) >> 10));
2046#if ACPI_SUPPORT
2047                    // current aspm mode
2048                    nub->reserved->expressASPMDefault = (3 & (nub->configRead16(capa + 0x10)));
2049#else
2050                    nub->reserved->expressASPMDefault = nub->reserved->aspmCaps;
2051#endif
2052		}
2053
2054				if (nub->reserved->expressCapability && nub->reserved->latencyToleranceCapability
2055				 && (data = OSDynamicCast(OSData, nub->getProperty(kIOPCIExpressMaxLatencyKey, gIOServicePlane))))
2056				{
2057					nub->extendedConfigWrite32(nub->reserved->latencyToleranceCapability + 0x04,
2058												*((uint32_t *) data->getBytesNoCopy()));
2059					enableLTR(nub, true);
2060				}
2061
2062                if (nub->reserved->expressCapability)
2063                {
2064					if ((data = OSDynamicCast(OSData, nub->getProperty(kIOPCIExpressASPMDefaultKey))))
2065					{
2066						nub->reserved->expressASPMDefault = *((uint32_t *) data->getBytesNoCopy());
2067						setDeviceASPMState(nub, this, nub->reserved->expressASPMDefault);
2068					}
2069					else
2070					{
2071						nub->setProperty(kIOPCIExpressASPMDefaultKey, nub->reserved->expressASPMDefault, 32);
2072					}
2073                }
2074
2075				if (kPCIHeaderType1 == nub->reserved->headerType)
2076				{
2077					nub->reserved->rootPort = ((0xF0 & nub->reserved->expressCapabilities) == 0x40);
2078					uint16_t bridgeControl = nub->configRead16(kPCI2PCIBridgeControl);
2079					bridgeControl |= 0x0002;	// SERR forward
2080					nub->configWrite16(kPCI2PCIBridgeControl, bridgeControl);
2081				}
2082                capa = 0;
2083                if (nub->extendedFindPCICapability(kIOPCIExpressErrorReportingCapability, &capa))
2084                {
2085                    nub->reserved->aerCapability = capa;
2086
2087					uint32_t dcEnables = 0;
2088					uint32_t sdata = 0;
2089
2090					enum { kDeviceControlAllErrors	= ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) };
2091					if (kIOPCIConfiguratorAER & gIOPCIFlags) dcEnables |= kDeviceControlAllErrors;
2092
2093					if ((data = OSDynamicCast(OSData, nub->getProperty(kIOPCIExpressErrorControlKey, gIOServicePlane))))
2094					{
2095						nub->configWrite32(nub->reserved->aerCapability + 0x18,
2096													*((uint32_t *) data->getBytesNoCopy()));
2097					}
2098					if ((data = OSDynamicCast(OSData, nub->getProperty(kIOPCIExpressErrorUncorrectableSeverityKey, gIOServicePlane))))
2099					{
2100						nub->configWrite32(nub->reserved->aerCapability + 0x0C,
2101													*((uint32_t *) data->getBytesNoCopy()));
2102					}
2103					if ((data = OSDynamicCast(OSData, nub->getProperty(kIOPCIExpressErrorUncorrectableMaskKey, gIOServicePlane))))
2104					{
2105						sdata = ((uint32_t *) data->getBytesNoCopy())[0];
2106						nub->configWrite32(nub->reserved->aerCapability + 0x04, sdata);
2107						nub->configWrite32(nub->reserved->aerCapability + 0x08, sdata);
2108					}
2109					if ((data = OSDynamicCast(OSData, nub->getProperty(kIOPCIExpressErrorCorrectableMaskKey, gIOServicePlane))))
2110					{
2111						sdata = ((uint32_t *) data->getBytesNoCopy())[0];
2112						nub->configWrite32(nub->reserved->aerCapability + 0x10, sdata);
2113						nub->configWrite32(nub->reserved->aerCapability + 0x14, sdata);
2114					}
2115
2116					if (dcEnables)
2117					{
2118						uint32_t deviceControl = nub->configRead32(nub->reserved->expressCapability + 0x08);
2119						deviceControl |= dcEnables;
2120						nub->configWrite32(nub->reserved->expressCapability + 0x08, deviceControl);
2121#if 0
2122						uint16_t cmd = nub->configRead32(kIOPCIConfigCommand);
2123						cmd |= kIOPCICommandSERR;
2124						nub->configWrite32(kIOPCIConfigCommand, cmd);
2125#endif
2126					}
2127				}
2128
2129                nub->release();
2130            }
2131        }
2132    }
2133
2134    idx = 0;
2135    while ((nub = (IOPCIDevice *)nubs->getObject(idx++)))
2136    {
2137        if (hotplugBus || provider->getProperty(kIOPCIEjectableKey))
2138        {
2139			nub->setProperty(kIOPCIEjectableKey, kOSBooleanTrue);
2140        }
2141
2142        publishNub(nub , idx);
2143    }
2144
2145    nubs->release();
2146    if (kidsIter)
2147        kidsIter->release();
2148}
2149
2150/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2151
2152bool IOPCIBridge::addBridgeIORange( IOByteCount start, IOByteCount length )
2153{
2154    bool ok;
2155
2156    // fix - ACPIPCI makes this up for hosts with zero space
2157    if ((0x0 == start) && (0x10000 == length))
2158        return (false);
2159
2160    ok = IOPCIRangeListAddRange(&reserved->rangeLists[kIOPCIResourceTypeIO],
2161                                kIOPCIResourceTypeIO,
2162                                start, length);
2163    return (ok);
2164}
2165
2166bool IOPCIBridge::addBridgeMemoryRange( IOPhysicalAddress start,
2167                                        IOPhysicalLength length, bool host )
2168{
2169    bool ok;
2170
2171    // fix - ACPIPCI makes this up for hosts with zero space
2172    if ((0x80000000 == start) && (0x7f000000 == length))
2173        return (false);
2174
2175    ok = IOPCIRangeListAddRange(&reserved->rangeLists[kIOPCIResourceTypeMemory],
2176                                kIOPCIResourceTypeMemory,
2177                                start, length);
2178    return (ok);
2179
2180}
2181
2182bool IOPCIBridge::addBridgePrefetchableMemoryRange( addr64_t start,
2183                                                    addr64_t length )
2184{
2185    bool ok;
2186    ok = IOPCIRangeListAddRange(&reserved->rangeLists[kIOPCIResourceTypePrefetchMemory],
2187                                kIOPCIResourceTypePrefetchMemory,
2188                                start, length);
2189    return (ok);
2190}
2191
2192bool IOPCIBridge::addBridgePrefetchableMemoryRange( IOPhysicalAddress start,
2193                                                    IOPhysicalLength length,
2194                                                    bool host )
2195{
2196    return (addBridgePrefetchableMemoryRange(start, length));
2197}
2198
2199/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2200
2201bool IOPCIBridge::constructRange( IOPCIAddressSpace * flags,
2202                                  IOPhysicalAddress64 phys,
2203                                  IOPhysicalLength64 len,
2204                                  OSArray * array )
2205{
2206    IOMemoryDescriptor *    md;
2207    IOMemoryDescriptor *    ioMemory;
2208	IOSubMemoryDescriptor * subMem;
2209	IOAddressRange 		    range;
2210    bool                    ok;
2211    unsigned int            idx;
2212
2213    for (idx = 0;
2214    	 (md = (IODeviceMemory *) array->getObject(idx))
2215          	&& (flags->s.registerNum != (md->getTag() & 0xff));
2216         idx++) {}
2217
2218	if (md)
2219	{
2220		md->retain();
2221		md->redirect(TASK_NULL, true);
2222
2223		DLOG("reloc at (%u:%u:%u:0x%x) 0x%qx, 0x%qx -> 0x%qx, 0x%qx\n",
2224			 flags->s.busNum, flags->s.deviceNum, flags->s.functionNum, flags->s.registerNum,
2225			 md->getPhysicalSegment(0, 0, kIOMemoryMapperNone), (uint64_t) md->getLength(),
2226			 phys, len);
2227
2228		if ((subMem = OSDynamicCast(IOSubMemoryDescriptor, md)))
2229		{
2230			ok = subMem->initSubRange(ioDeviceMemory(), phys, len, (IODirection) kIOMemoryThreadSafe);
2231		}
2232		else
2233		{
2234			range.address = phys;
2235			range.length  = len;
2236			ok = md->initWithOptions(&range, 1, 0, TASK_NULL,
2237									 kIOMemoryTypePhysical64
2238									 // | kIOMemoryRedirected
2239									 | kIODirectionNone
2240									 | kIOMemoryMapperNone,
2241									 NULL);
2242		}
2243		if (!ok) panic("IOMD::initWithOptions");
2244		md->redirect(TASK_NULL, false);
2245	}
2246	else
2247	{
2248		if (kIOPCIIOSpace == flags->s.space)
2249		{
2250			if (!(ioMemory = ioDeviceMemory()))
2251				md = 0;
2252			else
2253			{
2254				phys &= 0x00ffffff; // seems bogus
2255				md = IOSubMemoryDescriptor::withSubRange(ioMemory, phys, len, kIOMemoryThreadSafe);
2256				if (md == 0)
2257				{
2258					/* didn't fit */
2259					md = IOMemoryDescriptor::withAddressRange(
2260								phys + ioMemory->getPhysicalSegment(0, 0, kIOMemoryMapperNone),
2261								len, kIODirectionNone | kIOMemoryHostOnly, NULL );
2262				}
2263			}
2264		}
2265		else
2266		{
2267			md = IOMemoryDescriptor::withAddressRange(
2268								phys, len, kIODirectionNone | kIOMemoryMapperNone, NULL);
2269		}
2270        ok = array->setObject(md);
2271	}
2272
2273    if (md)
2274	{
2275        md->setTag( flags->bits );
2276        md->release();
2277    }
2278    else
2279        ok = false;
2280
2281    return (ok);
2282}
2283
2284IOReturn IOPCIBridge::getDTNubAddressing( IOPCIDevice * regEntry )
2285{
2286    OSArray *           array;
2287    IORegistryEntry *   parentEntry;
2288    OSData *            addressProperty;
2289#if defined(__i386__) || defined(__x86_64__)
2290    IOPhysicalAddress64 phys;
2291    IOPhysicalLength64  len;
2292#else
2293    IOPhysicalAddress phys;
2294    IOPhysicalLength  len;
2295#endif
2296    UInt32              cells = 5;
2297    int                 i, num;
2298    UInt32 *            reg;
2299
2300    addressProperty = (OSData *) regEntry->getProperty( "assigned-addresses" );
2301    if (0 == addressProperty)
2302        return (kIOReturnSuccess);
2303
2304    parentEntry = regEntry->getParentEntry( gIODTPlane );
2305    if (0 == parentEntry)
2306        return (kIOReturnBadArgument);
2307
2308    array = (OSArray *) regEntry->copyProperty(gIODeviceMemoryKey);
2309	if (array)
2310	{
2311		OSArray * newArray;
2312		newArray = OSArray::withArray(array);
2313		array->release();
2314		array = newArray;
2315	}
2316
2317	if (!array) array = OSArray::withCapacity(4);
2318    if (!array) return (kIOReturnNoMemory);
2319
2320    reg = (UInt32 *) addressProperty->getBytesNoCopy();
2321    num = addressProperty->getLength() / (sizeof(UInt32) * cells);
2322
2323    for (i = 0; i < num; i++)
2324    {
2325#if defined(__i386__) || defined(__x86_64__)
2326		phys = ((IOPhysicalAddress64) reg[1] << 32) | reg[2];
2327		len = ((IOPhysicalLength64) reg[3] << 32) | reg[4];
2328		constructRange( (IOPCIAddressSpace *) reg, phys, len, array );
2329#else
2330		if (IODTResolveAddressCell(parentEntry, reg, &phys, &len))
2331			constructRange( (IOPCIAddressSpace *) reg, phys, len, array );
2332#endif
2333        reg += cells;
2334    }
2335
2336    if (array->getCount())
2337        regEntry->setProperty( gIODeviceMemoryKey, array);
2338
2339    array->release();
2340
2341    return (kIOReturnSuccess);
2342}
2343
2344IOReturn IOPCIBridge::getNubAddressing( IOPCIDevice * nub )
2345{
2346    return (kIOReturnError);
2347}
2348
2349bool IOPCIBridge::isDTNub( IOPCIDevice * nub )
2350{
2351    return (true);
2352}
2353
2354IOReturn IOPCIBridge::getNubResources( IOService * service )
2355{
2356    IOPCIDevice *       nub = (IOPCIDevice *) service;
2357    IOReturn            err;
2358
2359    if (service->getProperty(kIOPCIResourcedKey))
2360        return (kIOReturnSuccess);
2361    service->setProperty(kIOPCIResourcedKey, kOSBooleanTrue);
2362
2363    err = getDTNubAddressing( nub );
2364
2365    bool
2366    msiDefault = (false
2367#if 0
2368                    || (0 == strcmp("display", nub->getName()))
2369                    || (0 == strcmp("GFX0", nub->getName()))
2370                    || (0 == strcmp("PXS1", nub->getName()))        // yukon
2371                    || (0 == strcmp("HDEF", nub->getName()))
2372                    || (0 == strcmp("SATA", nub->getName()))
2373                    || (0 == strcmp("LAN0", nub->getName()))
2374                    || (0 == strcmp("LAN1", nub->getName()))
2375                    || (0 == strcmp("PXS2", nub->getName()))        // airport
2376                    || (0 == strcmp("PXS3", nub->getName()))        // express
2377#endif
2378    );
2379
2380    IOService * provider = getProvider();
2381    if (msiDefault)
2382        resolveMSIInterrupts( provider, nub );
2383    resolveLegacyInterrupts( provider, nub );
2384    if (!msiDefault)
2385        resolveMSIInterrupts( provider, nub );
2386
2387    return (err);
2388}
2389
2390IOReturn IOPCIBridge::relocate(IOPCIDevice * device, uint32_t options)
2391{
2392    spaceFromProperties(device, &device->space);
2393	return (getDTNubAddressing(device));
2394}
2395
2396bool IOPCIBridge::matchKeys( IOPCIDevice * nub, const char * keys,
2397                             UInt32 defaultMask, UInt8 regNum )
2398{
2399    const char *        next;
2400    UInt32              mask, value, reg;
2401    bool                found = false;
2402
2403    do
2404    {
2405        value = strtoul( keys, (char **) &next, 16);
2406        if (next == keys)
2407            break;
2408
2409        while ((*next) == ' ')
2410            next++;
2411
2412        if ((*next) == '&')
2413            mask = strtoul( next + 1, (char **) &next, 16);
2414        else
2415            mask = defaultMask;
2416
2417        reg = nub->savedConfig[ regNum >> 2 ];
2418        found = ((value & mask) == (reg & mask));
2419        keys = next;
2420    }
2421    while (!found);
2422
2423    return (found);
2424}
2425
2426
2427bool IOPCIBridge::pciMatchNub( IOPCIDevice * nub,
2428                               OSDictionary * table,
2429                               SInt32 * score )
2430{
2431    OSString *          prop;
2432    const char *        keys;
2433    bool                match = true;
2434    UInt8               regNum;
2435    int                 i;
2436
2437    struct IOPCIMatchingKeys
2438    {
2439        const char *    propName;
2440        UInt8           regs[ 4 ];
2441        UInt32          defaultMask;
2442    };
2443    const IOPCIMatchingKeys *              look;
2444    static const IOPCIMatchingKeys matching[] = {
2445                                              { kIOPCIMatchKey,
2446                                                { 0x00 + 1, 0x2c }, 0xffffffff },
2447                                              { kIOPCIPrimaryMatchKey,
2448                                                { 0x00 }, 0xffffffff },
2449                                              { kIOPCISecondaryMatchKey,
2450                                                { 0x2c }, 0xffffffff },
2451                                              { kIOPCIClassMatchKey,
2452                                                { 0x08 }, 0xffffff00 }};
2453
2454    for (look = matching;
2455            (match && (look < &matching[4]));
2456            look++)
2457    {
2458        prop = (OSString *) table->getObject( look->propName );
2459        if (prop)
2460        {
2461            keys = prop->getCStringNoCopy();
2462            match = false;
2463            for (i = 0;
2464                    ((false == match) && (i < 4));
2465                    i++)
2466            {
2467                regNum = look->regs[ i ];
2468                match = matchKeys( nub, keys,
2469                                   look->defaultMask, regNum & 0xfc );
2470                if (0 == (1 & regNum))
2471                    break;
2472            }
2473        }
2474    }
2475
2476    return (match);
2477}
2478
2479bool IOPCIBridge::matchNubWithPropertyTable( IOService * nub,
2480        OSDictionary * table,
2481        SInt32 * score )
2482{
2483    bool        matches;
2484
2485    matches = pciMatchNub( (IOPCIDevice *) nub, table, score);
2486
2487	if (matches)
2488	{
2489		OSString  * classProp;
2490		classProp = OSDynamicCast(OSString, table->getObject(kIOClassKey));
2491//		classProp = OSDynamicCast(OSString, table->getObject(kCFBundleIdentifierKey));
2492		if (classProp)
2493		{
2494  			if (nub->getProperty(gIOPCITunnelledKey))
2495        	{
2496        		if (!classProp->isEqualTo("IOPCI2PCIBridge"))
2497				{
2498					if (!table->getObject(kIOPCITunnelCompatibleKey))
2499					{
2500						IOLog("Driver \"%s\" needs \"%s\" key in plist\n",
2501								classProp->getCStringNoCopy(), kIOPCITunnelCompatibleKey);
2502					}
2503					if ((kIOPCIConfiguratorNoTunnelDrv & gIOPCIFlags)
2504					  || (kOSBooleanFalse == table->getObject(kIOPCITunnelCompatibleKey))
2505					  || ((kOSBooleanTrue != table->getObject(kIOPCITunnelCompatibleKey))
2506							&& (kIOPCIConfiguratorCheckTunnel & gIOPCIFlags))
2507					 )
2508					{
2509						matches = false;
2510					}
2511        		}
2512        	}
2513		}
2514	}
2515
2516//	if (matches && (!strncmp("pci1033", nub->getName(), strlen("pci1033")))) matches = false;
2517
2518    return (matches);
2519}
2520
2521bool IOPCIBridge::compareNubName( const IOService * nub,
2522                                  OSString * name, OSString ** matched ) const
2523{
2524    return (IODTCompareNubName(nub, name, matched));
2525}
2526
2527UInt32 IOPCIBridge::findPCICapability( IOPCIAddressSpace space,
2528                                       UInt8 capabilityID, UInt8 * found )
2529{
2530    UInt32      data = 0;
2531    UInt8       offset;
2532
2533    if (found)
2534        *found = 0;
2535
2536    if (0 == ((kIOPCIStatusCapabilities << 16)
2537              & (configRead32(space, kIOPCIConfigCommand))))
2538        return (0);
2539
2540    offset = (0xff & configRead32(space, kIOPCIConfigCapabilitiesPtr));
2541    if (offset & 3)
2542        offset = 0;
2543    while (offset)
2544    {
2545        data = configRead32( space, offset );
2546        if (capabilityID == (data & 0xff))
2547        {
2548            if (found)
2549                *found = offset;
2550            break;
2551        }
2552        offset = (data >> 8) & 0xff;
2553        if (offset & 3)
2554            offset = 0;
2555    }
2556
2557    return (offset ? data : 0);
2558}
2559
2560UInt32 IOPCIBridge::extendedFindPCICapability( IOPCIAddressSpace space,
2561                                                UInt32 capabilityID, IOByteCount * found )
2562{
2563	uint32_t result;
2564	uint32_t firstOffset = 0;
2565
2566	if (found)
2567		firstOffset = *found;
2568	result = gIOPCIConfigurator->findPCICapability(space, capabilityID, &firstOffset);
2569	if (found)
2570		*found = firstOffset;
2571
2572	return ((UInt32) result);
2573}
2574
2575/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2576
2577IOReturn IOPCIBridge::createAGPSpace( IOAGPDevice * master,
2578                                      IOOptionBits options,
2579                                      IOPhysicalAddress * address,
2580                                      IOPhysicalLength * length )
2581{
2582    return (kIOReturnUnsupported);
2583}
2584
2585IOReturn IOPCIBridge::destroyAGPSpace( IOAGPDevice * master )
2586{
2587    return (kIOReturnUnsupported);
2588}
2589
2590IORangeAllocator * IOPCIBridge::getAGPRangeAllocator( IOAGPDevice * master )
2591{
2592    return (0);
2593}
2594
2595IOOptionBits IOPCIBridge::getAGPStatus( IOAGPDevice * master,
2596                                        IOOptionBits options )
2597{
2598    return (0);
2599}
2600
2601IOReturn IOPCIBridge::commitAGPMemory( IOAGPDevice * master,
2602                                       IOMemoryDescriptor * memory,
2603                                       IOByteCount agpOffset,
2604                                       IOOptionBits options )
2605{
2606    return (kIOReturnUnsupported);
2607}
2608
2609IOReturn IOPCIBridge::releaseAGPMemory( IOAGPDevice * master,
2610                                        IOMemoryDescriptor * memory,
2611                                        IOByteCount agpOffset,
2612                                        IOOptionBits options )
2613{
2614    return (kIOReturnUnsupported);
2615}
2616
2617IOReturn IOPCIBridge::resetAGPDevice( IOAGPDevice * master,
2618                                      IOOptionBits options )
2619{
2620    return (kIOReturnUnsupported);
2621}
2622
2623IOReturn IOPCIBridge::getAGPSpace( IOAGPDevice * master,
2624                                   IOPhysicalAddress * address,
2625                                   IOPhysicalLength * length )
2626{
2627    return (kIOReturnUnsupported);
2628}
2629
2630/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2631
2632#undef super
2633#define super IOPCIBridge
2634
2635OSDefineMetaClassAndStructors(IOPCI2PCIBridge, IOPCIBridge)
2636OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  0);
2637OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  1);
2638OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  2);
2639OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  3);
2640OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  4);
2641OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  5);
2642OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  6);
2643OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  7);
2644OSMetaClassDefineReservedUnused(IOPCI2PCIBridge,  8);
2645
2646/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2647
2648IOService * IOPCI2PCIBridge::probe( IOService *         provider,
2649                                    SInt32 *            score )
2650{
2651    if (0 == (fBridgeDevice = OSDynamicCast(IOPCIDevice, provider)))
2652        return (0);
2653
2654    *score              -= 100;
2655
2656    return (this);
2657}
2658
2659bool IOPCI2PCIBridge::serializeProperties( OSSerialize * serialize ) const
2660{
2661    return (super::serializeProperties(serialize));
2662}
2663
2664IOReturn IOPCIBridge::checkLink(uint32_t options)
2665{
2666    return (kIOReturnSuccess);
2667}
2668
2669IOReturn IOPCI2PCIBridge::checkLink(uint32_t options)
2670{
2671	IOReturn ret;
2672	bool     present;
2673	uint16_t linkStatus;
2674
2675	AbsoluteTime startTime, endTime;
2676	uint64_t 	 nsec, nsec2;
2677
2678	ret = fBridgeDevice->checkLink(options & ~kCheckLinkParents);
2679	if (kIOReturnSuccess != ret) return (kIOReturnNoDevice);
2680
2681	if ((kCheckLinkParents & options) || !fHotPlugInts || !fBridgeInterruptSource) return (ret);
2682
2683	clock_get_uptime(&startTime);
2684	linkStatus = fBridgeDevice->configRead16(fBridgeDevice->reserved->expressCapability + 0x12);
2685
2686#if 1
2687	clock_get_uptime(&endTime);
2688	absolutetime_to_nanoseconds(startTime, &nsec2);
2689	SUB_ABSOLUTETIME(&endTime, &startTime);
2690	absolutetime_to_nanoseconds(endTime, &nsec);
2691
2692	if (nsec > 1000*1000)
2693	{
2694		DLOG("%s: @%lld link %x took %lld us link %x\n",
2695			fLogName, nsec2 / 1000,
2696			linkStatus, nsec / 1000,
2697			fBridgeDevice->checkLink(options));
2698	}
2699#endif
2700
2701	if (0xffff == linkStatus)
2702		return (kIOReturnNoDevice);
2703
2704	present = (0 != ((1 << 13) & linkStatus));
2705	if (fPresenceInt != present)
2706	{
2707		fPresenceInt = present;
2708		if (!present)
2709		{
2710			fBridgeDevice->configWrite32(kPCI2PCIMemoryRange,         0);
2711			fBridgeDevice->configWrite32(kPCI2PCIPrefetchMemoryRange, 0);
2712			fBridgeDevice->configWrite32(kPCI2PCIPrefetchUpperBase,   0);
2713			fBridgeDevice->configWrite32(kPCI2PCIPrefetchUpperLimit,  0);
2714		}
2715		DLOG("%s: @%lld -> present %d\n",
2716			fLogName, nsec / 1000, present);
2717	}
2718
2719	return (present ? kIOReturnSuccess : kIOReturnOffline);
2720}
2721
2722enum {
2723	kIntsHP  = 0x00000001,
2724	kIntsAER = 0x00000002,
2725};
2726
2727bool IOPCI2PCIBridge::filterInterrupt(IOFilterInterruptEventSource * source)
2728{
2729	IOReturn ret;
2730	uint8_t  intsPending = 0;
2731
2732//	DLOG("%s: filterInterrupt\n",
2733//		fLogName);
2734
2735	if (kIOPCIDeviceOffState == fPowerState) return (false);
2736	if (fNoDevice)     						 return (false);
2737	ret = checkLink();
2738	if (kIOReturnNoDevice == ret)
2739	{
2740		fNoDevice = true;
2741		return (false);
2742	}
2743
2744	if (fHotPlugInts)
2745	{
2746		enum { kNeedMask = ((1 << 8) | (1 << 3)) };
2747
2748		uint16_t slotStatus = fBridgeDevice->configRead16( fBridgeDevice->reserved->expressCapability + 0x1a );
2749//		if (kNeedMask & slotStatus)
2750			fBridgeDevice->configWrite16( fBridgeDevice->reserved->expressCapability + 0x1a, slotStatus );
2751
2752		if (0 != (kNeedMask & slotStatus)) intsPending |= kIntsHP;
2753	}
2754
2755	IOPCIAERRoot * root;
2756	if ((root = fAERRoot))
2757	{
2758		enum { kNeedMask = ((1 << 2) | (1 << 0)) };
2759
2760		uint32_t status = fBridgeDevice->configRead32(fBridgeDevice->reserved->aerCapability + 0x30);
2761		if (0 != (kNeedMask & status))
2762		{
2763			IOInterruptState ints;
2764			uint8_t          nextIdx;
2765
2766			ints    = IOSimpleLockLockDisableInterrupt(fISRLock);
2767			nextIdx = root->fAERWriteIndex + 1;
2768			if (nextIdx == kAERISRNum) nextIdx = 0;
2769			if (nextIdx != root->fAERReadIndex)
2770			{
2771				root->fISRErrors[root->fAERWriteIndex].status = status;
2772				root->fISRErrors[root->fAERWriteIndex].source = fBridgeDevice->configRead32(fBridgeDevice->reserved->aerCapability + 0x34);
2773				root->fAERWriteIndex = nextIdx;
2774			}
2775			IOSimpleLockUnlockEnableInterrupt(fISRLock, ints);
2776			intsPending |= kIntsAER;
2777		}
2778		fBridgeDevice->configWrite16(fBridgeDevice->reserved->aerCapability + 0x30, status);
2779	}
2780
2781	OSBitOrAtomic8(intsPending, &fIntsPending);
2782
2783    return (intsPending != 0);
2784}
2785
2786void IOPCI2PCIBridge::handleInterrupt(IOInterruptEventSource * source, int count)
2787{
2788	uint8_t intsPending = 0;
2789
2790	intsPending = fIntsPending;
2791	OSBitAndAtomic8(~intsPending, &fIntsPending);
2792
2793	if (kIntsHP & intsPending)
2794	{
2795		bool present;
2796		UInt32 probeTimeMS = 1;
2797
2798		fHotplugCount++;
2799
2800		uint16_t slotStatus  = fBridgeDevice->configRead16( fBridgeDevice->reserved->expressCapability + 0x1a );
2801		uint16_t linkStatus  = fBridgeDevice->configRead16( fBridgeDevice->reserved->expressCapability + 0x12 );
2802		uint16_t linkControl = fBridgeDevice->configRead16( fBridgeDevice->reserved->expressCapability + 0x10 );
2803
2804		DLOG("%s: hotpInt (%d), fNeedProbe %d, slotStatus %x, linkStatus %x, linkControl %x\n",
2805				fLogName,
2806				fHotplugCount, fNeedProbe, slotStatus, linkStatus, linkControl);
2807
2808		present = (0 != ((1 << 6) & slotStatus));
2809
2810		if (fLinkControlWithPM)
2811		{
2812			uint16_t pmBits = fBridgeDevice->configRead16(fBridgeDevice->reserved->powerCapability + 4);
2813			if (present && (kPCIPMCSPowerStateD0 != (kPCIPMCSPowerStateMask & pmBits)))
2814			{
2815				DLOG("%s: pwr on\n", fLogName);
2816				fBridgeDevice->configWrite16(fBridgeDevice->reserved->powerCapability + 4, kPCIPMCSPMEStatus | kPCIPMCSPowerStateD0);
2817				IOSleep(10);
2818			}
2819		}
2820
2821		if (present && ((1 << 4) & linkControl))
2822		{
2823			DLOG("%s: enabling link\n", fLogName);
2824			linkControl &= ~((1 << 4) | (1 << 6));
2825			fBridgeDevice->configWrite16( fBridgeDevice->reserved->expressCapability + 0x10, linkControl );
2826			fWaitingLinkEnable = true;
2827			present = false;
2828		}
2829		else if (!present)
2830		{
2831			if (fLinkControlWithPM)
2832			{
2833				DLOG("%s: pwr off\n", fLogName);
2834				fBridgeDevice->configWrite16(fBridgeDevice->reserved->powerCapability + 4, (kPCIPMCSPMEStatus | kPCIPMCSPMEEnable | kPCIPMCSPowerStateD3));
2835			}
2836			else if (!((1 << 4) & linkControl))
2837			{
2838				if (fWaitingLinkEnable)
2839					fWaitingLinkEnable = false;
2840				else
2841				{
2842					DLOG("%s: disabling link\n", fLogName);
2843					linkControl &= ~(1 << 6);
2844					linkControl |= (1 << 4);
2845					fBridgeDevice->configWrite16(fBridgeDevice->reserved->expressCapability + 0x10, linkControl);
2846				}
2847			}
2848		}
2849		if (fLinkChangeOnly)
2850			return;
2851
2852		present &= (0 != ((1 << 13) & linkStatus));
2853
2854		if (fPresence != present)
2855		{
2856			DLOG("%s: now present %d\n", fLogName, present);
2857
2858			fBridgeDevice->removeProperty(kIOPCIConfiguredKey);
2859			fNeedProbe = true;
2860			fPresence = present;
2861			if (!present)
2862			{
2863				// not present
2864				fBridgeDevice->removeProperty(kIOPCIOnlineKey);
2865			}
2866			else
2867			{
2868				// present
2869				fBridgeDevice->setProperty(kIOPCIOnlineKey, true);
2870				probeTimeMS = 2000;
2871			}
2872		}
2873
2874		if (fNeedProbe)
2875		{
2876			if (kIOPMUndefinedDriverAssertionID == fPMAssertion)
2877			{
2878				fPMAssertion = getPMRootDomain()->createPMAssertion(
2879									kIOPMDriverAssertionCPUBit, kIOPMDriverAssertionLevelOn,
2880									this, "com.apple.iokit.iopcifamily");
2881			}
2882			fTimerProbeES->setTimeoutMS(probeTimeMS);
2883		}
2884	}
2885
2886	if (kIntsAER & intsPending)
2887	{
2888		IOPCIAERRoot *     root = fAERRoot;
2889		IOPCIAddressSpace  space;
2890		IOInterruptState   ints;
2891		IOService *        result;
2892		IOPCIDevice *      device;
2893		IOPCIEventSource * src;
2894		IOReturn           ret;
2895		uint8_t            nextIdx;
2896		uint32_t           correctable, source, rstatus, status, severity;
2897		IOPCIEvent		   newEvent;
2898
2899		ints = IOSimpleLockLockDisableInterrupt(fISRLock);
2900		while (root->fAERReadIndex != root->fAERWriteIndex)
2901		{
2902			rstatus = root->fISRErrors[root->fAERReadIndex].status;
2903			source  = root->fISRErrors[root->fAERReadIndex].source;
2904			nextIdx = root->fAERReadIndex + 1;
2905			if (nextIdx == kAERISRNum) nextIdx = 0;
2906			root->fAERReadIndex = nextIdx;
2907			IOSimpleLockUnlockEnableInterrupt(fISRLock, ints);
2908
2909			DLOG("%s: AER root status %x\n", fLogName, rstatus);
2910			for (correctable = 0; correctable < 2; correctable++, source <<= 16)
2911			{
2912				if (!((correctable ? 1 : 4) & rstatus)) continue;
2913				space.s.busNum      = (source >> 24);
2914				space.s.deviceNum   = (31 & (source >> 19));
2915				space.s.functionNum = (7  & (source >> 16));
2916				ret = configOp(NULL, kConfigOpFindEntry, &result, &space);
2917				DLOG("AER source %d %d %d: find %x %p %s 0x%qx\n",
2918						space.s.busNum, space.s.deviceNum, space.s.functionNum, ret, result,
2919						result ? result->getName() : "",
2920						result ? result->getRegistryEntryID() : 0);
2921				if (kIOReturnSuccess != ret) continue;
2922
2923				if ((device = OSDynamicCast(IOPCIDevice, result))
2924					 && device->reserved->aerCapability)
2925				{
2926					status   = device->configRead32(device->reserved->aerCapability + (correctable ? 0x10 : 0x04));
2927					severity = (correctable ? 0 : device->configRead32(device->reserved->aerCapability + 0x0c));
2928					newEvent.data[0] = status;
2929					newEvent.data[1] = device->configRead32(device->reserved->aerCapability + 0x1c);
2930					newEvent.data[2] = device->configRead32(device->reserved->aerCapability + 0x20);
2931					newEvent.data[3] = device->configRead32(device->reserved->aerCapability + 0x24);
2932					newEvent.data[4] = device->configRead32(device->reserved->aerCapability + 0x28);
2933
2934					DLOG("AER %scorrectable status 0x%08x sev 0x%08x TLP 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2935							correctable ? "" : "un", status, severity,
2936							newEvent.data[1], newEvent.data[2], newEvent.data[3], newEvent.data[4]);
2937
2938					IOSimpleLockLock(gIOPCIEventSourceLock);
2939					queue_iterate(&gIOPCIEventSourceQueue, src, IOPCIEventSource *, fQ)
2940					{
2941						if (src->fRoot && (this != src->fRoot)) continue;
2942						nextIdx = src->fWriteIndex + 1;
2943						if (nextIdx == kIOPCIEventNum) nextIdx = 0;
2944						if (nextIdx != src->fReadIndex)
2945						{
2946							src->fEvents[src->fWriteIndex].event =
2947								correctable ? kIOPCIEventCorrectableError
2948											: ((status & severity) ? kIOPCIEventFatalError : kIOPCIEventNonFatalError);
2949							device->retain();
2950							src->fEvents[src->fWriteIndex].reporter = device;
2951							memcpy(&src->fEvents[src->fWriteIndex].data[0],
2952									&newEvent.data[0],
2953									sizeof(src->fEvents[src->fWriteIndex].data));
2954							src->fWriteIndex = nextIdx;
2955						}
2956						if (src->isEnabled()) src->signalWorkAvailable();
2957					}
2958					IOSimpleLockUnlock(gIOPCIEventSourceLock);
2959				}
2960				result->release();
2961			}
2962			ints = IOSimpleLockLockDisableInterrupt(fISRLock);
2963		}
2964		IOSimpleLockUnlockEnableInterrupt(fISRLock, ints);
2965	}
2966}
2967
2968void IOPCI2PCIBridge::timerProbe(IOTimerEventSource * es)
2969{
2970    if (fNeedProbe && (kIOPCIDeviceOnState == fPowerState))
2971    {
2972        fNeedProbe = false;
2973        DLOG("%s: probe\n", fLogName);
2974        fBridgeDevice->kernelRequestProbe(kIOPCIProbeOptionDone | kIOPCIProbeOptionLinkInt | kIOPCIProbeOptionNeedsScan);
2975    }
2976	if (kIOPMUndefinedDriverAssertionID != fPMAssertion)
2977	{
2978		getPMRootDomain()->releasePMAssertion(fPMAssertion);
2979		fPMAssertion = kIOPMUndefinedDriverAssertionID;
2980	}
2981}
2982
2983bool IOPCI2PCIBridge::start( IOService * provider )
2984{
2985    bool ok;
2986
2987	fPMAssertion = kIOPMUndefinedDriverAssertionID;
2988
2989    setName(kIOPCI2PCIBridgeName);
2990
2991	snprintf(fLogName, sizeof(fLogName), "%s(%u:%u:%u)(%u-%u)",
2992			 fBridgeDevice->getName(), PCI_ADDRESS_TUPLE(fBridgeDevice), firstBusNum(), lastBusNum());
2993
2994    ok = super::start(provider);
2995
2996    if (ok && fBridgeInterruptSource)
2997        changePowerStateTo(kIOPCIDeviceOnState);
2998
2999    return (ok);
3000}
3001
3002bool IOPCI2PCIBridge::configure( IOService * provider )
3003{
3004	fPowerState = kIOPCIDeviceOnState;
3005    if (fBridgeDevice->reserved->powerCapability)
3006	{
3007		fLinkControlWithPM = fBridgeDevice->savedConfig
3008							&& (0x3B488086 == fBridgeDevice->savedConfig[kIOPCIConfigVendorID >> 2]);
3009	}
3010
3011    if (fBridgeDevice->reserved->expressCapability)
3012    do
3013    {
3014        if (fBridgeDevice->getProperty(kIOPCIHotPlugKey))
3015        {
3016        	fHotPlugInts = true;
3017            setProperty(kIOPCIHotPlugKey, kOSBooleanTrue);
3018        }
3019        else if (fBridgeDevice->getProperty(kIOPCILinkChangeKey))
3020        {
3021            setProperty(kIOPCILinkChangeKey, kOSBooleanTrue);
3022        	fHotPlugInts = true;
3023            fLinkChangeOnly = true;
3024        }
3025        else if (fBridgeDevice->getProperty(kIOPCITunnelLinkChangeKey))
3026		{
3027        	fHotPlugInts = true;
3028		}
3029		fIsAERRoot = (fBridgeDevice->reserved->rootPort && fBridgeDevice->reserved->aerCapability);
3030		if (fHotPlugInts || fIsAERRoot)
3031		{
3032			allocateBridgeInterrupts(provider);
3033		}
3034
3035		if (fBridgeInterruptSource && !fBridgeDevice->getProperty(kIOPCITunnelBootDeferKey)) startBridgeInterrupts(provider);
3036    }
3037    while(false);
3038
3039    saveBridgeState();
3040    if (fBridgeDevice->savedConfig)
3041    {
3042        configShadow(fBridgeDevice)->bridge = this;
3043        configShadow(fBridgeDevice)->flags |= kIOPCIConfigShadowBridge;
3044        if (fHotPlugInts)
3045			configShadow(fBridgeDevice)->flags |= kIOPCIConfigShadowBridgeInterrupts;
3046        if (OSTypeIDInst(this) != OSTypeID(IOPCI2PCIBridge))
3047            configShadow(fBridgeDevice)->flags |= kIOPCIConfigShadowBridgeDriver;
3048    }
3049
3050    return (super::configure(provider));
3051}
3052
3053
3054void IOPCI2PCIBridge::allocateBridgeInterrupts(IOService * provider)
3055{
3056	IOReturn ret = kIOReturnSuccess;
3057    do
3058    {
3059		int interruptType;
3060		int intIdx = 1;
3061		for (intIdx = 1; intIdx >= 0; intIdx--)
3062		{
3063			ret = fBridgeDevice->getInterruptType(intIdx, &interruptType);
3064			if (kIOReturnSuccess == ret)
3065			{
3066				fBridgeMSI = (0 != (kIOInterruptTypePCIMessaged & interruptType));
3067				break;
3068			}
3069		}
3070        if (kIOReturnSuccess != ret) break;
3071
3072        fBridgeInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(
3073                      this,
3074                      OSMemberFunctionCast(IOInterruptEventSource::Action,
3075                                            this, &IOPCI2PCIBridge::handleInterrupt),
3076                      OSMemberFunctionCast(IOFilterInterruptEventSource::Filter,
3077                                            this, &IOPCI2PCIBridge::filterInterrupt),
3078                      provider, intIdx);
3079    }
3080    while(false);
3081}
3082
3083
3084void IOPCI2PCIBridge::startBridgeInterrupts(IOService * provider)
3085{
3086	IOReturn ret = kIOReturnSuccess;
3087    do
3088    {
3089        if (!fBridgeInterruptSource) break;
3090
3091        fWorkLoop = gIOPCIConfigurator->getWorkLoop();
3092		fTimerProbeES = IOTimerEventSource::timerEventSource(this,
3093										OSMemberFunctionCast(IOTimerEventSource::Action,
3094															this, &IOPCI2PCIBridge::timerProbe));
3095        if (!fTimerProbeES) break;
3096        ret = fWorkLoop->addEventSource(fTimerProbeES);
3097		if (kIOReturnSuccess != ret) break;
3098        ret = fWorkLoop->addEventSource(fBridgeInterruptSource);
3099		if (kIOReturnSuccess != ret) break;
3100
3101		fISRLock = IOSimpleLockAlloc();
3102		if (!fISRLock) break;
3103		if (fIsAERRoot)
3104		{
3105			fAERRoot = IONew(IOPCIAERRoot, 1);
3106			if (!fAERRoot) break;
3107			bzero(fAERRoot, sizeof(IOPCIAERRoot));
3108			fAERRoot->fISRErrors = IONew(IOPCIAERISREntry, kAERISRNum);
3109			if (!fAERRoot->fISRErrors) break;
3110		}
3111
3112		if (fHotPlugInts)
3113		{
3114			fPresence = (0 != fBridgeDevice->getProperty(kIOPCIOnlineKey));
3115			fPresenceInt = fPresence;
3116		}
3117
3118        fBridgeInterruptEnablePending = true;
3119		enableBridgeInterrupts();
3120	}
3121    while(false);
3122}
3123
3124void IOPCI2PCIBridge::enableBridgeInterrupts(void)
3125{
3126	if (fHotPlugInts)
3127	{
3128		uint16_t slotControl = fBridgeDevice->configRead16( fBridgeDevice->reserved->expressCapability + 0x18 );
3129		fBridgeDevice->configWrite16( fBridgeDevice->reserved->expressCapability + 0x1a, 1 << 3 );
3130		slotControl |= kSlotControlEnables;
3131		fBridgeDevice->configWrite16( fBridgeDevice->reserved->expressCapability + 0x18, slotControl );
3132	}
3133	if (fIsAERRoot)
3134	{
3135		 DLOG("%s: start AER\n", fBridgeDevice->getName());
3136		 uint16_t command = fBridgeDevice->configRead32(fBridgeDevice->reserved->aerCapability + 0x2c);
3137		 fBridgeDevice->configWrite32(fBridgeDevice->reserved->aerCapability + 0x30, 0xff);
3138		 command |= (1 << 0) | (1 << 1) | (1 << 2);
3139		 fBridgeDevice->configWrite32(fBridgeDevice->reserved->aerCapability + 0x2c, command);
3140	}
3141}
3142
3143void IOPCI2PCIBridge::disableBridgeInterrupts(void)
3144{
3145	if (fHotPlugInts)
3146	{
3147		uint16_t slotControl = fBridgeDevice->configRead16( fBridgeDevice->reserved->expressCapability + 0x18 );
3148		slotControl &= ~kSlotControlEnables;
3149		fBridgeDevice->configWrite16( fBridgeDevice->reserved->expressCapability + 0x18, slotControl );
3150	}
3151	if (fIsAERRoot)
3152	{
3153		fBridgeDevice->configWrite32(fBridgeDevice->reserved->aerCapability + 0x2c, 0);
3154	}
3155}
3156
3157
3158void IOPCI2PCIBridge::startBootDefer(IOService * provider)
3159{
3160	DLOG("%s: start boot deferred\n", provider->getName());
3161	provider->removeProperty(kIOPCITunnelBootDeferKey);
3162	startBridgeInterrupts(provider);
3163    if (fBridgeInterruptEnablePending)
3164    {
3165        // enable int source
3166        fBridgeInterruptSource->enable();
3167		fBridgeInterruptSource->signalInterrupt();
3168        fBridgeInterruptEnablePending = false;
3169	}
3170}
3171
3172void IOPCI2PCIBridge::probeBus( IOService * provider, UInt8 busNum )
3173{
3174	bool bootDefer = (0 != provider->getProperty(kIOPCITunnelBootDeferKey));
3175    if (!bootDefer)
3176	{
3177		snprintf(fLogName, sizeof(fLogName), "%s(%u:%u:%u)(%u-%u)",
3178				 fBridgeDevice->getName(), PCI_ADDRESS_TUPLE(fBridgeDevice), firstBusNum(), lastBusNum());
3179		super::probeBus(provider, busNum);
3180		if (fBridgeInterruptEnablePending)
3181		{
3182			// enable hotp ints
3183			fBridgeInterruptSource->enable();
3184			fBridgeInterruptSource->signalInterrupt();
3185			fBridgeInterruptEnablePending = false;
3186		}
3187		return;
3188	}
3189
3190	DLOG("%s: boot probe deferred\n", provider->getName());
3191#if 0
3192	startBootDefer(provider);
3193#endif
3194}
3195
3196IOReturn IOPCI2PCIBridge::requestProbe( IOOptionBits options )
3197{
3198    return (super::requestProbe(options));
3199}
3200
3201IOReturn IOPCI2PCIBridge::setPowerState( unsigned long powerState,
3202                                            IOService * whatDevice )
3203{
3204	IOReturn ret;
3205
3206    if ((powerState != fPowerState)
3207    	&& fBridgeInterruptSource
3208    	&& !fBridgeInterruptEnablePending)
3209	do
3210	{
3211		unsigned long fromPowerState;
3212
3213		fromPowerState = fPowerState;
3214		fPowerState = powerState;
3215
3216		if (kIOPCIDeviceOffState == powerState)
3217		{
3218			if (fHotPlugInts && fNeedProbe) DLOG("%s: sleeping with fNeedProbe\n", fLogName);
3219			disableBridgeInterrupts();
3220			break;
3221		}
3222		if (kIOPCIDeviceOffState == fromPowerState)
3223		{
3224			if (fHotPlugInts)
3225			{
3226				if (fNoDevice) break;
3227				ret = checkLink();
3228				if (kIOReturnNoDevice == ret)
3229				{
3230					fNoDevice = true;
3231					break;
3232				}
3233				fNeedProbe |= fPresence;
3234				OSBitOrAtomic8(kIntsHP, &fIntsPending);
3235			}
3236			enableBridgeInterrupts();
3237		}
3238		if (kIOPCIDeviceOnState == powerState)
3239		{
3240			if (fBridgeDevice->reserved->needsProbe) deferredProbe(fBridgeDevice);
3241			fBridgeInterruptSource->signalInterrupt();
3242		}
3243	}
3244	while (false);
3245
3246    return (super::setPowerState(powerState, whatDevice));
3247}
3248
3249void IOPCI2PCIBridge::adjustPowerState(unsigned long state)
3250{
3251	DLOG("%s: adjustPowerState(%ld)\n", fBridgeDevice->getName(), state);
3252	if (state < kIOPCIDeviceOnState)
3253	{
3254		fBridgeDevice->powerOverrideOnPriv();
3255	}
3256	else
3257	{
3258		state = kIOPCIDeviceOnState;
3259		fBridgeDevice->powerOverrideOffPriv();
3260	}
3261
3262	fBridgeDevice->changePowerStateToPriv(state);
3263}
3264
3265IOReturn IOPCI2PCIBridge::saveDeviceState(IOPCIDevice * device,
3266                                          IOOptionBits options)
3267{
3268	// bridge flags
3269    if (device->getProperty(kIOPMPCISleepLinkDisableKey))
3270		configShadow(fBridgeDevice)->flags |= kIOPCIConfigShadowSleepLinkDisable;
3271	else
3272		configShadow(fBridgeDevice)->flags &= ~kIOPCIConfigShadowSleepLinkDisable;
3273    if (device->getProperty(kIOPMPCISleepResetKey))
3274		configShadow(fBridgeDevice)->flags |= kIOPCIConfigShadowSleepReset;
3275	else
3276		configShadow(fBridgeDevice)->flags &= ~kIOPCIConfigShadowSleepReset;
3277    if (device->getProperty(gIOPCITunnelledKey) || device->getProperty(kIOPCIEjectableKey))
3278		configShadow(fBridgeDevice)->flags |= kIOPCIConfigShadowHotplug;
3279	else
3280		configShadow(fBridgeDevice)->flags &= ~kIOPCIConfigShadowHotplug;
3281
3282	// device flags
3283    if (device->getProperty(kIOPMPCIWakeL1PMDisableKey))
3284		configShadow(device)->flags |= kIOPCIConfigShadowWakeL1PMDisable;
3285	else
3286		configShadow(device)->flags &= ~kIOPCIConfigShadowWakeL1PMDisable;
3287
3288
3289	return super::saveDeviceState(device, options);
3290}
3291
3292void IOPCI2PCIBridge::stop( IOService * provider )
3293{
3294    super::stop( provider);
3295
3296	IOWorkLoop * tempWL;
3297	if (fBridgeInterruptSource)
3298	{
3299		fBridgeInterruptSource->disable();
3300		if ((tempWL = fBridgeInterruptSource->getWorkLoop()))
3301		   tempWL->removeEventSource(fBridgeInterruptSource);
3302		fBridgeInterruptSource->release();
3303		fBridgeInterruptSource = 0;
3304	}
3305	if (fTimerProbeES)
3306	{
3307		fTimerProbeES->cancelTimeout();
3308		if ((tempWL = fTimerProbeES->getWorkLoop()))
3309			tempWL->removeEventSource(fTimerProbeES);
3310		fTimerProbeES->release();
3311		fTimerProbeES = 0;
3312	}
3313	if (kIOPMUndefinedDriverAssertionID != fPMAssertion)
3314	{
3315		getPMRootDomain()->releasePMAssertion(fPMAssertion);
3316		fPMAssertion = kIOPMUndefinedDriverAssertionID;
3317	}
3318	if (fISRLock)
3319	{
3320		IOSimpleLockFree(fISRLock);
3321		fISRLock = 0;
3322	}
3323	if (fAERRoot)
3324	{
3325		if (fAERRoot->fISRErrors) IODelete(fAERRoot->fISRErrors, IOPCIAERISREntry, kAERISRNum);
3326		IODelete(fAERRoot, IOPCIAERRoot, 1);
3327	}
3328}
3329
3330void IOPCI2PCIBridge::free()
3331{
3332    super::free();
3333}
3334
3335void IOPCI2PCIBridge::saveBridgeState( void )
3336{
3337}
3338
3339void IOPCI2PCIBridge::restoreBridgeState( void )
3340{
3341}
3342
3343UInt8 IOPCI2PCIBridge::firstBusNum( void )
3344{
3345    return fBridgeDevice->configRead8( kPCI2PCISecondaryBus );
3346}
3347
3348UInt8 IOPCI2PCIBridge::lastBusNum( void )
3349{
3350    return fBridgeDevice->configRead8( kPCI2PCISubordinateBus );
3351}
3352
3353IOPCIAddressSpace IOPCI2PCIBridge::getBridgeSpace( void )
3354{
3355    return (fBridgeDevice->space);
3356}
3357
3358UInt32 IOPCI2PCIBridge::configRead32( IOPCIAddressSpace space,
3359                                      UInt8 offset )
3360{
3361    return (fBridgeDevice->configRead32(space, offset));
3362}
3363
3364void IOPCI2PCIBridge::configWrite32( IOPCIAddressSpace space,
3365                                     UInt8 offset, UInt32 data )
3366{
3367    fBridgeDevice->configWrite32( space, offset, data );
3368}
3369
3370UInt16 IOPCI2PCIBridge::configRead16( IOPCIAddressSpace space,
3371                                      UInt8 offset )
3372{
3373    return (fBridgeDevice->configRead16(space, offset));
3374}
3375
3376void IOPCI2PCIBridge::configWrite16( IOPCIAddressSpace space,
3377                                     UInt8 offset, UInt16 data )
3378{
3379    fBridgeDevice->configWrite16( space, offset, data );
3380}
3381
3382UInt8 IOPCI2PCIBridge::configRead8( IOPCIAddressSpace space,
3383                                    UInt8 offset )
3384{
3385    return (fBridgeDevice->configRead8(space, offset));
3386}
3387
3388void IOPCI2PCIBridge::configWrite8( IOPCIAddressSpace space,
3389                                    UInt8 offset, UInt8 data )
3390{
3391    fBridgeDevice->configWrite8( space, offset, data );
3392}
3393
3394IODeviceMemory * IOPCI2PCIBridge::ioDeviceMemory( void )
3395{
3396    return (fBridgeDevice->ioDeviceMemory());
3397}
3398
3399bool IOPCI2PCIBridge::publishNub( IOPCIDevice * nub, UInt32 index )
3400{
3401    if (nub)
3402        nub->setProperty( "IOChildIndex" , index, 32 );
3403
3404    return (super::publishNub(nub, index));
3405}
3406
3407
3408IOReturn IOPCIBridge::resolveMSIInterrupts( IOService * provider, IOPCIDevice * nub )
3409{
3410    IOReturn ret = kIOReturnUnsupported;
3411
3412	if (!(kIOPCIConfiguratorTBMSIEnable & gIOPCIFlags)
3413  		&& nub->getProperty(gIOPCITunnelledKey))
3414  	{
3415		return (ret);
3416	}
3417
3418    if (reserved && !reserved->messagedInterruptController)
3419    {
3420        callPlatformFunction(gIOPlatformGetMessagedInterruptControllerKey, false,
3421                             (void *)provider,
3422                             (void *)&reserved->messagedInterruptController,
3423                             (void *)0, (void *)0);
3424    }
3425
3426#if USE_MSI
3427
3428    IOByteCount msiCapability = nub->reserved->msiCapability;
3429    if (msiCapability && reserved && reserved->messagedInterruptController)
3430    {
3431        ret = reserved->messagedInterruptController->allocateDeviceInterrupts(
3432       	        nub, 0, msiCapability);
3433    }
3434
3435#endif /* USE_MSI */
3436
3437    return (ret);
3438}
3439
3440IOReturn IOPCIBridge::resolveLegacyInterrupts( IOService * provider, IOPCIDevice * nub )
3441{
3442#if USE_LEGACYINTS
3443
3444    uint32_t pin;
3445    uint32_t irq = 0;
3446
3447    pin = nub->configRead8( kIOPCIConfigInterruptPin );
3448    if ( pin == 0 || pin > 4 )
3449        return (kIOReturnUnsupported);  // assume no interrupt usage
3450
3451    pin--;  // make pin zero based, INTA=0, INTB=1, INTC=2, INTD=3
3452
3453    // Ask the platform driver to resolve the PCI interrupt route,
3454    // and return its corresponding system interrupt vector.
3455
3456    if ( kIOReturnSuccess == provider->callPlatformFunction(gIOPlatformResolvePCIInterruptKey,
3457                   /* waitForFunction */ false,
3458                   /* provider nub    */ provider,
3459                   /* device number   */ (void *)(uintptr_t) nub->space.s.deviceNum,
3460                   /* interrupt pin   */ (void *)(uintptr_t) pin,
3461                   /* resolved IRQ    */ &irq ))
3462    {
3463        DLOG("%s: Resolved interrupt %d (%d) for %s\n",
3464                  provider->getName(),
3465                  irq, pin,
3466                  nub->getName());
3467
3468        nub->configWrite8( kIOPCIConfigInterruptLine, irq & 0xff );
3469    }
3470    else
3471    {
3472        irq = nub->configRead8( kIOPCIConfigInterruptLine );
3473        if ( 0 == irq || 0xff == irq ) return (kIOReturnUnsupported);
3474        irq &= 0xf;  // what about IO-APIC and irq > 15?
3475    }
3476
3477    provider->callPlatformFunction(gIOPlatformSetDeviceInterruptsKey,
3478              /* waitForFunction */ false,
3479              /* nub             */ nub,
3480              /* vectors         */ (void *) &irq,
3481              /* vectorCount     */ (void *) 1,
3482              /* exclusive       */ (void *) false );
3483
3484#endif /* USE_LEGACYINTS */
3485
3486    return (kIOReturnSuccess);
3487}
3488
3489/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3490
3491IOPCIEventSource * IOPCIBridge::createEventSource(
3492			OSObject * owner, IOPCIEventSource::Action action, uint32_t options)
3493{
3494	IOPCIEventSource * src;
3495	bool               ok = false;
3496
3497	src = OSTypeAlloc(IOPCIEventSource);
3498	if (!src) return (0);
3499	do
3500	{
3501		if (!src->init(owner, (IOEventSource::Action) action)) break;
3502		src->fEvents = IONew(IOPCIEvent, kIOPCIEventNum);
3503		if (!src->fEvents) break;
3504		src->fRoot   = 0;
3505		src->fDevice = 0;
3506		ok = true;
3507	}
3508	while (false);
3509
3510	if (!ok)
3511	{
3512		src->release();
3513		src = 0;
3514	}
3515	return (src);
3516}
3517
3518IOPCIEventSource * IOPCIBridge::createEventSource(IOPCIDevice * device,
3519			OSObject * owner, IOPCIEventSource::Action action, uint32_t options)
3520{
3521	return (0);
3522}
3523
3524IOPCIEventSource * IOPCI2PCIBridge::createEventSource(IOPCIDevice * device,
3525			OSObject * owner, IOPCIEventSource::Action action, uint32_t options)
3526{
3527	IOPCIEventSource * src;
3528
3529	if (!fIsAERRoot) return (fBridgeDevice->parent->createEventSource(device, owner, action, options));
3530
3531	src = IOPCIBridge::createEventSource(owner, action, options);
3532	if (src)
3533	{
3534		src->fRoot = this;
3535		src->fDevice = device;
3536		if (device) device->retain();
3537	}
3538
3539	return (src);
3540}
3541
3542/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3543
3544#undef super
3545#define super IOEventSource
3546
3547OSDefineMetaClassAndStructors(IOPCIEventSource, IOEventSource)
3548
3549void IOPCIEventSource::free(void)
3550{
3551    IOPCIEvent       event;
3552    uint32_t         nextIdx;
3553
3554	if (fEvents)
3555	{
3556		IOSimpleLockLock(gIOPCIEventSourceLock);
3557		while (fReadIndex != fWriteIndex)
3558		{
3559			event = fEvents[fReadIndex];
3560			nextIdx = fReadIndex + 1;
3561			if (nextIdx == kIOPCIEventNum) nextIdx = 0;
3562			fReadIndex = nextIdx;
3563			if (event.reporter)
3564			{
3565				IOSimpleLockUnlock(gIOPCIEventSourceLock);
3566				event.reporter->release();
3567				IOSimpleLockLock(gIOPCIEventSourceLock);
3568			}
3569		}
3570		IOSimpleLockUnlock(gIOPCIEventSourceLock);
3571		IODelete(fEvents, IOPCIEvent, kIOPCIEventNum);
3572	}
3573
3574	if (fDevice) fDevice->release();
3575    super::free();
3576}
3577
3578void IOPCIEventSource::enable()
3579{
3580	super::enable();
3581	IOSimpleLockLock(gIOPCIEventSourceLock);
3582	if (!fQ.next) queue_enter(&gIOPCIEventSourceQueue, this, IOPCIEventSource *, fQ);
3583	IOSimpleLockUnlock(gIOPCIEventSourceLock);
3584}
3585
3586void IOPCIEventSource::disable()
3587{
3588	super::disable();
3589	IOSimpleLockLock(gIOPCIEventSourceLock);
3590	if (fQ.next)
3591	{
3592		queue_remove(&gIOPCIEventSourceQueue, this, IOPCIEventSource *, fQ);
3593		fQ.next = 0;
3594	}
3595	IOSimpleLockUnlock(gIOPCIEventSourceLock);
3596}
3597
3598bool IOPCIEventSource::checkForWork(void)
3599{
3600    IOPCIEventAction pciAction = (IOPCIEventAction) action;
3601    IOPCIEvent       event;
3602    uint32_t         nextIdx;
3603
3604	IOSimpleLockLock(gIOPCIEventSourceLock);
3605    while (enabled && (fReadIndex != fWriteIndex))
3606	{
3607		event = fEvents[fReadIndex];
3608		nextIdx = fReadIndex + 1;
3609		if (nextIdx == kIOPCIEventNum) nextIdx = 0;
3610		fReadIndex = nextIdx;
3611		IOSimpleLockUnlock(gIOPCIEventSourceLock);
3612		(*pciAction)(owner, this, &event);
3613		if (event.reporter) event.reporter->release();
3614		IOSimpleLockLock(gIOPCIEventSourceLock);
3615	}
3616	IOSimpleLockUnlock(gIOPCIEventSourceLock);
3617
3618    return (false);
3619}
3620
3621/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3622
3623#undef super
3624#define super IOService
3625
3626static void
3627PCIEventTest(OSObject * owner, IOPCIEventSource * es, const IOPCIEvent * event )
3628{
3629	kprintf("PCIEventTest %s, 0x%08qx : 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x 0x%08x\n",
3630						event->reporter->getName(), event->reporter->getRegistryEntryID(),
3631						event->event, event->data[0],
3632						event->data[1], event->data[2], event->data[3], event->data[4]);
3633}
3634
3635IOReturn
3636IOPCIBridge::setProperties(OSObject * properties)
3637{
3638    IOReturn       ret = kIOReturnUnsupported;
3639    OSDictionary * dict;
3640    OSDictionary * matching;
3641    OSArray *      array;
3642    OSString *     str;
3643	IOService *    victimS = 0;
3644    IOPCIDevice *  victim = 0;
3645    const char *   cmdstr;
3646    uint64_t       arg = 0;
3647
3648    dict = OSDynamicCast(OSDictionary, properties);
3649    if (dict
3650     && (array = OSDynamicCast(OSArray, dict->getObject(kIODebugArgumentsKey)))
3651	 && (str = OSDynamicCast(OSString, array->getObject(0))))
3652    {
3653	   	ret = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
3654		if (kIOReturnSuccess != ret) return (ret);
3655
3656	    cmdstr = str->getCStringNoCopy();
3657		kprintf("pcicmd: %s\n", cmdstr);
3658
3659		str = OSDynamicCast(OSString, array->getObject(1));
3660
3661		if (!strncmp("find", cmdstr, strlen("find")))
3662		{
3663			IOPCIAddressSpace space;
3664			IOService *       result;
3665
3666			space.s.busNum = strtoq(str ? str->getCStringNoCopy() : 0, NULL, 0);
3667			str = OSDynamicCast(OSString, array->getObject(2));
3668			space.s.deviceNum = strtoq(str ? str->getCStringNoCopy() : 0, NULL, 0);;
3669			str = OSDynamicCast(OSString, array->getObject(3));
3670			space.s.functionNum = strtoq(str ? str->getCStringNoCopy() : 0, NULL, 0);;
3671			IOReturn ret = configOp(NULL, kConfigOpFindEntry, &result, &space);
3672			kprintf("%d %d %d: find %x %p %s 0x%qx\n",
3673					space.s.busNum, space.s.deviceNum, space.s.functionNum, ret, result,
3674					result ? result->getName() : "",
3675					result ? result->getRegistryEntryID() : 0);
3676
3677		}
3678		else if (!strcmp("esg", cmdstr))
3679		{
3680			IOPCIEventSource * src = createEventSource(this, &PCIEventTest, 0);
3681			getWorkLoop()->addEventSource(src);
3682			src->enable();
3683			IOSleep(10*1000);
3684			getWorkLoop()->removeEventSource(src);
3685			src->release();
3686		}
3687		else if (str)
3688		{
3689			arg = strtoq(str->getCStringNoCopy(), NULL, 0);
3690			if (arg) matching = registryEntryIDMatching(arg);
3691			else     matching = nameMatching(str->getCStringNoCopy());
3692			victimS = copyMatchingService(matching);
3693		    matching->release();
3694			victim = OSDynamicCast(IOPCIDevice, victimS);
3695		}
3696		if (victim)
3697		{
3698			if (!strncmp("pause", cmdstr, strlen("pause")))
3699			{
3700				victim->reserved->pauseFlags = true;
3701				if ('d' == cmdstr[strlen("pause")]) victim->reserved->pauseFlags++;
3702				configOp(victim, kConfigOpTestPause, NULL);
3703				ret = kIOReturnSuccess;
3704			}
3705			else if (!strcmp("unpause", cmdstr))
3706			{
3707				victim->changePowerStateToPriv(kIOPCIDeviceOnState);
3708				victim->powerOverrideOffPriv();
3709				ret = kIOReturnSuccess;
3710			}
3711			else if (!strcmp("reset", cmdstr))
3712			{
3713				uint16_t control;
3714				control = victim->configRead16(kPCI2PCIBridgeControl);
3715				control |= (1 << 6);
3716				victim->configWrite16(kPCI2PCIBridgeControl, control);
3717				IOSleep(10);
3718				control &= ~(1 << 6);
3719				victim->configWrite16(kPCI2PCIBridgeControl, control);
3720				ret = kIOReturnSuccess;
3721			}
3722			else if (!strncmp("gen", cmdstr, strlen("gen")))
3723			{
3724				uint16_t control;
3725				control = (('1' == cmdstr[strlen("gen")]) ? 1 : 2);
3726				control |= 0x30;
3727	            victim->configWrite16(victim->reserved->expressCapability + 0x30, control);
3728			    control = victim->configRead16(victim->reserved->expressCapability + 0x10);
3729				control |= (1 << 5);
3730				victim->configWrite16(victim->reserved->expressCapability + 0x10, control);
3731				IOSleep(100);
3732				kprintf("link speed %d\n", (15 & victim->configRead16(victim->reserved->expressCapability + 0x12)));
3733				ret = kIOReturnSuccess;
3734			}
3735			else if (!strcmp("ltr", cmdstr))
3736			{
3737				IOOptionBits type = 0;
3738				uint64_t nsecs = 0;
3739				str = OSDynamicCast(OSString, array->getObject(2));
3740				if (str) type = strtoq(str->getCStringNoCopy(), NULL, 0);
3741				str = OSDynamicCast(OSString, array->getObject(3));
3742				if (str) nsecs = strtoq(str->getCStringNoCopy(), NULL, 0);
3743				ret = victim->setLatencyTolerance(type, nsecs);
3744				kprintf("setLatencyTolerance 0x%x\n", ret);
3745				ret = kIOReturnSuccess;
3746			}
3747			else if (!strcmp("cycle", cmdstr))
3748			{
3749				uint32_t      idx, did;
3750				IOPCIBridge * bridge;
3751				IOPCIBridge * pbridge;
3752				IOPCIDevice * parent;
3753				bridge = OSDynamicCast(IOPCIBridge, victim->getProvider());
3754				parent = OSDynamicCast(IOPCIDevice, bridge->getProvider());
3755				pbridge = OSDynamicCast(IOPCIBridge, parent->getProvider());
3756
3757				for (idx = 0; idx < 100; idx++)
3758				{
3759					bridge->setDevicePowerState(victim,  0, kIOPCIDeviceOnState,  kIOPCIDeviceOffState);
3760					pbridge->setDevicePowerState(parent, 0, kIOPCIDeviceOnState,  kIOPCIDeviceOffState);
3761					pbridge->setDevicePowerState(parent, 0, kIOPCIDeviceOffState, kIOPCIDeviceOnState);
3762					bridge->setDevicePowerState(victim,  0, kIOPCIDeviceOffState, kIOPCIDeviceOnState);
3763					did = victim->configRead32(0);
3764					if (0xffffffff == did) panic("did");
3765				}
3766				ret = kIOReturnSuccess;
3767			}
3768			else if (!strcmp("es", cmdstr))
3769			{
3770				IOPCIEventSource * src = victim->createEventSource(this, &PCIEventTest, 0);
3771				victim->getWorkLoop()->addEventSource(src);
3772				src->enable();
3773				IOSleep(10*1000);
3774				victim->getWorkLoop()->removeEventSource(src);
3775				src->release();
3776			}
3777			else if (!strcmp("l1ena", cmdstr))
3778			{
3779				ret = victim->setTunnelL1Enable(victim, true);
3780			}
3781			else if (!strcmp("l1dis", cmdstr))
3782			{
3783				ret = victim->setTunnelL1Enable(victim, false);
3784			}
3785		}
3786		if (victimS) victimS->release();
3787    }
3788	else ret = super::setProperties(properties);
3789
3790	return (ret);
3791}
3792/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3793
3794IOReturn
3795IOPCIBridge::newUserClient(task_t owningTask, void * securityID,
3796                           UInt32 type,  OSDictionary * properties,
3797                           IOUserClient ** handler)
3798{
3799    IOPCIDiagnosticsClient * uc;
3800    bool                     ok;
3801    int                      bootArg;
3802
3803    if (type != kIOPCIDiagnosticsClientType)
3804        return (super::newUserClient(owningTask, securityID, type, properties, handler));
3805
3806	ok = false;
3807	uc = NULL;
3808    do
3809    {
3810		if (kIOReturnSuccess != IOUserClient::clientHasPrivilege(
3811			securityID, kIOClientPrivilegeAdministrator)) 						 break;
3812		if (!PE_parse_boot_argn("debug", &bootArg, sizeof(bootArg)) || !bootArg) break;
3813
3814		uc = OSTypeAlloc(IOPCIDiagnosticsClient);
3815        if (!uc) break;
3816        ok = uc->initWithTask(owningTask, securityID, type, properties);
3817		uc->owner = this;
3818        if (!ok) break;
3819        ok = uc->attach(this);
3820        if (!ok) break;
3821        ok = uc->start(this);
3822    }
3823    while (false);
3824
3825    if (ok)
3826    {
3827        *handler = uc;
3828        return (kIOReturnSuccess);
3829    }
3830    else
3831    {
3832        if (uc && uc->inPlane(gIOServicePlane))
3833            uc->detach(this);
3834        if (uc) uc->release();
3835        *handler = NULL;
3836        return (kIOReturnUnsupported);
3837    }
3838}
3839
3840/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3841
3842#undef super
3843#define super IOUserClient
3844
3845OSDefineMetaClassAndStructors(IOPCIDiagnosticsClient, IOUserClient)
3846
3847/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3848
3849IOReturn IOPCIDiagnosticsClient::clientClose(void)
3850{
3851	terminate();
3852    return (kIOReturnSuccess);
3853}
3854
3855IOService * IOPCIDiagnosticsClient::getService(void)
3856{
3857    return (owner);
3858}
3859
3860IOReturn IOPCIDiagnosticsClient::setProperties(OSObject * properties)
3861{
3862    IOReturn            kr = kIOReturnUnsupported;
3863    return (kr);
3864}
3865
3866IOReturn IOPCIDiagnosticsClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
3867												IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
3868{
3869    IOReturn                     ret = kIOReturnBadArgument;
3870    IOPCIDiagnosticsParameters * params;
3871	IOMemoryDescriptor         * md;
3872	IOMemoryMap                * map;
3873	void                       * vmaddr;
3874
3875    switch (selector)
3876    {
3877        case kIOPCIDiagnosticsMethodWrite:
3878            if (args->structureInputSize != sizeof(IOPCIDiagnosticsParameters)) return (kIOReturnBadArgument);
3879
3880			params = (typeof(params)) args->structureInput;
3881            break;
3882
3883        case kIOPCIDiagnosticsMethodRead:
3884            if (args->structureInputSize  != sizeof(IOPCIDiagnosticsParameters)) return (kIOReturnBadArgument);
3885            if (args->structureOutputSize != sizeof(IOPCIDiagnosticsParameters)) return (kIOReturnBadArgument);
3886
3887			bcopy(args->structureInput, args->structureOutput, sizeof(IOPCIDiagnosticsParameters));
3888			params = (typeof(params)) args->structureOutput;
3889            break;
3890
3891        default:
3892        	return (kIOReturnBadArgument);
3893            break;
3894	}
3895
3896	map = 0;
3897	vmaddr = 0;
3898	if (kIOPCI64BitMemorySpace == params->spaceType)
3899	{
3900		md = IOMemoryDescriptor::withAddressRange(params->address.addr64,
3901				(params->bitWidth >> 3), kIODirectionOutIn | kIOMemoryMapperNone, NULL);
3902		if (md)
3903		{
3904			map = md->map();
3905			md->release();
3906		}
3907		if (!map) return (kIOReturnVMError);
3908		vmaddr = (void *)(uintptr_t) map->getAddress();
3909	}
3910
3911    switch (selector)
3912    {
3913        case kIOPCIDiagnosticsMethodWrite:
3914
3915			if (kIOPCI64BitMemorySpace == params->spaceType)
3916			{
3917				switch (params->bitWidth)
3918				{
3919					case 8:
3920						*((uint8_t *) vmaddr) = params->value;
3921						ret = kIOReturnSuccess;
3922						break;
3923					case 16:
3924						*((uint16_t *) vmaddr) = params->value;
3925						ret = kIOReturnSuccess;
3926						break;
3927					case 32:
3928						*((uint32_t *) vmaddr) = params->value;
3929						ret = kIOReturnSuccess;
3930						break;
3931					case 64:
3932						*((uint64_t *) vmaddr) = params->value;
3933						ret = kIOReturnSuccess;
3934						break;
3935					default:
3936						break;
3937				}
3938			}
3939			else if (kIOPCIConfigSpace == params->spaceType)
3940			{
3941				IOPCIAddressSpace space;
3942				space.bits                   = 0;
3943				space.es.busNum              = params->address.pci.bus;
3944				space.es.deviceNum           = params->address.pci.device;
3945				space.es.functionNum         = params->address.pci.function;
3946				space.es.registerNumExtended = (0xF & (params->address.pci.offset >> 8));
3947				switch (params->bitWidth)
3948				{
3949					case 8:
3950						owner->configWrite8(space, params->address.pci.offset, params->value);
3951						ret = kIOReturnSuccess;
3952						break;
3953					case 16:
3954						owner->configWrite16(space, params->address.pci.offset, params->value);
3955						ret = kIOReturnSuccess;
3956						break;
3957					case 32:
3958						owner->configWrite32(space, params->address.pci.offset, params->value);
3959						ret = kIOReturnSuccess;
3960						break;
3961					default:
3962						break;
3963				}
3964			}
3965			break;
3966
3967        case kIOPCIDiagnosticsMethodRead:
3968
3969			if (kIOPCI64BitMemorySpace == params->spaceType)
3970			{
3971				switch (params->bitWidth)
3972				{
3973					case 8:
3974						params->value = *((uint8_t *) vmaddr);
3975						ret = kIOReturnSuccess;
3976						break;
3977					case 16:
3978						params->value = *((uint16_t *) vmaddr);
3979						ret = kIOReturnSuccess;
3980						break;
3981					case 32:
3982						params->value = *((uint32_t *) vmaddr);
3983						ret = kIOReturnSuccess;
3984						break;
3985					case 64:
3986						params->value = *((uint64_t *) vmaddr);
3987						ret = kIOReturnSuccess;
3988						break;
3989					default:
3990						break;
3991				}
3992			}
3993			else if (kIOPCIConfigSpace == params->spaceType)
3994			{
3995				IOPCIAddressSpace space;
3996				space.bits                   = 0;
3997				space.es.busNum              = params->address.pci.bus;
3998				space.es.deviceNum           = params->address.pci.device;
3999				space.es.functionNum         = params->address.pci.function;
4000				space.es.registerNumExtended = (0xF & (params->address.pci.offset >> 8));
4001				switch (params->bitWidth)
4002				{
4003					case 8:
4004						params->value = owner->configRead8(space, params->address.pci.offset);
4005						ret = kIOReturnSuccess;
4006						break;
4007					case 16:
4008						params->value = owner->configRead16(space, params->address.pci.offset);
4009						ret = kIOReturnSuccess;
4010						break;
4011					case 32:
4012						params->value = owner->configRead32(space, params->address.pci.offset);
4013						ret = kIOReturnSuccess;
4014						break;
4015					default:
4016						break;
4017				}
4018			}
4019			break;
4020
4021        default:
4022            break;
4023    }
4024
4025    if (map) map->release();
4026
4027    return (ret);
4028}
4029
4030/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4031
4032