/* Synchronousinterrupt handler, this handler kicks off all interrupt processing.*/ A_STATUS DevDsrHandler(void *context) { AR6K_DEVICE *pDev = (AR6K_DEVICE *)context; A_STATUS status = A_OK; A_BOOL done = FALSE; A_BOOL asyncProc = FALSE; AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDsrHandler: (dev: 0x%X)\n", (A_UINT32)pDev)); while (!done) { status = ProcessPendingIRQs(pDev, &done, &asyncProc); if (A_FAILED(status)) { break; } if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) { /* the HIF layer does not allow async IRQ processing, override the asyncProc flag */ asyncProc = FALSE; /* this will cause us to re-enter ProcessPendingIRQ() and re-read interrupt status registers. * this has a nice side effect of blocking us until all async read requests are completed. * This behavior is required on some HIF implementations that do not allow ASYNC * processing in interrupt handlers (like Windows CE) */ } if (asyncProc) { /* the function performed some async I/O for performance, we need to exit the ISR immediately, the check below will prevent the interrupt from being Ack'd while we handle it asynchronously */ break; } } if (A_SUCCESS(status) && !asyncProc) { /* Ack the interrupt only if : * 1. we did not get any errors in processing interrupts * 2. there are no outstanding async processing requests */ AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Acking interrupt from DevDsrHandler \n")); HIFAckInterrupt(pDev->HIFDevice); } AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDsrHandler \n")); return status; }
void HIFUnMaskInterrupt(HIF_DEVICE *device) { SDIO_STATUS status; AR_DEBUG_ASSERT(device != NULL); AR_DEBUG_ASSERT(device->handle != NULL); /* Unmask our function IRQ */ status = SDLIB_IssueConfig(device->handle, SDCONFIG_FUNC_UNMASK_IRQ, NULL, 0); AR_DEBUG_ASSERT(SDIO_SUCCESS(status)); /* * It was observed that if ar6000 module was removed while an interrupt * was pending then when its reloaded subsequently, the hcd/bus driver * expects an explicit acknowledgment before it can start reporting * interrupts. Under normal conditions, this should be harmless. */ HIFAckInterrupt(device); }
/* Synchronousinterrupt handler, this handler kicks off all interrupt processing.*/ int DevDsrHandler(void *context) { AR6K_DEVICE *pDev = (AR6K_DEVICE *)context; int status = 0; bool done = false; bool asyncProc = false; AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevDsrHandler: (dev: 0x%lX)\n", (unsigned long)pDev)); /* reset the recv counter that tracks when we need to yield from the DSR */ pDev->CurrentDSRRecvCount = 0; /* reset counter used to flag a re-scan of IRQ status registers on the target */ pDev->RecheckIRQStatusCnt = 0; while (!done) { status = ProcessPendingIRQs(pDev, &done, &asyncProc); if (status) { break; } if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) { /* the HIF layer does not allow async IRQ processing, override the asyncProc flag */ asyncProc = false; /* this will cause us to re-enter ProcessPendingIRQ() and re-read interrupt status registers. * this has a nice side effect of blocking us until all async read requests are completed. * This behavior is required on some HIF implementations that do not allow ASYNC * processing in interrupt handlers (like Windows CE) */ if (pDev->DSRCanYield && DEV_CHECK_RECV_YIELD(pDev)) { /* ProcessPendingIRQs() pulled enough recv messages to satisfy the yield count, stop * checking for more messages and return */ break; } } if (asyncProc) { /* the function performed some async I/O for performance, we need to exit the ISR immediately, the check below will prevent the interrupt from being Ack'd while we handle it asynchronously */ break; } } if (!status && !asyncProc) { /* Ack the interrupt only if : * 1. we did not get any errors in processing interrupts * 2. there are no outstanding async processing requests */ if (pDev->DSRCanYield) { /* if the DSR can yield do not ACK the interrupt, there could be more pending messages. * The HIF layer must ACK the interrupt on behalf of HTC */ AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Yield in effect (cur RX count: %d) \n", pDev->CurrentDSRRecvCount)); } else { AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Acking interrupt from DevDsrHandler \n")); HIFAckInterrupt(pDev->HIFDevice); } } AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevDsrHandler \n")); return status; }
void DevAsyncIrqProcessComplete(AR6K_DEVICE *pDev) { AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("DevAsyncIrqProcessComplete - forcing HIF IRQ ACK \n")); HIFAckInterrupt(pDev->HIFDevice); }
/* called by the HTC layer when it wants us to check if the device has any more pending * recv messages, this starts off a series of async requests to read interrupt registers */ int DevCheckPendingRecvMsgsAsync(void *context) { AR6K_DEVICE *pDev = (AR6K_DEVICE *)context; int status = 0; HTC_PACKET *pIOPacket; /* this is called in an ASYNC only context, we may NOT block, sleep or call any apis that can * cause us to switch contexts */ AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevCheckPendingRecvMsgsAsync: (dev: 0x%lX)\n", (unsigned long)pDev)); do { if (HIF_DEVICE_IRQ_SYNC_ONLY == pDev->HifIRQProcessingMode) { /* break the async processing chain right here, no need to continue. * The DevDsrHandler() will handle things in a loop when things are driven * synchronously */ break; } /* an optimization to bypass reading the IRQ status registers unecessarily which can re-wake * the target, if upper layers determine that we are in a low-throughput mode, we can * rely on taking another interrupt rather than re-checking the status registers which can * re-wake the target */ if (pDev->RecheckIRQStatusCnt == 0) { AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("Bypassing IRQ Status re-check, re-acking HIF interrupts\n")); /* ack interrupt */ HIFAckInterrupt(pDev->HIFDevice); break; } /* first allocate one of our HTC packets we created for async I/O * we reuse HTC packet definitions so that we can use the completion mechanism * in DevRWCompletionHandler() */ pIOPacket = AR6KAllocIOPacket(pDev); if (NULL == pIOPacket) { /* there should be only 1 asynchronous request out at a time to read these registers * so this should actually never happen */ status = A_NO_MEMORY; A_ASSERT(false); break; } /* stick in our completion routine when the I/O operation completes */ pIOPacket->Completion = DevGetEventAsyncHandler; pIOPacket->pContext = pDev; if (pDev->GetPendingEventsFunc) { /* HIF layer has it's own mechanism, pass the IO to it.. */ status = pDev->GetPendingEventsFunc(pDev->HIFDevice, (HIF_PENDING_EVENTS_INFO *)pIOPacket->pBuffer, pIOPacket); } else { /* standard way, read the interrupt register table asynchronously again */ status = HIFReadWrite(pDev->HIFDevice, HOST_INT_STATUS_ADDRESS, pIOPacket->pBuffer, AR6K_IRQ_PROC_REGS_SIZE, HIF_RD_ASYNC_BYTE_INC, pIOPacket); } AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,(" Async IO issued to get interrupt status...\n")); } while (false); AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevCheckPendingRecvMsgsAsync \n")); return status; }
/* callback when our fetch to get interrupt status registers completes */ static void DevGetEventAsyncHandler(void *Context, HTC_PACKET *pPacket) { AR6K_DEVICE *pDev = (AR6K_DEVICE *)Context; u32 lookAhead = 0; bool otherInts = false; AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("+DevGetEventAsyncHandler: (dev: 0x%lX)\n", (unsigned long)pDev)); do { if (pPacket->Status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" GetEvents I/O request failed, status:%d \n", pPacket->Status)); /* bail out, don't unmask HIF interrupt */ break; } if (pDev->GetPendingEventsFunc != NULL) { /* the HIF layer collected the information for us */ HIF_PENDING_EVENTS_INFO *pEvents = (HIF_PENDING_EVENTS_INFO *)pPacket->pBuffer; if (pEvents->Events & HIF_RECV_MSG_AVAIL) { lookAhead = pEvents->LookAhead; if (0 == lookAhead) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler1, lookAhead is zero! \n")); } } if (pEvents->Events & HIF_OTHER_EVENTS) { otherInts = true; } } else { /* standard interrupt table handling.... */ AR6K_IRQ_PROC_REGISTERS *pReg = (AR6K_IRQ_PROC_REGISTERS *)pPacket->pBuffer; u8 host_int_status; host_int_status = pReg->host_int_status & pDev->IrqEnableRegisters.int_status_enable; if (host_int_status & (1 << HTC_MAILBOX)) { host_int_status &= ~(1 << HTC_MAILBOX); if (pReg->rx_lookahead_valid & (1 << HTC_MAILBOX)) { /* mailbox has a message and the look ahead is valid */ lookAhead = pReg->rx_lookahead[HTC_MAILBOX]; if (0 == lookAhead) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,(" DevGetEventAsyncHandler2, lookAhead is zero! \n")); } } } if (host_int_status) { /* there are other interrupts to handle */ otherInts = true; } } if (otherInts || (lookAhead == 0)) { /* if there are other interrupts to process, we cannot do this in the async handler so * ack the interrupt which will cause our sync handler to run again * if however there are no more messages, we can now ack the interrupt */ AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, (" Acking interrupt from DevGetEventAsyncHandler (otherints:%d, lookahead:0x%X)\n", otherInts, lookAhead)); HIFAckInterrupt(pDev->HIFDevice); } else { int fetched = 0; int status; AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, (" DevGetEventAsyncHandler : detected another message, lookahead :0x%X \n", lookAhead)); /* lookahead is non-zero and there are no other interrupts to service, * go get the next message */ status = pDev->MessagePendingCallback(pDev->HTCContext, &lookAhead, 1, NULL, &fetched); if (!status && !fetched) { /* HTC layer could not pull out messages due to lack of resources, stop IRQ processing */ AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("MessagePendingCallback did not pull any messages, force-ack \n")); DevAsyncIrqProcessComplete(pDev); } } } while (false); /* free this IO packet */ AR6KFreeIOPacket(pDev,pPacket); AR_DEBUG_PRINTF(ATH_DEBUG_IRQ,("-DevGetEventAsyncHandler \n")); }
A_STATUS htcDSRHandler(HIF_DEVICE *device) { A_STATUS status; A_UINT32 address; HTC_TARGET *target; HIF_REQUEST request; A_UCHAR host_int_status; target = getTargetInstance(device); AR_DEBUG_ASSERT(target != NULL); HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcDsrHandler: Enter (target: 0x%p\n", target); /* * Read the first 28 bytes of the HTC register table. This will yield us * the value of different int status registers and the lookahead * registers. * length = sizeof(int_status) + sizeof(cpu_int_status) + * sizeof(error_int_status) + sizeof(counter_int_status) + * sizeof(mbox_frame) + sizeof(rx_lookahead_valid) + * sizeof(hole) + sizeof(rx_lookahead) + * sizeof(int_status_enable) + sizeof(cpu_int_status_enable) + * sizeof(error_status_enable) + * sizeof(counter_int_status_enable); */ HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS); address = getRegAddr(INT_STATUS_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, &target->table.host_int_status, 28, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); #ifdef DEBUG dumpRegisters(target); #endif /* DEBUG */ /* Update only those registers that are enabled */ /* This is not required as we have Already checked for * spuriours interrupt in htcInterruptDisabler */ host_int_status = target->table.host_int_status;// & //target->table.int_status_enable; HTC_DEBUG_PRINTF(ATH_LOG_INF, "Valid interrupt source(s) in INT_STATUS: 0x%x\n", host_int_status); if (HOST_INT_STATUS_CPU_GET(host_int_status)) { /* CPU Interrupt */ htcServiceCPUInterrupt(target); } if (HOST_INT_STATUS_ERROR_GET(host_int_status)) { /* Error Interrupt */ htcServiceErrorInterrupt(target); } if (HOST_INT_STATUS_MBOX_DATA_GET(host_int_status)) { /* Mailbox Interrupt */ htcServiceMailboxInterrupt(target); } if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) { /* Counter Interrupt */ htcServiceCounterInterrupt(target); } else { /* Ack the interrupt */ HIFAckInterrupt(target->device); } HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcDSRHandler: Exit\n"); return A_OK; }
A_STATUS htcRegCompletionCB(HTC_REG_REQUEST_ELEMENT *element, A_STATUS status) { A_STATUS ret; HTC_TARGET *target; HTC_ENDPOINT *endPoint; HTC_REG_BUFFER *regBuffer; #ifdef ONLY_16BIT A_UINT16 txCreditsConsumed; A_UINT16 txCreditsAvailable; #else A_UINT8 txCreditsConsumed; A_UINT8 txCreditsAvailable; #endif HTC_ENDPOINT_ID endPointId; HTC_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_SEND | ATH_LOG_RECV, "htcRegCompletion - Enter\n"); AR_DEBUG_ASSERT(status == A_OK); /* Get the context */ AR_DEBUG_ASSERT(element != NULL); regBuffer = GET_REG_BUFFER(element); AR_DEBUG_ASSERT(regBuffer != NULL); target = regBuffer->target; AR_DEBUG_ASSERT(target != NULL); /* Identify the register and the operation responsible for the callback */ ret = A_OK; switch(regBuffer->base) { case TX_CREDIT_COUNTER_DECREMENT_REG: HTC_DEBUG_PRINTF(ATH_LOG_INF, "TX_CREDIT_COUNTER_DECREMENT_REG\n"); endPointId = regBuffer->offset; endPoint = &target->endPoint[endPointId]; HTC_DEBUG_PRINTF(ATH_LOG_SYNC, "Critical Section (credit): LOCK at line %d in file %s\n", __LINE__, __FILE__); A_MUTEX_LOCK(&creditCS); /* Calculate the number of credits available */ #ifdef ONLY_16BIT AR_DEBUG_ASSERT((GET_TX_CREDITS_CONSUMED(endPoint)*2) == regBuffer->length); #else AR_DEBUG_ASSERT(GET_TX_CREDITS_CONSUMED(endPoint) == regBuffer->length); #endif AR_DEBUG_ASSERT(regBuffer->buffer[0] >= GET_TX_CREDITS_CONSUMED(endPoint)); SET_TX_CREDITS_AVAILABLE(endPoint, regBuffer->buffer[0] - GET_TX_CREDITS_CONSUMED(endPoint)); SET_TX_CREDITS_CONSUMED(endPoint, 0); txCreditsAvailable = GET_TX_CREDITS_AVAILABLE(endPoint); txCreditsConsumed = GET_TX_CREDITS_CONSUMED(endPoint); HTC_DEBUG_PRINTF(ATH_LOG_SYNC, "Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__); A_MUTEX_UNLOCK(&creditCS); HTC_DEBUG_PRINTF(ATH_LOG_INF | ATH_LOG_SEND, "Pulling %d tx credits from the target\n", txCreditsAvailable); #ifdef DEBUG txcreditsavailable[endPointId] = txCreditsAvailable; txcreditsconsumed[endPointId] = txCreditsConsumed; #endif /* DEBUG */ if (txCreditsAvailable) { htcSendFrame(endPoint); } else { /* * Enable the Tx credit counter interrupt so that we can get the * credits posted by the target. */ htcEnableCreditCounterInterrupt(target, endPointId); #ifdef DEBUG txcreditintrenable[endPointId] += 1; txcreditintrenableaggregate[endPointId] += 1; #endif /* DEBUG */ } break; case TX_CREDIT_COUNTER_RESET_REG: HTC_DEBUG_PRINTF(ATH_LOG_INF, "TX_CREDIT_COUNTER_RESET_REG\n"); endPointId = regBuffer->offset; /* * Enable the Tx credit counter interrupt so that we can get the * credits posted by the target. */ htcEnableCreditCounterInterrupt(target, endPointId); #ifdef DEBUG txcreditintrenable[endPointId] += 1; txcreditintrenableaggregate[endPointId] += 1; #endif /* DEBUG */ break; case COUNTER_INT_STATUS_ENABLE_REG: HTC_DEBUG_PRINTF(ATH_LOG_INF, "COUNTER_INT_STATUS_ENABLE: 0x%x\n", target->table.counter_int_status_enable); break; case COUNTER_INT_STATUS_DISABLE_REG: HTC_DEBUG_PRINTF(ATH_LOG_INF, "COUNTER_INT_STATUS_DISABLE:0x%x\n", target->table.counter_int_status_enable); HIFAckInterrupt(target->device); HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcDSRHandler - ACK\n"); break; case INT_WLAN_REG: HTC_DEBUG_PRINTF(ATH_LOG_INF, "INT_WLAN: 0x%x\n", target->table.int_wlan); target->table.int_wlan = 0; /* Mark the target state as ready and signal the waiting sem */ target->ready = TRUE; A_WAKE_UP(&htcEvent); break; case INT_STATUS_ENABLE_REG: HTC_DEBUG_PRINTF(ATH_LOG_INF, "INT_STATUS_ENABLE: 0x%x\n", target->table.int_status_enable); break; default: HTC_DEBUG_PRINTF(ATH_LOG_ERR, "Invalid register address: %d\n", regBuffer->base); } /* Free the register request structure */ freeRegRequestElement(element); HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcRegCompletion - Exit\n"); return ret; }