/* queue a read/write request */ A_STATUS HIFReadWrite(HIF_DEVICE *device, A_UINT32 address, A_UCHAR *buffer, A_UINT32 length, A_UINT32 request, void *context) { A_STATUS status = A_OK; BUS_REQUEST *busrequest; AR_DEBUG_ASSERT(device != NULL); AR_DEBUG_ASSERT(device->func != NULL); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Device: %p addr:0x%X\n", device,address)); do { if ((request & HIF_ASYNCHRONOUS) || (request & HIF_SYNCHRONOUS)){ /* serialize all requests through the async thread */ AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: Execution mode: %s\n", (request & HIF_ASYNCHRONOUS)?"Async":"Synch")); busrequest = hifAllocateBusRequest(device); if (busrequest == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: no async bus requests available (%s, addr:0x%X, len:%d) \n", request & HIF_READ ? "READ":"WRITE", address, length)); return A_ERROR; } busrequest->address = address; busrequest->buffer = buffer; busrequest->length = length; busrequest->request = request; busrequest->context = context; AddToAsyncList(device, busrequest); if (request & HIF_SYNCHRONOUS) { AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued sync req: 0x%X\n", (unsigned int)busrequest)); /* wait for completion */ up(&device->sem_async); if (down_interruptible(&busrequest->sem_req) != 0) { /* interrupted, exit */ return A_ERROR; } else { A_STATUS status = busrequest->status; AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: sync return freeing 0x%X: 0x%X\n", (unsigned int)busrequest, busrequest->status)); AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: freeing req: 0x%X\n", (unsigned int)request)); hifFreeBusRequest(device, busrequest); return status; } } else { AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("AR6000: queued async req: 0x%X\n", (unsigned int)busrequest)); up(&device->sem_async); return A_PENDING; } } else { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("AR6000: Invalid execution mode: 0x%08x\n", (unsigned int)request)); status = A_EINVAL; break; } } while(0); return status; }
/* callback to issue a read-write scatter request */ static A_STATUS HifReadWriteScatter(HIF_DEVICE *device, HIF_SCATTER_REQ *pReq) { A_STATUS status = A_EINVAL; A_UINT32 request = pReq->Request; HIF_SCATTER_REQ_PRIV *pReqPriv = (HIF_SCATTER_REQ_PRIV *)pReq->HIFPrivate[0]; do { A_ASSERT(pReqPriv != NULL); AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: total len: %d Scatter Entries: %d\n", pReq->TotalLength, pReq->ValidScatterEntries)); if (!(request & HIF_EXTENDED_IO)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: Invalid command type: 0x%08x\n", request)); break; } if (!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS))) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: Invalid execution mode: 0x%08x\n", request)); break; } if (!(request & HIF_BLOCK_BASIS)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: Invalid data mode: 0x%08x\n", request)); break; } if (pReq->TotalLength > MAX_SCATTER_REQ_TRANSFER_SIZE) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("HIF-SCATTER: Invalid length: %d \n", pReq->TotalLength)); break; } if (pReq->TotalLength == 0) { A_ASSERT(FALSE); break; } /* add bus request to the async list for the async I/O thread to process */ AddToAsyncList(device, pReqPriv->busrequest); if (request & HIF_SYNCHRONOUS) { AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued sync req: 0x%lX\n", (unsigned long)pReqPriv->busrequest)); /* signal thread and wait */ up(&device->sem_async); if (down_interruptible(&pReqPriv->busrequest->sem_req) != 0) { AR_DEBUG_PRINTF(ATH_DEBUG_ERROR,("HIF-SCATTER: interrupted! \n")); /* interrupted, exit */ status = A_ERROR; break; } else { status = pReq->CompletionStatus; } } else { AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, ("HIF-SCATTER: queued async req: 0x%lX\n", (unsigned long)pReqPriv->busrequest)); /* wake thread, it will process and then take care of the async callback */ up(&device->sem_async); status = A_OK; } } while (FALSE); if (A_FAILED(status) && (request & HIF_ASYNCHRONOUS)) { pReq->CompletionStatus = status; pReq->CompletionRoutine(pReq); status = A_OK; } return status; }