/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef _IOKIT_APPLEAPIC_H #define _IOKIT_APPLEAPIC_H #include #include /* APIC direct register offsets */ enum { kOffsetIND = 0x00, /* 8-bits R/W Index */ kOffsetDAT = 0x10, /* 32-bits R/W Data */ kOffsetIRQPA = 0x20, /* 32-bits WO IRQ Pin Assertion */ kOffsetEOIR = 0x40 /* 32-bits WO EOI */ }; #define IOAPIC_REG(reg) \ (*((volatile UInt32 *)(_apicBaseAddr + kOffset##reg))) /* APIC indirect registers indices */ enum { kIndexID = 0x00, /* Identification */ kIndexVER = 0x01, /* Version */ kIndexARBID = 0x02, /* Arbitration ID */ kIndexBOOT = 0x03, /* Boot Config */ kIndexRTLO = 0x10, /* Redirection table lower 32-bits */ kIndexRTHI = 0x11 /* Redirection table upper 32-bits */ }; /* Bit fields for indirect registers */ enum { /* ID Register */ kIDAPICIDMask = 0x0F000000, kIDAPICIDShift = 24, /* Version Register */ kVERMaxEntriesMask = 0x00FF0000, kVERMaxEntriesShift = 16, kVERPRQMask = 0x00008000, kVERPRQShift = 15, kVERVersionMask = 0x000000FF, kVERVersionShift = 0, /* Arbitration ID Register */ kARBIDArbitrationIDMask = 0x0F000000, kARBIDArbitrationIDShift = 24, /* Boot Configuration Register */ kBOOTDeliveryTypeMask = 0x00000001, kBOOTDeliveryTypeShift = 0, /* Redirection Table Entries */ kRTLOVectorNumberMask = 0x000000FF, kRTLOVectorNumberShift = 0, kRTLODeliveryModeMask = 0x00000700, kRTLODeliveryModeShift = 8, kRTLODeliveryModeFixed = 0 << kRTLODeliveryModeShift, kRTLODeliveryModeLowestPriority = 1 << kRTLODeliveryModeShift, kRTLODeliveryModeSMI = 2 << kRTLODeliveryModeShift, kRTLODeliveryModeNMI = 4 << kRTLODeliveryModeShift, kRTLODeliveryModeINIT = 5 << kRTLODeliveryModeShift, kRTLODeliveryModeExtINT = 7 << kRTLODeliveryModeShift, kRTLODestinationModeMask = 0x00000800, kRTLODestinationModeShift = 11, kRTLODestinationModePhysical = 0 << kRTLODestinationModeShift, kRTLODestinationModeLogical = 1 << kRTLODestinationModeShift, kRTLODeliveryStatusMask = 0x00001000, kRTLODeliveryStatusShift = 12, kRTLOInputPolarityMask = 0x00002000, kRTLOInputPolarityShift = 13, kRTLOInputPolarityHigh = 0 << kRTLOInputPolarityShift, kRTLOInputPolarityLow = 1 << kRTLOInputPolarityShift, kRTLORemoteIRRMask = 0x00004000, kRTLORemoteIRRShift = 14, kRTLOTriggerModeMask = 0x00008000, kRTLOTriggerModeShift = 15, kRTLOTriggerModeEdge = 0 << kRTLOTriggerModeShift, kRTLOTriggerModeLevel = 1 << kRTLOTriggerModeShift, kRTLOMaskMask = 0x00010000, kRTLOMaskShift = 16, kRTLOMaskEnabled = 0, kRTLOMaskDisabled = kRTLOMaskMask, kRTHIExtendedDestinationIDMask = 0x00FF0000, kRTHIExtendedDestinationIDShift = 16, kRTHIDestinationMask = 0xFF000000, kRTHIDestinationShift = 24 }; /* Redirection Table vector entry */ struct VectorEntry { UInt32 l32; UInt32 h32; }; #define AppleAPIC AppleAPICInterruptController class AppleAPIC : public IOInterruptController { OSDeclareDefaultStructors( AppleAPICInterruptController ) protected: const OSSymbol * _handleSleepWakeFunction; // APIC registers are memory mapped. IOMemoryDescriptor * _apicMemory; IOMemoryMap * _apicMemoryMap; IOVirtualAddress _apicBaseAddr; IOSimpleLock * _apicLock; // The base global system interrupt number. This should be // zero for the first or only IO APIC in the system. long _vectorBase; // A cache of entries in the vector table. Makes restoring // hardware context following system sleep easier, and also // avoids a register read on vector updates. VectorEntry * _vectorTable; long _vectorCount; // The APIC ID of the CPU that will handle the interrupt. // in physical mode. long _destinationAddress; // ID register at register index 0, saved across sleep/wake. UInt32 _apicIDRegister; // Inline functions to read and write to the APIC // indirect registers. Must be accessed as 32-bit values. inline UInt32 indexRead( UInt32 index ) { IOAPIC_REG( IND ) = index; return IOAPIC_REG( DAT ); } inline void indexWrite( UInt32 index, UInt32 value ) { IOAPIC_REG( IND ) = index; IOAPIC_REG( DAT ) = value; } // Enable or disable (mask) a vector entry. Protected with // a spinlock with interrupt disabled. inline void enableVectorEntry( long vectorNumber ) { IOInterruptState state; state = IOSimpleLockLockDisableInterrupt( _apicLock ); _vectorTable[vectorNumber].l32 &= ~kRTLOMaskDisabled; indexWrite( kIndexRTLO + vectorNumber * 2, _vectorTable[vectorNumber].l32 ); IOSimpleLockUnlockEnableInterrupt( _apicLock, state ); } inline void disableVectorEntry( long vectorNumber ) { IOInterruptState state; state = IOSimpleLockLockDisableInterrupt( _apicLock ); _vectorTable[vectorNumber].l32 |= kRTLOMaskDisabled; indexWrite( kIndexRTLO + vectorNumber * 2, _vectorTable[vectorNumber].l32 ); IOSimpleLockUnlockEnableInterrupt( _apicLock, state ); } void resetVectorTable( void ); void writeVectorEntry( long vectorNumber ); void writeVectorEntry( long vectorNumber, VectorEntry entry ); void dumpRegisters( void ); void prepareForSleep( void ); void resumeFromSleep( void ); virtual void free( void ); public: virtual bool start( IOService * provider ); virtual IOReturn getInterruptType( IOService * nub, int source, int * interruptType ); virtual IOReturn registerInterrupt( IOService * nub, int source, void * target, IOInterruptHandler handler, void * refCon ); virtual void initVector( long vectorNumber, IOInterruptVector * vector ); virtual bool vectorCanBeShared( long vectorNumber, IOInterruptVector * vector ); virtual void enableVector( long vectorNumber, IOInterruptVector * vector ); virtual void disableVectorHard( long vectorNumber, IOInterruptVector * vector ); virtual IOReturn handleInterrupt( void * savedState, IOService * nub, int source ); virtual IOInterruptAction getInterruptHandlerAddress( void ); virtual IOReturn callPlatformFunction( const OSSymbol * function, bool waitForFunction, void * param1, void * param2, void * param3, void * param4 ); }; #endif /* !_IOKIT_APPLEAPIC_H */