AppleUSBUHCI_Interrupts.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/usb/IOUSBLog.h>
#include <IOKit/usb/IOUSBRootHubDevice.h>
#include "AppleUSBUHCI.h"
#include "AppleUHCIListElement.h"
#include "USBTracepoints.h"
#define super IOUSBControllerV3
#define self this
#pragma mark Interrupts
void
AppleUSBUHCI::PollInterrupts(IOUSBCompletionAction safeAction)
{
#pragma unused (safeAction)
USBLog(1, "AppleUSBUHCI[%p]::PollInterrupts (unused)", this);
}
void
AppleUSBUHCI::UpdateFrameNumberWithTime(void)
{
if (_anchorFrame != _tempAnchorFrame)
{
_anchorTime = _tempAnchorTime;
_anchorFrame = _tempAnchorFrame;
}
}
bool
AppleUSBUHCI::PrimaryInterruptFilter(OSObject *owner, IOFilterInterruptEventSource *source)
{
#pragma unused (source)
register AppleUSBUHCI *controller = (AppleUSBUHCI *)owner;
bool result = true;
if (!controller || controller->isInactive() || !controller->_controllerAvailable)
{
#if UHCI_USE_KPRINTF
kprintf("AppleUSBUHCI[%p]::PrimaryInterruptFilter - not available - ignoring\n", controller);
#endif
return false;
}
controller->_filterInterruptActive = true;
result = controller->FilterInterrupt();
controller->_filterInterruptActive = false;
return result;
}
void
AppleUSBUHCI::InterruptHandler(OSObject *owner, IOInterruptEventSource *source, int count)
{
#pragma unused (source, count)
AppleUSBUHCI *controller = (AppleUSBUHCI *)owner;
if (controller && !controller->isInactive() && controller->_controllerAvailable)
{
controller->HandleInterrupt();
}
#if UHCI_USE_KPRINTF
else
{
kprintf("AppleUSBUHCI[%p]::InterruptHandler - not available - ignoring\n", controller);
}
#endif
}
UInt64
AppleUSBUHCI::GetFrameNumberInternal(void)
{
UInt32 lastIrqFrameLow;
UInt32 currentIrqFrameLow;
UInt64 lastIrqFrameHi;
UInt64 currentFrame;
if (ioRead16(kUHCI_STS) & kUHCI_STS_HCH)
{
if (_myPowerState == kUSBPowerStateOn)
{
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsGetFrameNumberInternal, (uintptr_t)this, kUHCI_STS_HCH, 0, 0);
}
return 0;
}
lastIrqFrameLow = _lastIrqFrameLow;
lastIrqFrameHi = _lastIrqFrame & ~0x7ff;
currentIrqFrameLow = ReadFrameNumberRegister();
if (currentIrqFrameLow <= lastIrqFrameLow)
{
uint64_t tempTime;
lastIrqFrameHi += 0x800;
currentFrame = lastIrqFrameHi + ((UInt64) currentIrqFrameLow);
_tempAnchorFrame = currentFrame;
tempTime = mach_absolute_time();
_tempAnchorTime = *(AbsoluteTime*)&tempTime;
} else
{
currentFrame = lastIrqFrameHi + ((UInt64) currentIrqFrameLow);
}
_lastIrqFrameLow = currentIrqFrameLow;
_lastIrqFrame = currentFrame;
return (currentFrame);
}
bool
AppleUSBUHCI::FilterInterrupt(void)
{
UInt16 activeInterrupts;
Boolean needSignal = false;
UInt64 currentFrame;
uint64_t timeStamp;
activeInterrupts = ioRead16(kUHCI_STS) & kUHCI_STS_INTR_MASK;
if (activeInterrupts != 0)
{
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt , (uintptr_t)this, activeInterrupts, 0, 3 );
if (activeInterrupts & kUHCI_STS_HCPE)
{
_hostControllerProcessInterrupt = kUHCI_STS_HCPE;
ioWrite16(kUHCI_STS, kUHCI_STS_HCPE);
needSignal = true;
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostControllerProcessInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 1 );
}
if (activeInterrupts & kUHCI_STS_HSE)
{
_hostSystemErrorInterrupt = kUHCI_STS_HSE;
ioWrite16(kUHCI_STS, kUHCI_STS_HSE);
needSignal = true;
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsFilterInterrupt, (uintptr_t)this, _hostSystemErrorInterrupt, _device->configRead16(kUHCI_PCI_LEGKEY), 2 );
}
if (activeInterrupts & kUHCI_STS_RD)
{
_resumeDetectInterrupt = kUHCI_STS_RD;
ioWrite16(kUHCI_STS, kUHCI_STS_RD);
needSignal = true;
}
if (activeInterrupts & kUHCI_STS_EI)
{
_usbErrorInterrupt = kUHCI_STS_EI;
ioWrite16(kUHCI_STS, kUHCI_STS_EI);
needSignal = true;
}
if (activeInterrupts & kUHCI_STS_INT)
{
timeStamp = mach_absolute_time();
ioWrite16(kUHCI_STS, kUHCI_STS_INT);
needSignal = true;
GetFrameNumberInternal();
if (!_inAbortIsochEP && (_outSlot < kUHCI_NVFRAMES))
{
AppleUHCIIsochTransferDescriptor *cachedHead;
UInt32 cachedProducer;
UInt16 curSlot, testSlot, nextSlot;
curSlot = (ReadFrameNumber() & kUHCI_NVFRAMES_MASK);
cachedHead = (AppleUHCIIsochTransferDescriptor*)_savedDoneQueueHead;
cachedProducer = _producerCount;
testSlot = _outSlot;
while (testSlot != curSlot)
{
IOUSBControllerListElement *thing, *nextThing;
AppleUHCIIsochTransferDescriptor *isochTD;
nextSlot = (testSlot+1) & kUHCI_NVFRAMES_MASK;
thing = _logicalFrameList[testSlot];
while (thing != NULL)
{
nextThing = thing->_logicalNext;
isochTD = OSDynamicCast(AppleUHCIIsochTransferDescriptor, thing);
if (!isochTD)
break;
_logicalFrameList[testSlot] = nextThing;
_frameList[testSlot] = HostToUSBLong(thing->GetPhysicalLink());
if (isochTD->_lowLatency)
isochTD->frStatus = isochTD->UpdateFrameList(*(AbsoluteTime*)&timeStamp);
isochTD->_doneQueueLink = cachedHead;
cachedHead = isochTD;
cachedProducer++;
if (isochTD->_pEndpoint)
{
isochTD->_pEndpoint->onProducerQ++;
OSDecrementAtomic( &(isochTD->_pEndpoint->scheduledTDs));
}
thing = nextThing;
}
testSlot = nextSlot;
_outSlot = testSlot;
}
IOSimpleLockLock( _wdhLock );
_savedDoneQueueHead = cachedHead; _producerCount = cachedProducer;
IOSimpleLockUnlock( _wdhLock );
}
_usbCompletionInterrupt = kUHCI_STS_INT;
}
}
if (needSignal)
_interruptSource->signalInterrupt();
return false;
}
void
AppleUSBUHCI::HandleInterrupt(void)
{
UInt16 status;
UInt32 intrStatus;
bool needReset = false;
status = ioRead16(kUHCI_STS);
USBTrace_Start( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 0);
if (_hostControllerProcessInterrupt & kUHCI_STS_HCPE)
{
_hostControllerProcessInterrupt = 0;
USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller process error", this);
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 1 );
needReset = true;
}
if (_hostSystemErrorInterrupt & kUHCI_STS_HSE)
{
_hostSystemErrorInterrupt = 0;
USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller system error(CMD:%p STS:%p INTR:%p PORTSC1:%p PORTSC2:%p FRBASEADDR:%p ConfigCMD:%p)", this,(void*)ioRead16(kUHCI_CMD), (void*)ioRead16(kUHCI_STS), (void*)ioRead16(kUHCI_INTR), (void*)ioRead16(kUHCI_PORTSC1), (void*)ioRead16(kUHCI_PORTSC2), (void*)ioRead32(kUHCI_FRBASEADDR), (void*)_device->configRead16(kIOPCIConfigCommand));
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, ioRead16(kUHCI_CMD), 0, 2 );
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, ioRead16(kUHCI_STS), ioRead16(kUHCI_INTR), ioRead16(kUHCI_PORTSC1), 3 );
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, ioRead16(kUHCI_PORTSC2), ioRead32(kUHCI_FRBASEADDR), _device->configRead16(kIOPCIConfigCommand), 4 );
needReset = true;
}
if (_resumeDetectInterrupt & kUHCI_STS_RD)
{
_resumeDetectInterrupt = 0;
USBLog(2, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller resume detected - calling EnsureUsability", this);
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 6);
EnsureUsability();
}
if (_usbErrorInterrupt & kUHCI_STS_EI)
{
_usbErrorInterrupt = 0;
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 7);
USBLog(6, "AppleUSBUHCI[%p]::HandleInterrupt - Host controller error interrupt", this);
}
if (_usbCompletionInterrupt & kUHCI_STS_INT)
{
_usbCompletionInterrupt = 0;
UpdateFrameNumberWithTime();
USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Normal interrupt", this);
if (_consumerCount != _producerCount)
{
USBLog(7, "AppleUSBUHCI[%p]::HandleInterrupt - Isoch was handled", this);
}
}
if (needReset)
{
IOSleep(1000);
USBLog(1, "AppleUSBUHCI[%p]::HandleInterrupt - Resetting controller due to errors detected at interrupt time (0x%x)", this, status);
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, status, needReset, 5 );
Reset(true);
Run(true);
}
if (_myPowerState == kUSBPowerStateOn)
{
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, status, 0, 9);
ProcessCompletedTransactions();
RHCheckStatus();
}
else
{
USBLog(2, "AppleUSBUHCI[%p]::HandleInterrupt - deferring further processing until we are running again", this);
USBTrace( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 10);
}
USBTrace_End( kUSBTUHCIInterrupts, kTPUHCIInterruptsHandleInterrupt, (uintptr_t)this, 0, 0, 0);
}