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#define __IOPCIDEVICE_INTERNAL__	1
24
25#include <IOKit/system.h>
26
27#include <IOKit/pci/IOPCIBridge.h>
28#include <IOKit/pci/IOPCIPrivate.h>
29#include <IOKit/pci/IOAGPDevice.h>
30#include <IOKit/pci/IOPCIConfigurator.h>
31#include <IOKit/pci/IOPCIPrivate.h>
32#include <IOKit/IOPlatformExpert.h>
33#include <IOKit/IODeviceTreeSupport.h>
34#include <IOKit/IOUserClient.h>
35
36#include <IOKit/IOLib.h>
37#include <IOKit/assert.h>
38
39#include <libkern/c++/OSContainers.h>
40#include <libkern/version.h>
41
42#if ACPI_SUPPORT
43#include <IOKit/acpi/IOACPIPlatformDevice.h>
44#endif
45
46#ifndef VERSION_MAJOR
47#error VERSION_MAJOR
48#endif
49
50enum
51{
52    // reserved->pmSleepEnabled
53    kPMEnable  = 0x01,
54    kPMEOption = 0x02
55};
56
57#define DLOG(fmt, args...)                   \
58    do {                                                    \
59        if ((gIOPCIFlags & kIOPCIConfiguratorIOLog) && !ml_at_interrupt_context())   \
60            IOLog(fmt, ## args);                            \
61        if (gIOPCIFlags & kIOPCIConfiguratorKPrintf)        \
62            kprintf(fmt, ## args);                          \
63    } while(0)
64
65
66/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
67
68#define super IOService
69
70OSDefineMetaClassAndStructors(IOPCIDevice, IOService)
71OSMetaClassDefineReservedUnused(IOPCIDevice,  3);
72OSMetaClassDefineReservedUnused(IOPCIDevice,  4);
73OSMetaClassDefineReservedUnused(IOPCIDevice,  5);
74OSMetaClassDefineReservedUnused(IOPCIDevice,  6);
75OSMetaClassDefineReservedUnused(IOPCIDevice,  7);
76OSMetaClassDefineReservedUnused(IOPCIDevice,  8);
77OSMetaClassDefineReservedUnused(IOPCIDevice,  9);
78OSMetaClassDefineReservedUnused(IOPCIDevice, 10);
79OSMetaClassDefineReservedUnused(IOPCIDevice, 11);
80OSMetaClassDefineReservedUnused(IOPCIDevice, 12);
81OSMetaClassDefineReservedUnused(IOPCIDevice, 13);
82OSMetaClassDefineReservedUnused(IOPCIDevice, 14);
83OSMetaClassDefineReservedUnused(IOPCIDevice, 15);
84
85/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
86
87//*********************************************************************************
88// [public] maxCapabilityForDomainState
89//
90// Finds the highest power state in the array whose input power
91// requirement is equal to the input parameter.  Where a more intelligent
92// decision is possible, override this in the subclassed driver.
93//*********************************************************************************
94
95unsigned long
96IOPCIDevice::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
97{
98	if (domainState & kIOPMPowerOn)        return (kIOPCIDeviceOnState);
99	if (domainState & kIOPMSoftSleep)      return (kIOPCIDeviceDozeState);
100	if (domainState & kIOPMConfigRetained) return (kIOPCIDevicePausedState);
101    return (kIOPCIDeviceOffState);
102}
103
104//*********************************************************************************
105// [public] initialPowerStateForDomainState
106//
107// Finds the highest power state in the array whose input power
108// requirement is equal to the input parameter.  Where a more intelligent
109// decision is possible, override this in the subclassed driver.
110//*********************************************************************************
111
112unsigned long
113IOPCIDevice::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
114{
115	if (domainState & kIOPMPowerOn)        return (kIOPCIDeviceOnState);
116	if (domainState & kIOPMSoftSleep)      return (kIOPCIDeviceDozeState);
117	if (domainState & kIOPMConfigRetained) return (kIOPCIDevicePausedState);
118    return (kIOPCIDeviceOffState);
119}
120
121//*********************************************************************************
122// [public] powerStateForDomainState
123//
124// Finds the highest power state in the array whose input power
125// requirement is equal to the input parameter.  Where a more intelligent
126// decision is possible, override this in the subclassed driver.
127//*********************************************************************************
128
129unsigned long
130IOPCIDevice::powerStateForDomainState ( IOPMPowerFlags domainState )
131{
132	if (domainState & kIOPMPowerOn)        return (kIOPCIDeviceOnState);
133	if (domainState & kIOPMSoftSleep)      return (kIOPCIDeviceDozeState);
134	if (domainState & kIOPMConfigRetained) return (kIOPCIDevicePausedState);
135    return (kIOPCIDeviceOffState);
136}
137
138/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
139// attach
140//
141/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
142
143bool IOPCIDevice::attach( IOService * provider )
144{
145    if (!super::attach(provider)) return (false);
146
147#if ACPI_SUPPORT
148	IOACPIPlatformDevice * device;
149	uint32_t               idx;
150	bool                   hasPS;
151
152	device = 0;
153	if (reserved->configEntry
154	 && (device = (IOACPIPlatformDevice *) reserved->configEntry->acpiDevice)
155	 && !device->metaCast("IOACPIPlatformDevice")) device = 0;
156
157	for (idx = kIOPCIDeviceOffState, hasPS = false; idx <= kIOPCIDeviceOnState; idx++)
158	{
159		reserved->psMethods[idx] = -1;
160		if (!device) continue;
161		if (kIOReturnSuccess == device->validateObject(gIOPCIPSMethods[idx]))
162		{
163			reserved->psMethods[idx] = idx;
164			hasPS = true;
165		}
166		else if (kIOPCIDeviceDozeState == idx)
167		{
168			reserved->psMethods[idx] = reserved->psMethods[kIOPCIDeviceOffState];
169		}
170	}
171	reserved->psMethods[kIOPCIDevicePausedState] = reserved->psMethods[kIOPCIDeviceOnState];
172	if (hasPS) DLOG("%s: _PSx %d, %d, %d, %d\n", getName(),
173				  reserved->psMethods[0], reserved->psMethods[1],
174				  reserved->psMethods[2], reserved->psMethods[3]);
175	reserved->lastPSMethod = reserved->psMethods[kIOPCIDeviceOnState];
176#endif
177	reserved->pciPMState = kIOPCIDeviceOnState;
178
179	if (reserved->powerCapability)
180	{
181		uint16_t pmcsr;
182		reserved->pmControlStatus = reserved->powerCapability + 4;
183		pmcsr = extendedConfigRead16(reserved->pmControlStatus);
184		if (pmcsr & kPCIPMCSPMEStatus)
185		{
186			// R/WC PME_Status
187			extendedConfigWrite16(reserved->pmControlStatus, pmcsr);
188		}
189	}
190
191    // initialize superclass variables
192    PMinit();
193    // clamp power on
194    temporaryPowerClampOn();
195    // register as controlling driver
196    IOPCIRegisterPowerDriver(this, false);
197
198    // join the tree
199	reserved->pmState  = kIOPCIDeviceOnState;
200	reserved->pmActive = true;
201    provider->joinPMtree( this);
202
203#if 0
204    // clamp power on if this is a slot device
205    slotNameProperty = provider->getProperty ("AAPL,slot-name");
206    if (slotNameProperty != NULL)
207        changePowerStateToPriv (1);
208#endif
209	return (true);
210}
211
212void IOPCIDevice::detach( IOService * provider )
213{
214	IOPCIConfigShadow * shadow;
215
216	if ((shadow = configShadow(this)) && shadow->tunnelRoot)
217	{
218		setTunnelL1Enable(this, true);
219	}
220
221    if (parent) parent->removeDevice(this);
222
223    PMstop();
224
225	IOLockLock(reserved->lock);
226	while (reserved->pmActive)
227	{
228		reserved->pmWait = true;
229		IOLockSleep(reserved->lock, &reserved->pmActive, THREAD_UNINT);
230	}
231	IOLockUnlock(reserved->lock);
232
233    super::detach(provider);
234
235    detachAbove(gIODTPlane);
236}
237
238void
239IOPCIDevice::detachAbove( const IORegistryPlane * plane )
240{
241	super::detachAbove(plane);
242
243    if (plane == gIOPowerPlane)
244	{
245		IOLockLock(reserved->lock);
246		reserved->pmActive = false;
247		if (reserved->pmWait)
248			IOLockWakeup(reserved->lock, &reserved->pmActive, true);
249		IOLockUnlock(reserved->lock);
250	}
251}
252
253bool
254IOPCIDevice::initReserved(void)
255{
256    // allocate our expansion data
257    if (!reserved)
258    {
259        reserved = IONew(IOPCIDeviceExpansionData, 1);
260        if (!reserved)
261            return (false);
262        bzero(reserved, sizeof(IOPCIDeviceExpansionData));
263		reserved->lock = IOLockAlloc();
264    }
265    return (true);
266}
267
268bool
269IOPCIDevice::init(OSDictionary * propTable)
270{
271    if (!super::init(propTable))  return (false);
272    return (initReserved());
273}
274
275bool IOPCIDevice::init( IORegistryEntry * from, const IORegistryPlane * inPlane )
276{
277    if (!super::init(from, inPlane))  return (false);
278    return (initReserved());
279}
280
281void IOPCIDevice::free()
282{
283    if (savedConfig)
284    {
285        IODelete(savedConfig, IOPCIConfigShadow, 1);
286        savedConfig = 0;
287    }
288    //  This needs to be the LAST thing we do, as it disposes of our "fake" member
289    //  variables.
290    //
291    if (reserved)
292	{
293		if (reserved->lock)
294			IOLockFree(reserved->lock);
295        IODelete(reserved, IOPCIDeviceExpansionData, 1);
296	}
297
298    super::free();
299}
300
301/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
302
303IOReturn IOPCIDevice::powerStateWillChangeTo (IOPMPowerFlags  capabilities,
304                                              unsigned long   stateNumber,
305                                              IOService*      whatDevice)
306{
307    uint16_t pmcsr;
308
309    if (stateNumber == kIOPCIDeviceOffState)
310    {
311        if ((kPMEOption & reserved->pmSleepEnabled) && reserved->pmControlStatus && (reserved->sleepControlBits & kPCIPMCSPMEStatus))
312        {
313            // if we would normally reset the PME_Status bit when going to sleep, do it now
314            // at the beginning of the power change. that way any PME event generated from this point
315            // until we go to sleep should wake the machine back up.
316            pmcsr = extendedConfigRead16(reserved->pmControlStatus);
317            if (pmcsr & kPCIPMCSPMEStatus)
318            {
319                // the the PME_Status bit is set at this point, we clear it but leave all other bits
320                // untouched by writing the exact same value back to the register. This is because the
321                // PME_Status bit is R/WC.
322                DLOG("%s[%p]::powerStateWillChangeTo(OFF) - PMCS has PME set(0x%x) - CLEARING\n", getName(), this, pmcsr);
323                extendedConfigWrite16(reserved->pmControlStatus, pmcsr);
324                DLOG("%s[%p]::powerStateWillChangeTo(OFF) - PMCS now is(0x%x)\n", getName(), this, extendedConfigRead16(reserved->pmControlStatus));
325            }
326            else
327            {
328                DLOG("%s[%p]::powerStateWillChangeTo(OFF) - PMCS has PME clear(0x%x) - not touching\n", getName(), this, pmcsr);
329            }
330        }
331    }
332    else if ((stateNumber == kIOPCIDeviceOnState) && reserved->pmControlStatus)
333    {
334        pmcsr = (kIOPCIDeviceOnState == reserved->pciPMState)
335                ? reserved->pmLastWakeBits : extendedConfigRead16(reserved->pmControlStatus);
336        updateWakeReason(pmcsr);
337    }
338
339    return super::powerStateWillChangeTo(capabilities, stateNumber, whatDevice);
340}
341
342/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
343// PCI setPowerState
344//
345/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
346
347IOReturn IOPCIDevice::setPCIPowerState(uint8_t powerState, uint32_t options)
348{
349	uint16_t            pmeState;
350	uint8_t             prevState;
351
352    DLOG("%s[%p]::pciSetPowerState(%d->%d)\n", getName(), this, reserved->pciPMState, powerState);
353
354#if ACPI_SUPPORT
355	IOACPIPlatformDevice * device;
356	int8_t  idx;
357	IOReturn ret;
358	uint64_t time;
359	if ((idx = reserved->psMethods[powerState]) >= 0)
360	{
361		if ((idx != reserved->lastPSMethod) && !(kMachineRestoreDehibernate & options))
362		{
363			IOPCIConfigShadow * shadow = configShadow(this);
364			if ((powerState >= kIOPCIDeviceOnState)
365				&& !space.s.busNum
366				&& (shadow)
367				&& (shadow->bridge)
368				&& (kIOPCIConfigShadowValid
369					== ((kIOPCIConfigShadowValid | kIOPCIConfigShadowBridgeDriver) & shadow->flags))
370				&& (!(0x00FFFFFF & extendedConfigRead32(kPCI2PCIPrimaryBus))))
371			{
372				DLOG("%s::restore bus(0x%x)\n", getName(), shadow->savedConfig[kPCI2PCIPrimaryBus >> 2]);
373				extendedConfigWrite32(kPCI2PCIPrimaryBus, shadow->savedConfig[kPCI2PCIPrimaryBus >> 2]);
374			}
375			device = (IOACPIPlatformDevice *) reserved->configEntry->acpiDevice;
376			DLOG("%s::evaluateObject(%s)\n", getName(), gIOPCIPSMethods[idx]->getCStringNoCopy());
377			time = mach_absolute_time();
378			ret = device->evaluateObject(gIOPCIPSMethods[idx]);
379			time = mach_absolute_time() - time;
380			absolutetime_to_nanoseconds(time, &time);
381			DLOG("%s::evaluateObject(%s) ret 0x%x %qd ms\n",
382				getName(), gIOPCIPSMethods[idx]->getCStringNoCopy(), ret, time / 1000000ULL);
383
384			if ((powerState < kIOPCIDeviceOnState) && shadow) shadow->restoreCount = 0;
385		}
386		reserved->lastPSMethod = idx;
387	}
388
389//    void * p3 = (void *) 0;
390//    if (doMsg) device->callPlatformFunction(gIOPlatformDeviceMessageKey, false,
391//						  (void *) kIOMessageDeviceWillPowerOff, device, p3, (void *) 0);
392//    if (doMsg) device->callPlatformFunction(gIOPlatformDeviceMessageKey, false,
393//						  (void *) kIOMessageDeviceHasPoweredOn, device, p3, (void *) 0);
394
395#endif
396
397	if (kMachineRestoreDehibernate & options) return (kIOReturnSuccess);
398	prevState = reserved->pciPMState;
399	if (powerState != prevState)
400	{
401		reserved->pciPMState = powerState;
402		if (!isInactive()) switch (powerState)
403		{
404			case kIOPCIDeviceOffState:
405			case kIOPCIDeviceDozeState:
406
407				if (reserved->pmSleepEnabled && reserved->pmControlStatus && reserved->sleepControlBits)
408				{
409					UInt16 bits = reserved->sleepControlBits;
410					if (kPMEOption & reserved->pmSleepEnabled)
411					{
412						// we don't clear the PME_Status at this time. Instead, we cleared it in powerStateWillChangeTo
413						// so this write will change our power state to the desired state and will also set PME_En
414						bits &= ~kPCIPMCSPMEStatus;
415					}
416					DLOG("%s[%p]::setPCIPowerState(OFF) - writing 0x%x to PMCS currently (0x%x)\n", getName(), this, bits, extendedConfigRead16(reserved->pmControlStatus));
417					extendedConfigWrite16(reserved->pmControlStatus, bits);
418					DLOG("%s[%p]::setPCIPowerState(OFF) - after writing, PMCS is (0x%x)\n", getName(), this, extendedConfigRead16(reserved->pmControlStatus));
419				}
420				break;
421
422			case kIOPCIDevicePausedState:
423			case kIOPCIDeviceOnState:
424				pmeState = reserved->pmControlStatus ? extendedConfigRead16(reserved->pmControlStatus) : 0;
425				if (reserved->pmSleepEnabled && reserved->pmControlStatus && reserved->sleepControlBits)
426				{
427					if ((pmeState & kPCIPMCSPowerStateMask) != kPCIPMCSPowerStateD0)
428					{
429						DLOG("%s[%p]::setPCIPowerState(ON) - moving PMCS from 0x%x to D0\n",
430							getName(), this, extendedConfigRead16(reserved->pmControlStatus));
431							// the write below will clear PME_Status, clear PME_En, and set the Power State to D0
432						extendedConfigWrite16(reserved->pmControlStatus, kPCIPMCSPMEStatus | kPCIPMCSPowerStateD0);
433						IOSleep(10);
434						DLOG("%s[%p]::setPCIPowerState(ON) - did move PMCS to 0x%x\n",
435							getName(), this, extendedConfigRead16(reserved->pmControlStatus));
436					}
437					else
438					{
439						DLOG("%s[%p]::setPCIPowerState(ON) - PMCS already at D0 (0x%x)\n",
440							getName(), this, extendedConfigRead16(reserved->pmControlStatus));
441							// the write below will clear PME_Status, clear PME_En, and set the Power State to D0
442						extendedConfigWrite16(reserved->pmControlStatus, kPCIPMCSPMEStatus);
443					}
444					reserved->pmLastWakeBits = pmeState;
445					reserved->pmeUpdate      = (kIOPCIDeviceOffState == prevState);
446				}
447				break;
448		}
449	}
450
451	if ((kIOPCIDeviceOnState == powerState)
452	  && reserved->pmeUpdate
453	  && !(kMachineRestoreDehibernate & options))
454    {
455        reserved->pmeUpdate = false;
456        updateWakeReason(reserved->pmLastWakeBits);
457    }
458
459    return (kIOReturnSuccess);
460}
461
462/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
463
464void IOPCIDevice::updateWakeReason(uint16_t pmeState)
465{
466    enum { kDidWake = kPCIPMCSPMEStatus | kPCIPMCSPMEEnable };
467    OSNumber * num;
468
469    if (0xFFFF == pmeState) removeProperty(kIOPCIPMCSStateKey);
470    else
471    {
472        if (kDidWake == (kDidWake & pmeState))
473        {
474            parent->updateWakeReason(this);
475        }
476        num = OSNumber::withNumber(pmeState, 16);
477        if (num)
478        {
479            setProperty(kIOPCIPMCSStateKey, num);
480            num->release();
481        }
482    }
483}
484
485/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
486// PM setPowerState
487//
488/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
489
490IOReturn IOPCIDevice::setPowerState( unsigned long newState,
491                                     IOService * whatDevice )
492{
493	IOReturn ret;
494	unsigned long prevState;
495
496    if (isInactive())
497        return (kIOPMAckImplied);
498
499	prevState = reserved->pmState;
500    ret = parent->setDevicePowerState(this, kIOPCIConfigShadowVolatile,
501    								  prevState, newState);
502    reserved->pmState = newState;
503	return (ret);
504}
505
506IOReturn IOPCIDevice::saveDeviceState( IOOptionBits options )
507{
508	IOReturn ret;
509    ret = parent->setDevicePowerState(this, 0,
510                                      kIOPCIDeviceOnState, kIOPCIDeviceDozeState);
511	return (ret);
512}
513
514IOReturn IOPCIDevice::restoreDeviceState( IOOptionBits options )
515{
516	IOReturn ret;
517    ret = parent->setDevicePowerState(this, 0,
518    								  kIOPCIDeviceDozeState, kIOPCIDeviceOnState);
519	return (ret);
520}
521
522/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
523
524bool IOPCIDevice::matchPropertyTable( OSDictionary * table, SInt32 * score )
525{
526    return (parent->matchNubWithPropertyTable(this, table, score));
527}
528
529bool IOPCIDevice::compareName( OSString * name, OSString ** matched ) const
530{
531    return (parent->compareNubName(this, name, matched));
532}
533
534IOReturn IOPCIDevice::getResources( void )
535{
536    return (parent->getNubResources(this));
537}
538
539/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
540
541UInt32 IOPCIDevice::configRead32( IOPCIAddressSpace _space,
542                                  UInt8 offset )
543{
544    return (parent->configRead32(_space, offset));
545}
546
547void IOPCIDevice::configWrite32( IOPCIAddressSpace _space,
548                                 UInt8 offset, UInt32 data )
549{
550    parent->configWrite32( _space, offset, data );
551}
552
553UInt16 IOPCIDevice::configRead16( IOPCIAddressSpace _space,
554                                  UInt8 offset )
555{
556    return (parent->configRead16(_space, offset));
557}
558
559void IOPCIDevice::configWrite16( IOPCIAddressSpace _space,
560                                 UInt8 offset, UInt16 data )
561{
562    parent->configWrite16( _space, offset, data );
563}
564
565UInt8 IOPCIDevice::configRead8( IOPCIAddressSpace _space,
566                                UInt8 offset )
567{
568    return (parent->configRead8(_space, offset));
569}
570
571void IOPCIDevice::configWrite8( IOPCIAddressSpace _space,
572                                UInt8 offset, UInt8 data )
573{
574    parent->configWrite8( _space, offset, data );
575}
576
577/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
578
579bool IOPCIDevice::configAccess(bool write)
580{
581	bool ok = (!isInactive()
582			&& reserved
583			&& (0 == ((write ? VM_PROT_WRITE : VM_PROT_READ) & reserved->configProt)));
584	if (!ok)
585	{
586		OSReportWithBacktrace("config protect fail(2) for device %u:%u:%u\n",
587								PCI_ADDRESS_TUPLE(this));
588	}
589	return (ok);
590}
591
592#if APPLE_KEXT_VTABLE_PADDING
593
594UInt32 IOPCIDevice::configRead32( UInt8 offset )
595{
596	if (!configAccess(false)) return (0xFFFFFFFF);
597    return (parent->configRead32(space, offset));
598}
599
600void IOPCIDevice::configWrite32( UInt8 offset, UInt32 data )
601{
602	if (!configAccess(true)) return;
603    parent->configWrite32( space, offset, data );
604}
605
606UInt16 IOPCIDevice::configRead16( UInt8 offset )
607{
608	if (!configAccess(false)) return (0xFFFF);
609    return (parent->configRead16(space, offset));
610}
611
612void IOPCIDevice::configWrite16( UInt8 offset, UInt16 data )
613{
614	if (!configAccess(true)) return;
615    parent->configWrite16( space, offset, data );
616}
617
618UInt8 IOPCIDevice::configRead8( UInt8 offset )
619{
620	if (!configAccess(false)) return (0xFF);
621    return (parent->configRead8(space, offset));
622}
623
624void IOPCIDevice::configWrite8( UInt8 offset, UInt8 data )
625{
626	if (!configAccess(true)) return;
627    parent->configWrite8( space, offset, data );
628}
629
630#endif /* APPLE_KEXT_VTABLE_PADDING */
631
632// --
633
634UInt32 IOPCIDevice::extendedConfigRead32( IOByteCount offset )
635{
636	if (!configAccess(false)) return (0xFFFFFFFF);
637    IOPCIAddressSpace _space = space;
638    _space.es.registerNumExtended = (offset >> 8);
639    return (configRead32(_space, offset));
640}
641
642void IOPCIDevice::extendedConfigWrite32( IOByteCount offset, UInt32 data )
643{
644	if (!configAccess(true)) return;
645    IOPCIAddressSpace _space = space;
646    _space.es.registerNumExtended = (offset >> 8);
647    configWrite32(_space, offset, data);
648}
649
650UInt16 IOPCIDevice::extendedConfigRead16( IOByteCount offset )
651{
652	if (!configAccess(false)) return (0xFFFF);
653    IOPCIAddressSpace _space = space;
654    _space.es.registerNumExtended = (offset >> 8);
655    return (configRead16(_space, offset));
656}
657
658void IOPCIDevice::extendedConfigWrite16( IOByteCount offset, UInt16 data )
659{
660	if (!configAccess(true)) return;
661    IOPCIAddressSpace _space = space;
662    _space.es.registerNumExtended = (offset >> 8);
663    configWrite16(_space, offset, data);
664}
665
666UInt8 IOPCIDevice::extendedConfigRead8( IOByteCount offset )
667{
668	if (!configAccess(false)) return (0xFF);
669    IOPCIAddressSpace _space = space;
670    _space.es.registerNumExtended = (offset >> 8);
671    return (configRead8(_space, offset));
672}
673
674void IOPCIDevice::extendedConfigWrite8( IOByteCount offset, UInt8 data )
675{
676	if (!configAccess(true)) return;
677    IOPCIAddressSpace _space = space;
678    _space.es.registerNumExtended = (offset >> 8);
679    configWrite8(_space, offset, data);
680}
681
682// --
683
684UInt32 IOPCIDevice::findPCICapability( UInt8 capabilityID, UInt8 * offset )
685{
686    return (parent->findPCICapability(space, capabilityID, offset));
687}
688
689UInt32 IOPCIDevice::extendedFindPCICapability( UInt32 capabilityID, IOByteCount * offset )
690{
691    return (parent->extendedFindPCICapability(space, capabilityID, offset));
692}
693
694UInt32 IOPCIDevice::setConfigBits( UInt8 reg, UInt32 mask, UInt32 value )
695{
696    UInt32      was;
697    UInt32      bits;
698
699    bits = extendedConfigRead32( reg );
700    was = (bits & mask);
701    bits &= ~mask;
702    bits |= (value & mask);
703    extendedConfigWrite32( reg, bits );
704
705    return (was);
706}
707
708bool IOPCIDevice::setBusMasterEnable( bool enable )
709{
710    return (0 != setConfigBits(kIOPCIConfigCommand, kIOPCICommandBusMaster,
711                               enable ? kIOPCICommandBusMaster : 0));
712}
713
714bool IOPCIDevice::setMemoryEnable( bool enable )
715{
716    return (0 != setConfigBits(kIOPCIConfigCommand, kIOPCICommandMemorySpace,
717                               enable ? kIOPCICommandMemorySpace : 0));
718}
719
720bool IOPCIDevice::setIOEnable( bool enable, bool /* exclusive = false */ )
721{
722    // exclusive is TODO.
723    return (0 != setConfigBits(kIOPCIConfigCommand, kIOPCICommandIOSpace,
724                               enable ? kIOPCICommandIOSpace : 0));
725}
726
727UInt8 IOPCIDevice::getBusNumber( void )
728{
729    return (space.s.busNum);
730}
731
732UInt8 IOPCIDevice::getDeviceNumber( void )
733{
734    return (space.s.deviceNum);
735}
736
737UInt8 IOPCIDevice::getFunctionNumber( void )
738{
739    return (space.s.functionNum);
740}
741
742/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
743
744IODeviceMemory * IOPCIDevice::getDeviceMemoryWithIndex(unsigned int index)
745{
746	if (kTunnelL1NotSet == reserved->tunnelL1Allow) setTunnelL1Enable(this, false);
747
748    return (super::getDeviceMemoryWithIndex(index));
749}
750
751IODeviceMemory * IOPCIDevice::getDeviceMemoryWithRegister( UInt8 reg )
752{
753    OSArray *           array;
754    IODeviceMemory *    range;
755    unsigned int        i = 0;
756
757	if (kTunnelL1NotSet == reserved->tunnelL1Allow) setTunnelL1Enable(this, false);
758
759    array = (OSArray *) getProperty( gIODeviceMemoryKey);
760    if (0 == array)
761        return (0);
762
763    while ((range = (IODeviceMemory *) array->getObject(i++)))
764    {
765        if (reg == (range->getTag() & 0xff))
766            break;
767    }
768
769    return (range);
770}
771
772IOMemoryMap * IOPCIDevice:: mapDeviceMemoryWithRegister( UInt8 reg,
773        IOOptionBits options )
774{
775    IODeviceMemory *    range;
776    IOMemoryMap *       map;
777
778    range = getDeviceMemoryWithRegister( reg );
779    if (range)
780        map = range->map( options );
781    else
782        map = 0;
783
784    return (map);
785}
786
787/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
788
789IODeviceMemory * IOPCIDevice::ioDeviceMemory( void )
790{
791    return (parent->ioDeviceMemory());
792}
793
794/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
795
796IOService * IOPCIDevice::matchLocation( IOService * /* client */ )
797{
798    return (this);
799}
800
801/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
802
803OSMetaClassDefineReservedUsed(IOPCIDevice,  0);
804bool IOPCIDevice::hasPCIPowerManagement(IOOptionBits state)
805{
806    UInt16      pciPMCapReg, checkMask;
807    OSData      *aString;
808
809    reserved->sleepControlBits = 0;               // on a new query, we reset the proper sleep control bits
810    if (!reserved->pmControlStatus) return (false);
811
812    pciPMCapReg = extendedConfigRead16(reserved->pmControlStatus - sizeof(uint16_t));
813//    DLOG("%s[%p]::hasPCIPwrMgmt found pciPMCapReg %x\n",
814//        getName(), this, pciPMCapReg);
815
816    if (state)
817    {
818        checkMask = state;
819        switch (state)
820        {
821            case kPCIPMCPMESupportFromD3Cold:
822            case kPCIPMCPMESupportFromD3Hot:
823                reserved->sleepControlBits = (kPCIPMCSPMEStatus | kPCIPMCSPMEEnable | kPCIPMCSPowerStateD3);
824                break;
825            case kPCIPMCPMESupportFromD2:
826                reserved->sleepControlBits = (kPCIPMCSPMEStatus | kPCIPMCSPMEEnable | kPCIPMCSPowerStateD2);
827                break;
828            case kPCIPMCPMESupportFromD1:
829                reserved->sleepControlBits = (kPCIPMCSPMEStatus | kPCIPMCSPMEEnable | kPCIPMCSPowerStateD1);
830                break;
831            case kPCIPMCD2Support:
832                reserved->sleepControlBits = kPCIPMCSPowerStateD2;
833                break;
834            case kPCIPMCD1Support:
835                reserved->sleepControlBits = kPCIPMCSPowerStateD1;
836                break;
837            case kPCIPMCD3Support:
838                reserved->sleepControlBits = kPCIPMCSPowerStateD3;
839                checkMask = 0;
840                break;
841            default:
842                break;
843        }
844        if (checkMask && !(checkMask & pciPMCapReg))
845            reserved->sleepControlBits = 0;
846    }
847    else
848    {
849        if ((aString = OSDynamicCast(OSData, getProperty("sleep-power-state"))))
850        {
851            DLOG("%s[%p]::hasPCIPwrMgmt found sleep-power-state string %p\n", getName(), this, aString);
852            if (aString->isEqualTo("D3cold", strlen("D3cold")))
853                reserved->sleepControlBits = (kPCIPMCSPMEStatus | kPCIPMCSPMEEnable | kPCIPMCSPowerStateD3);
854            else if (aString->isEqualTo("D3Hot", strlen("D3Hot")))
855                reserved->sleepControlBits = (kPCIPMCSPMEStatus | kPCIPMCSPMEEnable | kPCIPMCSPowerStateD3);
856        }
857    }
858
859    return (reserved->sleepControlBits ? true : false);
860}
861
862/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
863
864OSMetaClassDefineReservedUsed(IOPCIDevice,  1);
865IOReturn IOPCIDevice::enablePCIPowerManagement(IOOptionBits state)
866{
867    IOReturn    ret = kIOReturnSuccess;
868
869    if (!reserved->pmControlStatus)
870    {
871        ret = kIOReturnBadArgument;
872        return ret;
873    }
874
875    if ( state == kPCIPMCSPowerStateD0 )
876    {
877        reserved->sleepControlBits = 0;
878        reserved->pmSleepEnabled = false;
879        return ret;
880    }
881    else
882    {
883        UInt32  oldBits = reserved->sleepControlBits;
884
885        reserved->sleepControlBits = state & kPCIPMCSPowerStateMask;
886
887        if ( oldBits & kPCIPMCSPMEStatus )
888            reserved->sleepControlBits |= kPCIPMCSPMEStatus;
889
890        if ( oldBits & kPCIPMCSPMEEnable )
891            reserved->sleepControlBits |= kPCIPMCSPMEEnable;
892
893        if (!reserved->sleepControlBits)
894        {
895            DLOG("%s[%p] - enablePCIPwrMgmt - no sleep control bits - not enabling\n", getName(), this);
896            ret = kIOReturnBadArgument;
897        }
898        else
899        {
900            DLOG("%s[%p] - enablePCIPwrMgmt, enabling\n", getName(), this);
901            reserved->pmSleepEnabled = true;
902#if VERSION_MAJOR < 10
903            if (getProperty(kIOPCIPMEOptionsKey))
904#endif
905                reserved->pmSleepEnabled |= kPMEOption;
906        }
907    }
908    return ret;
909}
910
911/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
912
913IOReturn
914IOPCIDevice::callPlatformFunction(const OSSymbol * functionName,
915                                          bool waitForFunction,
916                                          void * p1, void * p2,
917                                          void * p3, void * p4)
918{
919    IOReturn result;
920
921    result = super::callPlatformFunction(functionName, waitForFunction,
922                                         p1, p2, p3, p4);
923
924    if ((kIOReturnUnsupported == result)
925     && (gIOPlatformDeviceASPMEnableKey == functionName)
926     && getProperty(kIOPCIDeviceASPMSupportedKey))
927    {
928    	IOOptionBits state = (p2 != 0) ? reserved->expressASPMDefault : 0;
929        result = parent->setDeviceASPMState(this, (IOService *) p1, state);
930    }
931
932    return (result);
933}
934
935IOReturn
936IOPCIDevice::callPlatformFunction(const char * functionName,
937                                          bool waitForFunction,
938                                          void * p1, void * p2,
939                                          void * p3, void * p4)
940{
941    return (super::callPlatformFunction(functionName, waitForFunction,
942                                         p1, p2, p3, p4));
943}
944
945/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
946
947IOReturn IOPCIDevice::enableLTR(IOPCIDevice * device, bool enable)
948{
949	uint32_t reg;
950
951	if (!reserved->expressCapability || !expressV2(this))   return (kIOReturnUnsupported);
952
953	reg = extendedConfigRead32(reserved->expressCapability + 0x24);
954	if (!((1 << 11) & reg))                                 return (kIOReturnUnsupported);
955
956	reg = extendedConfigRead32(reserved->expressCapability + 0x28);
957	reg &= ~(1 << 10);
958	if (enable) reg |= ( 1 << 10);
959	extendedConfigWrite32(reserved->expressCapability + 0x28, reg);
960
961	return (kIOReturnSuccess);
962}
963
964IOReturn
965IOPCIDevice::setLatencyTolerance(IOOptionBits type, uint64_t nanoseconds)
966{
967	static const uint32_t ltrScales[] = { 1, 32, 1024, 32768, 1048576, 33554432 };
968
969	OSData * data;
970	uint64_t ltrScale, ltrValue;
971	uint32_t idx;
972	uint32_t reg1;
973	uint8_t  reg2;
974	uint8_t  reg3;
975
976	if (!reserved->ltrDevice)
977	{
978		IOPCIDevice * next;
979		next = this;
980		reserved->ltrDevice = (IOPCIDevice *) 1L;
981		while (next)
982		{
983			if ((data = OSDynamicCast(OSData, next->getProperty("reg-ltrovr"))))
984			{
985				reserved->ltrDevice = next;
986				uint64_t off = *((uint64_t *)data->getBytesNoCopy());
987				reserved->ltrOffset = off;
988				reserved->ltrReg1 = reserved->ltrDevice->extendedConfigRead32(reserved->ltrOffset);
989				reserved->ltrReg2 = reserved->ltrDevice->extendedConfigRead8(reserved->ltrOffset + 4);
990				break;
991			}
992			next = OSDynamicCast(IOPCIDevice, next->getParentEntry(gIODTPlane));
993		}
994	}
995
996	if (((uintptr_t) reserved->ltrDevice) <= 1) return (kIOReturnUnsupported);
997
998	for (ltrValue = idx = 0; idx < arrayCount(ltrScales); idx++)
999	{
1000		ltrScale = ltrScales[idx];
1001		ltrValue = (nanoseconds / ltrScale);
1002		if (ltrValue < (1<<10)) break;
1003	}
1004
1005	if (idx >= arrayCount(ltrScales)) return (kIOReturnMessageTooLarge);
1006
1007    reg1 = reserved->ltrReg1;
1008    reg2 = reserved->ltrReg2;
1009    reg3 = reg2;
1010
1011    if (kIOPCILatencySnooped & type)
1012    {
1013        reg1 &= 0x0000FFFF;
1014        reg1 |= (1 << 31) | (idx << 26) | (ltrValue << 16);
1015        reg2 &= ~(1 << 0);
1016        reg3 |= (1 << 3) | (1 << 0);
1017    }
1018    if (kIOPCILatencyUnsnooped & type)
1019    {
1020        reg1 &= 0xFFFF0000;
1021        reg1 |= (1 << 15) | (idx << 10) | (ltrValue << 0);
1022        reg2 &= ~(1 << 1);
1023        reg3 |= (1 << 3) | (1 << 1);
1024    }
1025    reserved->ltrDevice->extendedConfigWrite32(reserved->ltrOffset, reg1);
1026    reserved->ltrDevice->extendedConfigWrite8(reserved->ltrOffset + 4, reg2);
1027    reserved->ltrDevice->extendedConfigWrite8(reserved->ltrOffset + 4, reg3);
1028    reserved->ltrReg1 = reg1;
1029    reserved->ltrReg2 = reg3;
1030
1031#if 0
1032    DLOG("%s: ltr 0x%x = 0x%x, 0x%x\n",
1033         reserved->ltrDevice->getName(),
1034         (int)reserved->ltrOffset,
1035         reserved->ltrDevice->extendedConfigRead32(reserved->ltrOffset),
1036         reserved->ltrDevice->extendedConfigRead8(reserved->ltrOffset + 4));
1037#endif
1038
1039	return (kIOReturnSuccess);
1040}
1041
1042/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1043
1044IOReturn
1045IOPCIDevice::setASPMState(IOService * client, IOOptionBits state)
1046{
1047	IOPCI2PCIBridge * pcib;
1048
1049	if (!(pcib = OSDynamicCast(IOPCI2PCIBridge, parent))) return (kIOReturnUnsupported);
1050
1051    return (pcib->setDeviceASPMState(this, client, state));
1052}
1053
1054IOReturn
1055IOPCIDevice::setTunnelL1Enable(IOService * client, bool l1Enable)
1056{
1057	IOPCI2PCIBridge * pcib;
1058
1059	if (!(pcib = OSDynamicCast(IOPCI2PCIBridge, parent))) return (kIOReturnUnsupported);
1060
1061    return (pcib->setTunnelL1Enable(this, client, l1Enable));
1062}
1063
1064/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1065
1066IOPCIEventSource *
1067IOPCIDevice::createEventSource(OSObject * owner, IOPCIEventSource::Action action, uint32_t options)
1068{
1069    return (parent->createEventSource(this, owner, action, options));
1070}
1071
1072/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1073
1074IOReturn
1075IOPCIDevice::setProperties(OSObject * properties)
1076{
1077    IOReturn       ret = kIOReturnUnsupported;
1078    OSDictionary * dict;
1079    IOService *    ejectable;
1080    IOService *    topEjectable = NULL;
1081
1082    dict = OSDynamicCast(OSDictionary, properties);
1083    if (dict)
1084    {
1085        if (kOSBooleanFalse == dict->getObject(kIOPCIOnlineKey))
1086        {
1087            ejectable = this;
1088            do
1089            {
1090                if (ejectable->getProperty(kIOPCIEjectableKey))
1091                {
1092                    ejectable->setProperty(kIOPCIOnlineKey, kOSBooleanFalse);
1093                    topEjectable = ejectable;
1094                }
1095                ejectable = ejectable->getProvider();
1096            }
1097            while (ejectable);
1098            if (topEjectable)
1099            {
1100                ret = topEjectable->requestProbe(kIOPCIProbeOptionEject | kIOPCIProbeOptionDone);
1101            }
1102            return (ret);
1103        }
1104    }
1105
1106    return (super::setProperties(properties));
1107}
1108
1109IOReturn IOPCIDevice::requestProbe(IOOptionBits options)
1110{
1111    if (kIOReturnSuccess != IOUserClient::clientHasPrivilege(current_task(),
1112                                kIOClientPrivilegeLocalUser))
1113    {
1114        IOLog("IOPCIDevice requestProbe failed insufficient privileges\n");
1115        return (kIOReturnNotPrivileged);
1116    }
1117
1118    // debug
1119    return (kernelRequestProbe(options));
1120}
1121
1122IOReturn IOPCIDevice::kernelRequestProbe(uint32_t options)
1123{
1124    return (parent->kernelRequestProbe(this, options));
1125}
1126
1127IOReturn IOPCIDevice::protectDevice(uint32_t space, uint32_t prot)
1128{
1129	if (space != kIOPCIConfigSpace)
1130		return (kIOReturnUnsupported);
1131
1132	reserved->configProt = prot;
1133
1134    return (parent->protectDevice(this, space, prot));
1135}
1136
1137IOReturn IOPCIDevice::checkLink(uint32_t options)
1138{
1139    return (parent->checkLink(options));
1140}
1141
1142IOReturn IOPCIDevice::relocate(uint32_t options)
1143{
1144    return (parent->relocate(this, options));
1145}
1146
1147/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1148
1149IOReturn
1150IOPCIDevice::setConfigHandler(IOPCIDeviceConfigHandler handler, void * ref,
1151                              IOPCIDeviceConfigHandler * currentHandler, void ** currentRef)
1152{
1153    if (!configShadow(this))
1154        return (kIOReturnError);
1155
1156    if (currentHandler)
1157        *currentHandler = configShadow(this)->handler;
1158    if (currentRef)
1159        *currentRef = configShadow(this)->handlerRef;
1160
1161	configShadow(this)->handler    = handler;
1162	configShadow(this)->handlerRef = ref;
1163
1164    return (kIOReturnSuccess);
1165}
1166
1167/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1168
1169IOReturn IOPCIDevice::newUserClient(task_t owningTask, void * securityID,
1170                                    UInt32 type,  OSDictionary * properties,
1171                                    IOUserClient ** handler)
1172{
1173    return (kIOReturnUnsupported);
1174}
1175
1176/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1177
1178#undef super
1179#define super IOPCIDevice
1180
1181OSDefineMetaClassAndStructors(IOAGPDevice, IOPCIDevice)
1182OSMetaClassDefineReservedUnused(IOAGPDevice,  0);
1183OSMetaClassDefineReservedUnused(IOAGPDevice,  1);
1184OSMetaClassDefineReservedUnused(IOAGPDevice,  2);
1185OSMetaClassDefineReservedUnused(IOAGPDevice,  3);
1186OSMetaClassDefineReservedUnused(IOAGPDevice,  4);
1187OSMetaClassDefineReservedUnused(IOAGPDevice,  5);
1188OSMetaClassDefineReservedUnused(IOAGPDevice,  6);
1189OSMetaClassDefineReservedUnused(IOAGPDevice,  7);
1190OSMetaClassDefineReservedUnused(IOAGPDevice,  8);
1191OSMetaClassDefineReservedUnused(IOAGPDevice,  9);
1192OSMetaClassDefineReservedUnused(IOAGPDevice, 10);
1193OSMetaClassDefineReservedUnused(IOAGPDevice, 11);
1194OSMetaClassDefineReservedUnused(IOAGPDevice, 12);
1195OSMetaClassDefineReservedUnused(IOAGPDevice, 13);
1196OSMetaClassDefineReservedUnused(IOAGPDevice, 14);
1197OSMetaClassDefineReservedUnused(IOAGPDevice, 15);
1198OSMetaClassDefineReservedUnused(IOAGPDevice, 16);
1199
1200/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1201
1202IOReturn IOAGPDevice::createAGPSpace( IOOptionBits options,
1203                                      IOPhysicalAddress * address,
1204                                      IOPhysicalLength * length )
1205{
1206    return (parent->createAGPSpace(this, options, address, length));
1207}
1208
1209IOReturn IOAGPDevice::destroyAGPSpace( void )
1210{
1211    return (parent->destroyAGPSpace(this));
1212}
1213
1214IORangeAllocator * IOAGPDevice::getAGPRangeAllocator( void )
1215{
1216    return (parent->getAGPRangeAllocator(this));
1217}
1218
1219IOOptionBits IOAGPDevice::getAGPStatus( IOOptionBits options )
1220{
1221    return (parent->getAGPStatus(this, options));
1222}
1223
1224IOReturn IOAGPDevice::resetAGP( IOOptionBits options )
1225{
1226    return (parent->resetAGPDevice(this, options));
1227}
1228
1229IOReturn IOAGPDevice::getAGPSpace( IOPhysicalAddress * address,
1230                                   IOPhysicalLength * length )
1231{
1232    return (parent->getAGPSpace(this, address, length));
1233}
1234
1235IOReturn IOAGPDevice::commitAGPMemory(  IOMemoryDescriptor * memory,
1236                                        IOByteCount agpOffset,
1237                                        IOOptionBits options )
1238{
1239    return (parent->commitAGPMemory(this, memory, agpOffset, options));
1240}
1241
1242IOReturn IOAGPDevice::releaseAGPMemory( IOMemoryDescriptor * memory,
1243                                        IOByteCount agpOffset,
1244                                        IOOptionBits options )
1245{
1246    return (parent->releaseAGPMemory(this, memory, agpOffset, options));
1247}
1248
1249