A_STATUS bmiBufferReceive(HIF_DEVICE *device, A_UCHAR *buffer, A_UINT32 length) { A_STATUS status; A_UINT32 address; A_UINT32 timeout; #ifdef ONLY_16BIT A_UINT16 cmdCredits; #else A_UCHAR cmdCredits; #endif HIF_REQUEST request; HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1; status = HIFReadWrite(device, address, (A_UCHAR *)&cmdCredits, sizeof(cmdCredits), &request, NULL); if (status != A_OK) { BMI_DEBUG_PRINTF(ATH_LOG_ERR,"Unable to decrement the command credit count register\n"); return A_ERROR; } timeout = BMI_COMMUNICATION_TIMEOUT; while(timeout--) { if (cmdCredits == 1) { HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = HIF_MBOX_END_ADDR(ENDPOINT1); status = HIFReadWrite(device, address, buffer, length, &request, NULL); if (status != A_OK) { BMI_DEBUG_PRINTF(ATH_LOG_ERR,"Unable to read the BMI data from the device\n"); return A_ERROR; } break; } HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 1; status = HIFReadWrite(device, address, (A_UCHAR *)&cmdCredits, sizeof(cmdCredits), &request, NULL); if (status != A_OK) { BMI_DEBUG_PRINTF(ATH_LOG_ERR,"Unable to decrement the command credit count register\n"); return A_ERROR; } status = A_ERROR; A_MDELAY(1); } if (status != A_OK) { BMI_DEBUG_PRINTF(ATH_LOG_ERR,"BMI Communication timeout\n"); } return status; }
/* set the window address register */ A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address) { A_STATUS status; /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written * last to initiate the access cycle */ status = HIFReadWrite(hifDevice, RegisterAddr+1, /* write upper 3 bytes */ ((A_UCHAR *)(&Address))+1, sizeof(A_UINT32)-1, HIF_WR_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n", RegisterAddr, Address)); return status; } /* write the LSB of the register, this initiates the operation */ status = HIFReadWrite(hifDevice, RegisterAddr, (A_UCHAR *)(&Address), sizeof(A_UINT8), HIF_WR_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n", RegisterAddr, Address)); return status; } return A_OK; }
/* * Commit an address to either WINDOW_WRITE_ADDR_REG or to * WINDOW_READ_ADDR_REG. We write the least significan byte (LSB) * last, since it triggers the read/write. */ static void _WRITE_WINDOW_ADDR(HTC_TARGET *target, A_UINT32 whichreg, A_UINT32 value) { A_UINT32 window_addr; HIF_REQUEST request; A_STATUS status; A_UINT32 address; window_addr = value; HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS); address = getRegAddr(whichreg, ENDPOINT_UNUSED); #ifdef ONLY_16BIT status = HIFReadWrite(target->device, address+2, (A_UCHAR *)&window_addr+2, 2, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); status = HIFReadWrite(target->device, address, (A_UCHAR *)&window_addr, 2, &request, NULL); status = HIFReadWrite(target->device, address, (A_UCHAR *)&window_addr, 2, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); #else status = HIFReadWrite(target->device, address+1, (A_UCHAR *)&window_addr+1, 3, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); status = HIFReadWrite(target->device, address, (A_UCHAR *)&window_addr, 1, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); #endif }
A_STATUS ar6k_ReadTargetRegister(HIF_DEVICE *hifDevice, int regsel, A_UINT32 *regval) { A_STATUS status; A_UCHAR vals[4]; A_UCHAR register_selection[4]; register_selection[0] = register_selection[1] = register_selection[2] = register_selection[3] = (regsel & 0xff); status = HIFReadWrite(hifDevice, CPU_DBG_SEL_ADDRESS, register_selection, 4, HIF_WR_SYNC_BYTE_FIX, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write CPU_DBG_SEL (%d)\n", regsel)); return status; } status = HIFReadWrite(hifDevice, CPU_DBG_ADDRESS, (A_UCHAR *)vals, sizeof(vals), HIF_RD_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from CPU_DBG_ADDRESS\n")); return status; } *regval = vals[0]<<0 | vals[1]<<8 | vals[2]<<16 | vals[3]<<24; return status; }
/* set the window address register (using 4-byte register access ). * This mitigates host interconnect issues with non-4byte aligned bus requests, some * interconnects use bus adapters that impose strict limitations. * Since diag window access is not intended for performance critical operations, the 4byte mode should * be satisfactory even though it generates 4X the bus activity. */ static A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address) { A_STATUS status; static A_UINT8 addrValue[4]; A_INT32 i; static A_UINT32 address; address = Address; /* write bytes 1,2,3 of the register to set the upper address bytes, the LSB is written * last to initiate the access cycle */ for (i = 1; i <= 3; i++) { /* fill the buffer with the address byte value we want to hit 4 times*/ addrValue[0] = ((A_UINT8 *)&Address)[i]; addrValue[1] = addrValue[0]; addrValue[2] = addrValue[0]; addrValue[3] = addrValue[0]; /* hit each byte of the register address with a 4-byte write operation to the same address, * this is a harmless operation */ status = HIFReadWrite(hifDevice, RegisterAddr+i, addrValue, 4, HIF_WR_SYNC_BYTE_FIX, NULL); if (status != A_OK) { break; } } if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n", Address, RegisterAddr)); return status; } /* write the address register again, this time write the whole 4-byte value. * The effect here is that the LSB write causes the cycle to start, the extra * 3 byte write to bytes 1,2,3 has no effect since we are writing the same values again */ status = HIFReadWrite(hifDevice, RegisterAddr, (A_UCHAR *)(&address), 4, HIF_WR_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n", Address, RegisterAddr)); return status; } return A_OK; }
A_STATUS htcInterruptEnabler(HIF_DEVICE *device) { A_STATUS status; A_UINT32 address; HIF_REQUEST request; HTC_TARGET *target; HTC_REG_REQUEST_ELEMENT *element; target = getTargetInstance(device); AR_DEBUG_ASSERT(target != NULL); HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcInterruptEnabler Enter target: 0x%p\n", target); target->table.int_status_enable = INT_STATUS_ENABLE_ERROR_SET(0x01) | INT_STATUS_ENABLE_CPU_SET(0x01) | INT_STATUS_ENABLE_COUNTER_SET(0x01) | INT_STATUS_ENABLE_MBOX_DATA_SET(0x0F); /* Reenable Dragon Interrupts */ element = allocateRegRequestElement(target); AR_DEBUG_ASSERT(element != NULL); #ifdef ONLY_16BIT FILL_REG_BUFFER(element, (A_UINT16 *)&target->table.int_status_enable, 2, INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED); #else FILL_REG_BUFFER(element, &target->table.int_status_enable, 1, INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED); #endif HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_ASYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED); #ifdef ONLY_16BIT status = HIFReadWrite(target->device, address, &target->table.int_status_enable, 2, &request, element); #else status = HIFReadWrite(target->device, address, &target->table.int_status_enable, 1, &request, element); #endif #ifndef HTC_SYNC AR_DEBUG_ASSERT(status == A_OK); #else AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING); if ( status == A_OK ) { element->completionCB(element, status); } #endif //HTC_SYNC HTC_DEBUG_PRINTF(ATH_LOG_TRC,"htcInterruptEnabler Exit\n"); return A_OK; }
A_STATUS htcInterruptPending(HIF_DEVICE *device, A_BOOL *intPending) { A_STATUS status; A_UINT32 address; HTC_TARGET *target; HIF_REQUEST request; A_UCHAR intStatus[2] = {0,0}; A_UCHAR intMask[2] = {0,0}; target = getTargetInstance(device); AR_DEBUG_ASSERT(target != NULL); HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcInterruptPending Enter target: 0x%p\n", target); // get the current interrupt status register HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(INT_STATUS_REG, ENDPOINT_UNUSED); #ifdef ONLY_16BIT status = HIFReadWrite(target->device, address, intStatus, 2, &request, NULL); #else status = HIFReadWrite(target->device, address, intStatus, 1, &request, NULL); #endif AR_DEBUG_ASSERT(status == A_OK); // get the interrupt enable register value HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED); #ifdef ONLY_16BIT status = HIFReadWrite(target->device, address, intMask, 2, &request, NULL); #else status = HIFReadWrite(target->device, address, intMask, 1, &request, NULL); #endif AR_DEBUG_ASSERT(status == A_OK); if (!((intMask[0] & intStatus[0]) == 0)) { *intPending = TRUE; } else { *intPending = FALSE; } return A_OK; }
/* BMI Access routines */ A_STATUS bmiBufferSend(HIF_DEVICE *device, A_UCHAR *buffer, A_UINT32 length) { A_STATUS status; A_UINT32 timeout; A_UINT32 address; static A_UINT32 cmdCredits; A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX]; HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR, &mboxAddress[0], sizeof(mboxAddress)); cmdCredits = 0; timeout = BMI_COMMUNICATION_TIMEOUT; while(timeout-- && !cmdCredits) { /* Read the counter register to get the command credits */ address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; /* hit the credit counter with a 4-byte access, the first byte read will hit the counter and cause * a decrement, while the remaining 3 bytes has no effect. The rationale behind this is to * make all HIF accesses 4-byte aligned */ status = HIFReadWrite(device, address, (A_UINT8 *)&cmdCredits, 4, HIF_RD_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register\n")); return A_ERROR; } /* the counter is only 8=bits, ignore anything in the upper 3 bytes */ cmdCredits &= 0xFF; } if (cmdCredits) { address = mboxAddress[ENDPOINT1]; status = HIFReadWrite(device, address, buffer, length, HIF_WR_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to send the BMI data to the device\n")); return A_ERROR; } } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("BMI Communication timeout - bmiBufferSend\n")); return A_ERROR; } return status; }
static int DevServiceDebugInterrupt(AR6K_DEVICE *pDev) { u32 dummy; int status; /* Send a target failure event to the application */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n")); if (pDev->TargetFailureCallback != NULL) { pDev->TargetFailureCallback(pDev->HTCContext); } if (pDev->GMboxEnabled) { DevNotifyGMboxTargetFailure(pDev); } /* clear the interrupt , the debug error interrupt is * counter 0 */ /* read counter to clear interrupt */ status = HIFReadWrite(pDev->HIFDevice, COUNT_DEC_ADDRESS, (u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC, NULL); A_ASSERT(status == 0); return status; }
static A_STATUS DevServiceDebugInterrupt(AR6K_DEVICE *pDev) { A_UINT32 dummy; A_STATUS status; /* Send a target failure event to the application */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n")); if (pDev->TargetFailureCallback != NULL) { pDev->TargetFailureCallback(pDev->HTCContext); } /* clear the interrupt , the debug error interrupt is * counter 0 */ /* read counter to clear interrupt */ status = HIFReadWrite(pDev->HIFDevice, COUNT_DEC_ADDRESS, (A_UINT8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC, NULL); AR_DEBUG_ASSERT(status == A_OK); return status; }
void htcServiceCPUInterrupt(HTC_TARGET *target) { A_STATUS status; A_UINT32 address; HIF_REQUEST request; A_UINT8 cpu_int_status; HTC_DEBUG_PRINTF(ATH_LOG_INF, "CPU Interrupt\n"); cpu_int_status = target->table.cpu_int_status & target->table.cpu_int_status_enable; AR_DEBUG_ASSERT(cpu_int_status); HTC_DEBUG_PRINTF(ATH_LOG_INF, "Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", cpu_int_status); /* Figure out the interrupt number */ HTC_DEBUG_PRINTF(ATH_LOG_INF, "Interrupt Number: 0x%x\n", htcGetBitNumSet(cpu_int_status)); /* Clear the interrupt */ target->table.cpu_int_status = cpu_int_status; /* W1C */ HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(CPU_INT_STATUS_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, &target->table.cpu_int_status, 1, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); }
/* * Write to the AR6000 through its diagnostic window. * No cooperation from the Target is required for this. */ A_STATUS ar6000_WriteRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data) { A_STATUS status; /* set write data */ status = HIFReadWrite(hifDevice, WINDOW_DATA_ADDRESS, (A_UCHAR *)data, sizeof(A_UINT32), HIF_WR_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data)); printk("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", *data); return status; } /* set window register, which starts the write cycle */ #if 1 status = ar6000_SetAddressWindowRegister(hifDevice, WINDOW_WRITE_ADDR_ADDRESS, *address); return status; #else return ar6000_SetAddressWindowRegister(hifDevice, WINDOW_WRITE_ADDR_ADDRESS, *address); #endif }
void DumpAR6KDevState(AR6K_DEVICE *pDev) { int status; AR6K_IRQ_ENABLE_REGISTERS regs; AR6K_IRQ_PROC_REGISTERS procRegs; LOCK_AR6K(pDev); /* copy into our temp area */ A_MEMCPY(®s,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE); UNLOCK_AR6K(pDev); /* load the register table from the device */ status = HIFReadWrite(pDev->HIFDevice, HOST_INT_STATUS_ADDRESS, (u8 *)&procRegs, AR6K_IRQ_PROC_REGS_SIZE, HIF_RD_SYNC_BYTE_INC, NULL); if (status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("DumpAR6KDevState : Failed to read register table (%d) \n",status)); return; } DevDumpRegisters(pDev,&procRegs,®s); if (pDev->GMboxInfo.pStateDumpCallback != NULL) { pDev->GMboxInfo.pStateDumpCallback(pDev->GMboxInfo.pProtocolContext); } /* dump any bus state at the HIF layer */ HIFConfigureDevice(pDev->HIFDevice,HIF_DEVICE_DEBUG_BUS_STATE,NULL,0); }
/* * Read from the AR6000 through its diagnostic window. * No cooperation from the Target is required for this. */ A_STATUS ar6000_ReadRegDiag(HIF_DEVICE *hifDevice, A_UINT32 *address, A_UINT32 *data) { A_STATUS status; /* set window register to start read cycle */ status = ar6000_SetAddressWindowRegister(hifDevice, WINDOW_READ_ADDR_ADDRESS, *address); if (status != A_OK) { return status; } /* read the data */ status = HIFReadWrite(hifDevice, WINDOW_DATA_ADDRESS, (A_UCHAR *)data, sizeof(A_UINT32), HIF_RD_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot read from WINDOW_DATA_ADDRESS\n")); return status; } return status; }
A_STATUS htcBlkSzNegCompletionCB(HTC_DATA_REQUEST_ELEMENT *element, A_STATUS status) { HTC_TARGET *target; HTC_ENDPOINT *endPoint; HIF_REQUEST request; HTC_MBOX_BUFFER *mboxBuffer; HTC_REG_REQUEST_ELEMENT *regElement; A_UINT32 address; /* Get the context */ mboxBuffer = GET_MBOX_BUFFER(element); AR_DEBUG_ASSERT(mboxBuffer != NULL); endPoint = mboxBuffer->endPoint; AR_DEBUG_ASSERT(endPoint != NULL); target = endPoint->target; AR_DEBUG_ASSERT(target != NULL); /* Recycle the request element */ RECYCLE_DATA_REQUEST_ELEMENT(element); element->completionCB = htcTxCompletionCB; if (status == A_OK) { /* Mark the state to be ready */ endPoint->enabled = TRUE; /* Set the state of the target as ready */ if (target->endPoint[ENDPOINT1].enabled && target->endPoint[ENDPOINT2].enabled && target->endPoint[ENDPOINT3].enabled && target->endPoint[ENDPOINT4].enabled ) { /* Send the INT_WLAN interrupt to the target */ target->table.int_wlan = 1; HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_ASYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(INT_WLAN_REG, ENDPOINT_UNUSED); regElement = allocateRegRequestElement(target); AR_DEBUG_ASSERT(regElement != NULL); FILL_REG_BUFFER(regElement, &target->table.int_wlan, sizeof(target->table.int_wlan), INT_WLAN_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, (A_UCHAR *)&target->table.int_wlan, sizeof(target->table.int_wlan), &request, regElement); #ifndef HTC_SYNC AR_DEBUG_ASSERT(status == A_OK); #else AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING); if(status == A_OK) { regElement->completionCB(regElement, status); } #endif } } return A_OK; }
A_STATUS DevEnableInterrupts(AR6K_DEVICE *pDev) { A_STATUS status; AR6K_IRQ_ENABLE_REGISTERS regs; LOCK_AR6K(pDev); /* Enable all the interrupts except for the internal AR6000 CPU interrupt */ pDev->IrqEnableRegisters.int_status_enable = INT_STATUS_ENABLE_ERROR_SET(0x01) | INT_STATUS_ENABLE_CPU_SET(0x01) | INT_STATUS_ENABLE_COUNTER_SET(0x01); if (NULL == pDev->GetPendingEventsFunc) { pDev->IrqEnableRegisters.int_status_enable |= INT_STATUS_ENABLE_MBOX_DATA_SET(0x01); } else { /* The HIF layer provided us with a pending events function which means that * the detection of pending mbox messages is handled in the HIF layer. * This is the case for the SPI2 interface. * In the normal case we enable MBOX interrupts, for the case * with HIFs that offer this mechanism, we keep these interrupts * masked */ pDev->IrqEnableRegisters.int_status_enable &= ~INT_STATUS_ENABLE_MBOX_DATA_SET(0x01); } /* Set up the CPU Interrupt Status Register */ pDev->IrqEnableRegisters.cpu_int_status_enable = CPU_INT_STATUS_ENABLE_BIT_SET(0x00); /* Set up the Error Interrupt Status Register */ pDev->IrqEnableRegisters.error_status_enable = ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) | ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01); /* Set up the Counter Interrupt Status Register (only for debug interrupt to catch fatal errors) */ pDev->IrqEnableRegisters.counter_int_status_enable = COUNTER_INT_STATUS_ENABLE_BIT_SET(AR6K_TARGET_DEBUG_INTR_MASK); /* copy into our temp area */ A_MEMCPY(®s,&pDev->IrqEnableRegisters,AR6K_IRQ_ENABLE_REGS_SIZE); UNLOCK_AR6K(pDev); /* always synchronous */ status = HIFReadWrite(pDev->HIFDevice, INT_STATUS_ENABLE_ADDRESS, ®s.int_status_enable, AR6K_IRQ_ENABLE_REGS_SIZE, HIF_WR_SYNC_BYTE_INC, NULL); if (status != A_OK) { /* Can't write it for some reason */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Failed to update interrupt control registers err: %d\n", status)); } return status; }
/* 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 */ A_STATUS DevCheckPendingRecvMsgsAsync(void *context) { AR6K_DEVICE *pDev = (AR6K_DEVICE *)context; A_STATUS status = A_OK; 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%X)\n", (A_UINT32)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; } /* 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; AR_DEBUG_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; }
static A_STATUS DevServiceErrorInterrupt(AR6K_DEVICE *pDev) { A_STATUS status; A_UINT8 error_int_status; A_UINT8 regBuffer[4]; AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error Interrupt\n")); error_int_status = pDev->IrqProcRegisters.error_int_status & 0x0F; AR_DEBUG_ASSERT(error_int_status); AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n", error_int_status)); if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) { /* Wakeup */ AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error : Wakeup\n")); } if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) { /* Rx Underflow */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Rx Underflow\n")); if (pDev->TargetFailureCallback != NULL) { pDev->TargetFailureCallback(pDev->HTCContext, AR6K_TARGET_RX_ERROR); } } if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) { /* Tx Overflow */ AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Tx Overflow\n")); if (pDev->TargetFailureCallback != NULL) { pDev->TargetFailureCallback(pDev->HTCContext, AR6K_TARGET_TX_ERROR); } } /* Clear the interrupt */ pDev->IrqProcRegisters.error_int_status &= ~error_int_status; /* W1C */ /* set up the register transfer buffer to hit the register 4 times , this is done * to make the access 4-byte aligned to mitigate issues with host bus interconnects that * restrict bus transfer lengths to be a multiple of 4-bytes */ /* set W1C value to clear the interrupt, this hits the register first */ regBuffer[0] = error_int_status; /* the remaining 4 values are set to zero which have no-effect */ regBuffer[1] = 0; regBuffer[2] = 0; regBuffer[3] = 0; status = HIFReadWrite(pDev->HIFDevice, ERROR_INT_STATUS_ADDRESS, regBuffer, 4, HIF_WR_SYNC_BYTE_FIX, NULL); AR_DEBUG_ASSERT(status == A_OK); return status; }
A_STATUS htcInterruptDisabler(HIF_DEVICE *device,A_BOOL *callDsr) { A_STATUS status; A_UINT32 address; HTC_TARGET *target; HIF_REQUEST request; A_BOOL interruptPending; target = getTargetInstance(device); AR_DEBUG_ASSERT(target != NULL); HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcInterruptDisabler Enter target: 0x%p\n", target); // Check for spurious interrupt status = htcInterruptPending (device, &interruptPending); if (!interruptPending){ *callDsr=FALSE; } else { /* * Disable the interrupts from Dragon. * We do the interrupt servicing in the bottom half and reenable the * Dragon interrupts at the end of the bottom-half */ target->table.int_status_enable = 0; HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED); #ifdef ONLY_16BIT status = HIFReadWrite(target->device, address, &target->table.int_status_enable, 2, &request, NULL); #else status = HIFReadWrite(target->device, address, &target->table.int_status_enable, 1, &request, NULL); #endif AR_DEBUG_ASSERT(status == A_OK); *callDsr=TRUE; } HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcInterruptDisabler: Exit\n"); return A_OK; }
A_STATUS ar6000_SetAddressWindowRegister(HIF_DEVICE *hifDevice, A_UINT32 RegisterAddr, A_UINT32 Address) { A_STATUS status; A_UINT8 addrValue[4]; A_INT32 i; for (i = 1; i <= 3; i++) { addrValue[0] = ((A_UINT8 *)&Address)[i]; addrValue[1] = addrValue[0]; addrValue[2] = addrValue[0]; addrValue[3] = addrValue[0]; status = HIFReadWrite(hifDevice, RegisterAddr+i, addrValue, 4, HIF_WR_SYNC_BYTE_FIX, NULL); if (status != A_OK) { break; } } if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write initial bytes of 0x%x to window reg: 0x%X \n", RegisterAddr, Address)); return status; } status = HIFReadWrite(hifDevice, RegisterAddr, (A_UCHAR *)(&Address), 4, HIF_WR_SYNC_BYTE_INC, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_LOG_ERR, ("Cannot write 0x%x to window reg: 0x%X \n", RegisterAddr, Address)); return status; } return A_OK; }
int DevSetupGMbox(struct ar6k_device *pDev) { int status = 0; u8 muxControl[4]; do { if (0 == pDev->MailBoxInfo.GMboxAddress) { break; } AR_DEBUG_PRINTF(ATH_DEBUG_ANY,(" GMBOX Advertised: Address:0x%X , size:%d \n", pDev->MailBoxInfo.GMboxAddress, pDev->MailBoxInfo.GMboxSize)); status = DevGMboxIRQAction(pDev, GMBOX_DISABLE_ALL, PROC_IO_SYNC); if (status) { break; } /* write to mailbox look ahead mux control register, we want the * GMBOX lookaheads to appear on lookaheads 2 and 3 * the register is 1-byte wide so we need to hit it 4 times to align the operation * to 4-bytes */ muxControl[0] = GMBOX_LA_MUX_OVERRIDE_2_3; muxControl[1] = GMBOX_LA_MUX_OVERRIDE_2_3; muxControl[2] = GMBOX_LA_MUX_OVERRIDE_2_3; muxControl[3] = GMBOX_LA_MUX_OVERRIDE_2_3; status = HIFReadWrite(pDev->HIFDevice, GMBOX_LOOKAHEAD_MUX_REG, muxControl, sizeof(muxControl), HIF_WR_SYNC_BYTE_FIX, /* hit this register 4 times */ NULL); if (status) { break; } status = GMboxProtocolInstall(pDev); if (status) { break; } pDev->GMboxEnabled = true; } while (false); return status; }
int DevWaitForPendingRecv(struct ar6k_device *pDev,u32 TimeoutInMs,bool *pbIsRecvPending) { int status = 0; u8 host_int_status = 0x0; u32 counter = 0x0; if(TimeoutInMs < 100) { TimeoutInMs = 100; } counter = TimeoutInMs / 100; do { //Read the Host Interrupt Status Register status = HIFReadWrite(pDev->HIFDevice, HOST_INT_STATUS_ADDRESS, &host_int_status, sizeof(u8), HIF_RD_SYNC_BYTE_INC, NULL); if (status) { AR_DEBUG_PRINTF(ATH_LOG_ERR,("DevWaitForPendingRecv:Read HOST_INT_STATUS_ADDRESS Failed 0x%X\n",status)); break; } host_int_status = !status ? (host_int_status & (1 << 0)):0; if(!host_int_status) { status = 0; *pbIsRecvPending = false; break; } else { *pbIsRecvPending = true; } A_MDELAY(100); counter--; }while(counter); return status; }
A_STATUS DevWaitForPendingRecv(AR6K_DEVICE *pDev,A_UINT32 TimeoutInMs,A_BOOL *pbIsRecvPending) { A_STATUS status = A_OK; A_UCHAR host_int_status = 0x0; A_UINT32 counter = 0x0; if(TimeoutInMs < 100) { TimeoutInMs = 100; } counter = TimeoutInMs / 100; do { //Read the Host Interrupt Status Register status = HIFReadWrite(pDev->HIFDevice, HOST_INT_STATUS_ADDRESS, &host_int_status, sizeof(A_UCHAR), HIF_RD_SYNC_BYTE_INC, NULL); if(A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_LOG_ERR,("DevWaitForPendingRecv:Read HOST_INT_STATUS_ADDRESS Failed 0x%X\n",status)); break; } host_int_status = A_SUCCESS(status) ? (host_int_status & (1 << 0)):0; if(!host_int_status) { status = A_OK; *pbIsRecvPending = FALSE; break; } else { *pbIsRecvPending = TRUE; } A_MDELAY(100); counter--; }while(counter); return status; }
static int hifDeviceSuspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); A_STATUS status = A_OK; HIF_DEVICE *device; device = getHifDevice(func); if (device && device->claimedContext && osdrvCallbacks.deviceSuspendHandler) { status = osdrvCallbacks.deviceSuspendHandler(device->claimedContext); } if (status == A_OK) { int oldresetvalue = reset_sdio_on_unload; reset_sdio_on_unload = 1; hifDisableFunc(device, func); reset_sdio_on_unload = oldresetvalue; device->is_suspend = TRUE; } else if (status == A_EBUSY) { A_INT32 cnt = 10; A_UINT8 host_int_status; do { while (atomic_read(&device->irqHandling)) { /* wait until irq handler finished all the jobs */ schedule_timeout(HZ/10); } /* check if there is any pending irq due to force done */ host_int_status = 0; status = HIFReadWrite(device, HOST_INT_STATUS_ADDRESS, (A_UINT8 *)&host_int_status, sizeof(host_int_status), HIF_RD_SYNC_BYTE_INC, NULL); host_int_status = A_SUCCESS(status) ? (host_int_status & (1 << 0)) : 0; if (host_int_status) { schedule(); /* schedule for next dsrHandler */ } } while (host_int_status && --cnt > 0); if (host_int_status && cnt == 0) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: %s(), Unable clear up pending IRQ before the system suspended\n", __FUNCTION__)); } #if 1 status = A_OK; /* assume that sdio host controller will take care the power of wifi chip */ #else return -EBUSY; /* Return -EBUSY if customer use all android patch of mmc stack provided by us */ #endif } return A_SUCCESS(status) ? 0 : status; }
/* poll the mailbox credit counter until we get a credit or timeout */ static A_STATUS GetCredits(AR6K_DEVICE *pDev, int mbox, int *pCredits) { A_STATUS status = A_OK; int timeout = TEST_CREDITS_RECV_TIMEOUT; A_UINT8 credits = 0; A_UINT32 address; while (TRUE) { /* Read the counter register to get credits, this auto-decrements */ address = COUNT_DEC_ADDRESS + (AR6K_MAILBOXES + mbox) * 4; status = HIFReadWrite(pDev->HIFDevice, address, &credits, sizeof(credits), HIF_RD_SYNC_BYTE_FIX, NULL); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to decrement the command credit count register (mbox=%d)\n",mbox)); status = A_ERROR; break; } if (credits) { break; } timeout--; if (timeout <= 0) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, (" Timeout reading credit registers (mbox=%d, address:0x%X) \n",mbox,address)); status = A_ERROR; break; } /* delay a little, target may not be ready */ A_MDELAY(1000); } if (status == A_OK) { *pCredits = credits; } return status; }
void htcServiceErrorInterrupt(HTC_TARGET *target) { A_STATUS status; A_UINT32 address; HIF_REQUEST request; A_UINT8 error_int_status; HTC_DEBUG_PRINTF(ATH_LOG_INF, "Error Interrupt\n"); error_int_status = target->table.error_int_status & target->table.error_status_enable; AR_DEBUG_ASSERT(error_int_status); HTC_DEBUG_PRINTF(ATH_LOG_INF, "Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n", error_int_status); if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) { /* Wakeup */ HTC_DEBUG_PRINTF(ATH_LOG_INF, "Wakeup\n"); } if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) { /* Rx Underflow */ HTC_DEBUG_PRINTF(ATH_LOG_INF, "Rx Underflow\n"); } if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) { /* Tx Overflow */ HTC_DEBUG_PRINTF(ATH_LOG_INF, "Tx Overflow\n"); } /* Clear the interrupt */ target->table.error_int_status = error_int_status; /* W1C */ HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(ERROR_INT_STATUS_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, &target->table.error_int_status, 1, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); }
/* send the ordered buffers to the target */ static A_STATUS SendBuffers(AR6K_DEVICE *pDev, int mbox) { A_STATUS status = A_OK; A_UINT32 request = HIF_WR_SYNC_BLOCK_INC; BUFFER_PROC_LIST sendList[BUFFER_PROC_LIST_DEPTH]; int i; int totalBytes = 0; int paddedLength; int totalwPadding = 0; AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sending buffers on mailbox : %d \n",mbox)); /* fill buffer with counting pattern */ InitBuffers(FILL_COUNTING); /* assemble the order in which we send */ AssembleBufferList(sendList); for (i = 0; i < BUFFER_PROC_LIST_DEPTH; i++) { /* we are doing block transfers, so we need to pad everything to a block size */ paddedLength = (sendList[i].length + (g_BlockSizes[mbox] - 1)) & (~(g_BlockSizes[mbox] - 1)); /* send each buffer synchronously */ status = HIFReadWrite(pDev->HIFDevice, g_MailboxAddrs[mbox], sendList[i].pBuffer, paddedLength, request, NULL); if (status != A_OK) { break; } totalBytes += sendList[i].length; totalwPadding += paddedLength; } AR_DEBUG_PRINTF(ATH_PRINT_OUT_ZONE, ("Sent %d bytes (%d padded bytes) to mailbox : %d \n",totalBytes,totalwPadding,mbox)); return status; }
A_STATUS DevGMboxRead(AR6K_DEVICE *pDev, HTC_PACKET *pPacket, A_UINT32 ReadLength) { A_UINT32 paddedLength; A_STATUS status; A_BOOL sync = (pPacket->Completion == NULL) ? TRUE : FALSE; /* adjust the length to be a multiple of block size if appropriate */ paddedLength = DEV_CALC_RECV_PADDED_LEN(pDev, ReadLength); if (paddedLength > pPacket->BufferLength) { A_ASSERT(FALSE); AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("DevGMboxRead, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n", paddedLength,ReadLength,pPacket->BufferLength)); if (pPacket->Completion != NULL) { COMPLETE_HTC_PACKET(pPacket,A_EINVAL); return A_OK; } return A_EINVAL; } AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("DevGMboxRead (0x%X : hdr:0x%X) Padded Length: %d Mbox:0x%X (mode:%s)\n", (A_UINT32)pPacket, pPacket->PktInfo.AsRx.ExpectedHdr, paddedLength, pDev->MailBoxInfo.GMboxAddress, sync ? "SYNC" : "ASYNC")); status = HIFReadWrite(pDev->HIFDevice, pDev->MailBoxInfo.GMboxAddress, pPacket->pBuffer, paddedLength, sync ? HIF_RD_SYNC_BLOCK_FIX : HIF_RD_ASYNC_BLOCK_FIX, sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */ if (sync) { pPacket->Status = status; } return status; }
int DevGMboxRead(struct ar6k_device *pDev, struct htc_packet *pPacket, u32 ReadLength) { u32 paddedLength; int status; bool sync = (pPacket->Completion == NULL) ? true : false; /* adjust the length to be a multiple of block size if appropriate */ paddedLength = DEV_CALC_RECV_PADDED_LEN(pDev, ReadLength); if (paddedLength > pPacket->BufferLength) { A_ASSERT(false); AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("DevGMboxRead, Not enough space for padlen:%d recvlen:%d bufferlen:%d \n", paddedLength,ReadLength,pPacket->BufferLength)); if (pPacket->Completion != NULL) { COMPLETE_HTC_PACKET(pPacket,A_EINVAL); return 0; } return A_EINVAL; } AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("DevGMboxRead (0x%lX : hdr:0x%X) Padded Length: %d Mbox:0x%X (mode:%s)\n", (unsigned long)pPacket, pPacket->PktInfo.AsRx.ExpectedHdr, paddedLength, pDev->MailBoxInfo.GMboxAddress, sync ? "SYNC" : "ASYNC")); status = HIFReadWrite(pDev->HIFDevice, pDev->MailBoxInfo.GMboxAddress, pPacket->pBuffer, paddedLength, sync ? HIF_RD_SYNC_BLOCK_FIX : HIF_RD_ASYNC_BLOCK_FIX, sync ? NULL : pPacket); /* pass the packet as the context to the HIF request */ if (sync) { pPacket->Status = status; } return status; }
int DevGMboxRecvLookAheadPeek(struct ar6k_device *pDev, u8 *pLookAheadBuffer, int *pLookAheadBytes) { int status = 0; struct ar6k_irq_proc_registers procRegs; int maxCopy; do { /* on entry the caller provides the length of the lookahead buffer */ if (*pLookAheadBytes > sizeof(procRegs.rx_gmbox_lookahead_alias)) { A_ASSERT(false); status = A_EINVAL; break; } maxCopy = *pLookAheadBytes; *pLookAheadBytes = 0; /* load the register table from the device */ status = HIFReadWrite(pDev->HIFDevice, HOST_INT_STATUS_ADDRESS, (u8 *)&procRegs, AR6K_IRQ_PROC_REGS_SIZE, HIF_RD_SYNC_BYTE_INC, NULL); if (status) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("DevGMboxRecvLookAheadPeek : Failed to read register table (%d) \n",status)); break; } if (procRegs.gmbox_rx_avail > 0) { int bytes = procRegs.gmbox_rx_avail > maxCopy ? maxCopy : procRegs.gmbox_rx_avail; memcpy(pLookAheadBuffer,&procRegs.rx_gmbox_lookahead_alias[0],bytes); *pLookAheadBytes = bytes; } } while (false); return status; }