Exemple #1
0
/* 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"));
}
Exemple #7
0
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;
}
Exemple #8
0
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;
}