static A_STATUS bmiBufferReceive(HIF_DEVICE *device, A_UCHAR *buffer, A_UINT32 length, A_BOOL want_timeout) { A_STATUS status; A_UINT32 address; A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX]; HIF_PENDING_EVENTS_INFO hifPendingEvents; static HIF_PENDING_EVENTS_FUNC getPendingEventsFunc = NULL; if (!pendingEventsFuncCheck) { /* see if the HIF layer implements an alternative function to get pending events * do this only once! */ HIFConfigureDevice(device, HIF_DEVICE_GET_PENDING_EVENTS_FUNC, &getPendingEventsFunc, sizeof(getPendingEventsFunc)); pendingEventsFuncCheck = TRUE; } HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR, &mboxAddress[0], sizeof(mboxAddress)); /* * During normal bootup, small reads may be required. * Rather than issue an HIF Read and then wait as the Target * adds successive bytes to the FIFO, we wait here until * we know that response data is available. * * This allows us to cleanly timeout on an unexpected * Target failure rather than risk problems at the HIF level. In * particular, this avoids SDIO timeouts and possibly garbage * data on some host controllers. And on an interconnect * such as Compact Flash (as well as some SDIO masters) which * does not provide any indication on data timeout, it avoids * a potential hang or garbage response. * * Synchronization is more difficult for reads larger than the * size of the MBOX FIFO (128B), because the Target is unable * to push the 129th byte of data until AFTER the Host posts an * HIF Read and removes some FIFO data. So for large reads the * Host proceeds to post an HIF Read BEFORE all the data is * actually available to read. Fortunately, large BMI reads do * not occur in practice -- they're supported for debug/development. * * So Host/Target BMI synchronization is divided into these cases: * CASE 1: length < 4 * Should not happen * * CASE 2: 4 <= length <= 128 * Wait for first 4 bytes to be in FIFO * If CONSERVATIVE_BMI_READ is enabled, also wait for * a BMI command credit, which indicates that the ENTIRE * response is available in the the FIFO * * CASE 3: length > 128 * Wait for the first 4 bytes to be in FIFO * * For most uses, a small timeout should be sufficient and we will * usually see a response quickly; but there may be some unusual * (debug) cases of BMI_EXECUTE where we want an larger timeout. * For now, we use an unbounded busy loop while waiting for * BMI_EXECUTE. * * If BMI_EXECUTE ever needs to support longer-latency execution, * especially in production, this code needs to be enhanced to sleep * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently * a function of Host processor speed. */ if (length >= 4) { /* NB: Currently, always true */ /* * NB: word_available is declared static for esoteric reasons * having to do with protection on some OSes. */ static A_UINT32 word_available; A_UINT32 timeout; word_available = 0; timeout = BMI_COMMUNICATION_TIMEOUT; while((!want_timeout || timeout--) && !word_available) { if (getPendingEventsFunc != NULL) { status = getPendingEventsFunc(device, &hifPendingEvents, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("BMI: Failed to get pending events \n")); break; } if (hifPendingEvents.AvailableRecvBytes >= sizeof(A_UINT32)) { word_available = 1; } continue; } #if defined(SDIO_3_0) status = HIFReadWrite(device, HOST_INT_STATUS_ADDRESS, (A_UINT8 *)&word_available, sizeof(word_available), HIF_RD_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read HOST_INT_STATUS_ADDRESS register\n")); return A_ERROR; } #else status = HIFReadWrite(device, RX_LOOKAHEAD_VALID_ADDRESS, (A_UINT8 *)&word_available, sizeof(word_available), HIF_RD_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read RX_LOOKAHEAD_VALID register\n")); return A_ERROR; } #endif /* We did a 4-byte read to the same register; all we really want is one bit */ #if defined(SDIO_3_0) word_available = (HOST_INT_STATUS_MBOX_DATA_GET(word_available) & ( 1 << ENDPOINT1)); #else word_available &= (1 << ENDPOINT1); #endif } if (!word_available) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferReceive FIFO empty\n")); return A_ERROR; } } #define CONSERVATIVE_BMI_READ 0 #if CONSERVATIVE_BMI_READ /* * This is an extra-conservative CREDIT check. It guarantees * that ALL data is available in the FIFO before we start to * read from the interconnect. * * This credit check is useless when firmware chooses to * allow multiple outstanding BMI Command Credits, since the next * credit will already be present. To restrict the Target to one * BMI Command Credit, see HI_OPTION_BMI_CRED_LIMIT. * * And for large reads (when HI_OPTION_BMI_CRED_LIMIT is set) * we cannot wait for the next credit because the Target's FIFO * will not hold the entire response. So we need the Host to * start to empty the FIFO sooner. (And again, large reads are * not used in practice; they are for debug/development only.) * * For a more conservative Host implementation (which would be * safer for a Compact Flash interconnect): * Set CONSERVATIVE_BMI_READ (above) to 1 * Set HI_OPTION_BMI_CRED_LIMIT and * reduce BMI_DATASZ_MAX to 32 or 64 */ if ((length > 4) && (length < 128)) { /* check against MBOX FIFO size */ A_UINT32 timeout; *pBMICmdCredits = 0; timeout = BMI_COMMUNICATION_TIMEOUT; while((!want_timeout || timeout--) && !(*pBMICmdCredits) { /* Read the counter register to get the command credits */ address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1; /* read the counter using a 4-byte read. Since the counter is NOT auto-decrementing, * we can read this counter multiple times using a non-incrementing address mode. * The rationale here is to make all HIF accesses a multiple of 4 bytes */ status = HIFReadWrite(device, address, (A_UINT8 *)pBMICmdCredits, sizeof(*pBMICmdCredits), HIF_RD_SYNC_BYTE_FIX, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to read the command credit count register\n")); return A_ERROR; } /* we did a 4-byte read to the same count register so mask off upper bytes */ (*pBMICmdCredits) &= 0xFF; }
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; }