/* registered target arrival callback from the HIF layer */ HTC_HANDLE HTCCreate(void *hif_handle, HTC_INIT_INFO *pInfo) { HTC_TARGET *target = NULL; A_STATUS status = A_OK; int i; A_UINT32 ctrl_bufsz; A_UINT32 blocksizes[HTC_MAILBOX_NUM_MAX]; AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Enter\n")); printk("HTCCreate !!\n"); do { /* allocate target memory */ if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); status = A_ERROR; break; } A_MEMZERO(target, sizeof(HTC_TARGET)); A_MUTEX_INIT(&target->HTCLock); A_MUTEX_INIT(&target->HTCRxLock); A_MUTEX_INIT(&target->HTCTxLock); INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); INIT_HTC_PACKET_QUEUE(&target->ControlBufferRXFreeList); /* give device layer the hif device handle */ target->Device.HIFDevice = hif_handle; /* give the device layer our context (for event processing) * the device layer will register it's own context with HIF * so we need to set this so we can fetch it in the target remove handler */ target->Device.HTCContext = target; /* set device layer target failure callback */ target->Device.TargetFailureCallback = HTCReportFailure; /* set device layer recv message pending callback */ target->Device.MessagePendingCallback = HTCRecvMessagePendingHandler; target->EpWaitingForBuffers = ENDPOINT_MAX; A_MEMCPY(&target->HTCInitInfo,pInfo,sizeof(HTC_INIT_INFO)); /* setup device layer */ status = DevSetup(&target->Device); if (A_FAILED(status)) { break; } /* get the block sizes */ status = HIFConfigureDevice(hif_handle, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, blocksizes, sizeof(blocksizes)); if (A_FAILED(status)) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Failed to get block size info from HIF layer...\n")); break; } /* Set the control buffer size based on the block size */ if (blocksizes[1] > HTC_MAX_CONTROL_MESSAGE_LENGTH) { ctrl_bufsz = blocksizes[1] + HTC_HDR_LENGTH; } else { ctrl_bufsz = HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH; } for (i = 0;i < NUM_CONTROL_BUFFERS;i++) { target->HTCControlBuffers[i].Buffer = A_MALLOC(ctrl_bufsz); if (target->HTCControlBuffers[i].Buffer == NULL) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n")); status = A_ERROR; break; } } if (A_FAILED(status)) { break; } /* carve up buffers/packets for control messages */ for (i = 0; i < NUM_CONTROL_RX_BUFFERS; i++) { HTC_PACKET *pControlPacket; pControlPacket = &target->HTCControlBuffers[i].HtcPacket; SET_HTC_PACKET_INFO_RX_REFILL(pControlPacket, target, target->HTCControlBuffers[i].Buffer, ctrl_bufsz, ENDPOINT_0); HTC_FREE_CONTROL_RX(target,pControlPacket); } for (;i < NUM_CONTROL_BUFFERS;i++) { HTC_PACKET *pControlPacket; pControlPacket = &target->HTCControlBuffers[i].HtcPacket; INIT_HTC_PACKET_INFO(pControlPacket, target->HTCControlBuffers[i].Buffer, ctrl_bufsz); HTC_FREE_CONTROL_TX(target,pControlPacket); } } while (FALSE); if (A_FAILED(status)) { if (target != NULL) { HTCCleanup(target); target = NULL; } } AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("HTCCreate - Exit\n")); return target; }
int DevSetup(struct ar6k_device *pDev) { u32 blocksizes[AR6K_MAILBOXES]; int status = 0; int i; HTC_CALLBACKS htcCallbacks; do { DL_LIST_INIT(&pDev->ScatterReqHead); /* initialize our free list of IO packets */ INIT_HTC_PACKET_QUEUE(&pDev->RegisterIOList); A_MUTEX_INIT(&pDev->Lock); A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS)); /* the device layer handles these */ htcCallbacks.rwCompletionHandler = DevRWCompletionHandler; htcCallbacks.dsrHandler = DevDsrHandler; htcCallbacks.context = pDev; status = HIFAttachHTC(pDev->HIFDevice, &htcCallbacks); if (status) { break; } pDev->HifAttached = true; /* get the addresses for all 4 mailboxes */ status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR, &pDev->MailBoxInfo, sizeof(pDev->MailBoxInfo)); if (status) { A_ASSERT(false); break; } /* carve up register I/O packets (these are for ASYNC register I/O ) */ for (i = 0; i < AR6K_MAX_REG_IO_BUFFERS; i++) { struct htc_packet *pIOPacket; pIOPacket = &pDev->RegIOBuffers[i].HtcPacket; SET_HTC_PACKET_INFO_RX_REFILL(pIOPacket, pDev, pDev->RegIOBuffers[i].Buffer, AR6K_REG_IO_BUFFER_SIZE, 0); /* don't care */ AR6KFreeIOPacket(pDev,pIOPacket); } /* get the block sizes */ status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, blocksizes, sizeof(blocksizes)); if (status) { A_ASSERT(false); break; } /* note: we actually get the block size of a mailbox other than 0, for SDIO the block * size on mailbox 0 is artificially set to 1. So we use the block size that is set * for the other 3 mailboxes */ pDev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE]; /* must be a power of 2 */ A_ASSERT((pDev->BlockSize & (pDev->BlockSize - 1)) == 0); /* assemble mask, used for padding to a block */ pDev->BlockMask = pDev->BlockSize - 1; AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("BlockSize: %d, MailboxAddress:0x%X \n", pDev->BlockSize, pDev->MailBoxInfo.MboxAddresses[HTC_MAILBOX])); pDev->GetPendingEventsFunc = NULL; /* see if the HIF layer implements the get pending events function */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_PENDING_EVENTS_FUNC, &pDev->GetPendingEventsFunc, sizeof(pDev->GetPendingEventsFunc)); /* assume we can process HIF interrupt events asynchronously */ pDev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC; /* see if the HIF layer overrides this assumption */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_IRQ_PROC_MODE, &pDev->HifIRQProcessingMode, sizeof(pDev->HifIRQProcessingMode)); switch (pDev->HifIRQProcessingMode) { case HIF_DEVICE_IRQ_SYNC_ONLY: AR_DEBUG_PRINTF(ATH_DEBUG_WARN,("HIF Interrupt processing is SYNC ONLY\n")); /* see if HIF layer wants HTC to yield */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_IRQ_YIELD_PARAMS, &pDev->HifIRQYieldParams, sizeof(pDev->HifIRQYieldParams)); if (pDev->HifIRQYieldParams.RecvPacketYieldCount > 0) { AR_DEBUG_PRINTF(ATH_DEBUG_WARN, ("HIF requests that DSR yield per %d RECV packets \n", pDev->HifIRQYieldParams.RecvPacketYieldCount)); pDev->DSRCanYield = true; } break; case HIF_DEVICE_IRQ_ASYNC_SYNC: AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is ASYNC and SYNC\n")); break; default: A_ASSERT(false); } pDev->HifMaskUmaskRecvEvent = NULL; /* see if the HIF layer implements the mask/unmask recv events function */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC, &pDev->HifMaskUmaskRecvEvent, sizeof(pDev->HifMaskUmaskRecvEvent)); AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF special overrides : 0x%lX , 0x%lX\n", (unsigned long)pDev->GetPendingEventsFunc, (unsigned long)pDev->HifMaskUmaskRecvEvent)); status = DevDisableInterrupts(pDev); if (status) { break; } status = DevSetupGMbox(pDev); } while (false); if (status) { if (pDev->HifAttached) { HIFDetachHTC(pDev->HIFDevice); pDev->HifAttached = false; } } return status; }
A_STATUS DevSetup(AR6K_DEVICE *pDev) { A_UINT32 mailboxaddrs[AR6K_MAILBOXES]; A_UINT32 blocksizes[AR6K_MAILBOXES]; A_STATUS status = A_OK; int i; HTC_CALLBACKS htcCallbacks; AR_DEBUG_ASSERT(AR6K_IRQ_PROC_REGS_SIZE == 16); AR_DEBUG_ASSERT(AR6K_IRQ_ENABLE_REGS_SIZE == 4); do { A_MEMZERO(&htcCallbacks, sizeof(HTC_CALLBACKS)); /* the device layer handles these */ htcCallbacks.rwCompletionHandler = DevRWCompletionHandler; htcCallbacks.dsrHandler = DevDsrHandler; htcCallbacks.context = pDev; status = HIFAttachHTC(pDev->HIFDevice, &htcCallbacks); if (A_FAILED(status)) { break; } pDev->HifAttached = TRUE; /* initialize our free list of IO packets */ INIT_HTC_PACKET_QUEUE(&pDev->RegisterIOList); A_MUTEX_INIT(&pDev->Lock); /* get the addresses for all 4 mailboxes */ status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_ADDR, mailboxaddrs, sizeof(mailboxaddrs)); if (status != A_OK) { AR_DEBUG_ASSERT(FALSE); break; } /* carve up register I/O packets (these are for ASYNC register I/O ) */ for (i = 0; i < AR6K_MAX_REG_IO_BUFFERS; i++) { HTC_PACKET *pIOPacket; pIOPacket = &pDev->RegIOBuffers[i].HtcPacket; SET_HTC_PACKET_INFO_RX_REFILL(pIOPacket, pDev, pDev->RegIOBuffers[i].Buffer, AR6K_REG_IO_BUFFER_SIZE, 0); /* don't care */ AR6KFreeIOPacket(pDev,pIOPacket); } /* get the address of the mailbox we are using */ pDev->MailboxAddress = mailboxaddrs[HTC_MAILBOX]; /* get the block sizes */ status = HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_MBOX_BLOCK_SIZE, blocksizes, sizeof(blocksizes)); if (status != A_OK) { AR_DEBUG_ASSERT(FALSE); break; } /* note: we actually get the block size of a mailbox other than 0, for SDIO the block * size on mailbox 0 is artificially set to 1. So we use the block size that is set * for the other 3 mailboxes */ pDev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE]; /* must be a power of 2 */ AR_DEBUG_ASSERT((pDev->BlockSize & (pDev->BlockSize - 1)) == 0); /* assemble mask, used for padding to a block */ pDev->BlockMask = pDev->BlockSize - 1; AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("BlockSize: %d, MailboxAddress:0x%X \n", pDev->BlockSize, pDev->MailboxAddress)); pDev->GetPendingEventsFunc = NULL; /* see if the HIF layer implements the get pending events function */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_PENDING_EVENTS_FUNC, &pDev->GetPendingEventsFunc, sizeof(pDev->GetPendingEventsFunc)); /* assume we can process HIF interrupt events asynchronously */ pDev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC; /* see if the HIF layer overrides this assumption */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_IRQ_PROC_MODE, &pDev->HifIRQProcessingMode, sizeof(pDev->HifIRQProcessingMode)); switch (pDev->HifIRQProcessingMode) { case HIF_DEVICE_IRQ_SYNC_ONLY: AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is SYNC ONLY\n")); break; case HIF_DEVICE_IRQ_ASYNC_SYNC: AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF Interrupt processing is ASYNC and SYNC\n")); break; default: AR_DEBUG_ASSERT(FALSE); } pDev->HifMaskUmaskRecvEvent = NULL; /* see if the HIF layer implements the mask/unmask recv events function */ HIFConfigureDevice(pDev->HIFDevice, HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC, &pDev->HifMaskUmaskRecvEvent, sizeof(pDev->HifMaskUmaskRecvEvent)); AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("HIF special overrides : 0x%X , 0x%X\n", (A_UINT32)pDev->GetPendingEventsFunc, (A_UINT32)pDev->HifMaskUmaskRecvEvent)); status = DevDisableInterrupts(pDev); } while (FALSE); if (A_FAILED(status)) { if (pDev->HifAttached) { HIFDetachHTC(pDev->HIFDevice); pDev->HifAttached = FALSE; } } return status; }
A_STATUS htcTargetInsertedHandler(HIF_DEVICE *device) { HTC_TARGET *target; HTC_ENDPOINT *endPoint; A_UINT8 count1, count2; HTC_EVENT_INFO eventInfo; HTC_REG_BUFFER *regBuffer; HTC_QUEUE_ELEMENT *element; HTC_MBOX_BUFFER *mboxBuffer; HTC_REG_REQUEST_LIST *regList; HTC_DATA_REQUEST_QUEUE *sendQueue, *recvQueue; HIF_REQUEST request; A_STATUS status; A_UINT32 address; HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcTargetInserted - Enter\n"); /* Initialize the locks */ A_MUTEX_INIT(&instanceCS); A_MUTEX_INIT(&creditCS); A_MUTEX_INIT(&counterCS); A_MUTEX_INIT(&txCS); /* Allocate target memory */ if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) { HTC_DEBUG_PRINTF(ATH_LOG_ERR, "Unable to allocate memory\n"); return A_ERROR; } A_MEMZERO(target, sizeof(HTC_TARGET)); target->device = device; target->ready = FALSE; /* Initialize the endpoints, mbox queues, event table */ for (count1 = ENDPOINT1; count1 <= ENDPOINT4; count1 ++) { endPoint = &target->endPoint[count1]; HTC_DEBUG_PRINTF(ATH_LOG_INF, "endPoint[%d]: %p\n", count1, endPoint); A_MEMZERO(endPoint->txCreditsAvailable, HTC_TX_CREDITS_NUM_MAX); endPoint->txCreditsConsumed = 0; endPoint->txCreditsIntrEnable = FALSE; endPoint->rxLengthPending = 0; endPoint->target = target; endPoint->enabled = FALSE; for (count2 = 0; count2<HTC_DATA_REQUEST_RING_BUFFER_SIZE; count2 ++) { /* Send Queue */ sendQueue = &endPoint->sendQueue; sendQueue->head = sendQueue->size = 0; element = &sendQueue->element[count2]; A_MEMZERO(element, sizeof(HTC_DATA_REQUEST_ELEMENT)); element->buffer.free = TRUE; element->completionCB = htcTxCompletionCB; mboxBuffer = GET_MBOX_BUFFER(element); mboxBuffer->endPoint = endPoint; /* Receive Queue */ recvQueue = &endPoint->recvQueue; recvQueue->head = recvQueue->size = 0; element = &recvQueue->element[count2]; A_MEMZERO(element, sizeof(HTC_DATA_REQUEST_ELEMENT)); element->buffer.free = TRUE; element->completionCB = htcRxCompletionCB; mboxBuffer = GET_MBOX_BUFFER(element); mboxBuffer->endPoint = endPoint; } A_MEMZERO(&target->endPoint[count1].eventTable, sizeof(HTC_ENDPOINT_EVENT_TABLE)); } /* Populate the block size for each of the end points */ endPoint = &target->endPoint[ENDPOINT1]; endPoint->blockSize = HIF_MBOX0_BLOCK_SIZE; endPoint = &target->endPoint[ENDPOINT2]; endPoint->blockSize = HIF_MBOX1_BLOCK_SIZE; endPoint = &target->endPoint[ENDPOINT3]; endPoint->blockSize = HIF_MBOX2_BLOCK_SIZE; endPoint = &target->endPoint[ENDPOINT4]; endPoint->blockSize = HIF_MBOX3_BLOCK_SIZE; /* Initialize the shadow copy of the target register table */ A_MEMZERO(&target->table, sizeof(HTC_REGISTER_TABLE)); /* Initialize the register request list */ regList = &target->regList; for (count1 = 0; count1 < HTC_REG_REQUEST_LIST_SIZE; count1 ++) { element = ®List->element[count1]; A_MEMZERO(element, sizeof(HTC_REG_REQUEST_ELEMENT)); element->buffer.free = TRUE; element->completionCB = htcRegCompletionCB; regBuffer = GET_REG_BUFFER(element); regBuffer->target = target; } /* Add the target instance to the global list */ addTargetInstance(target); /* Disable all the dragon interrupts */ target->table.int_status_enable = 0; target->table.cpu_int_status_enable = 0; target->table.error_status_enable = 0; target->table.counter_int_status_enable = 0; HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS, HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS); address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED); status = HIFReadWrite(target->device, address, &target->table.int_status_enable, 4, &request, NULL); AR_DEBUG_ASSERT(status == A_OK); /* * Frame a TARGET_AVAILABLE event and send it to the host. Return the * HIF_DEVICE handle as a parameter with the event. */ FRAME_EVENT(eventInfo, (A_UCHAR *)device, sizeof(HIF_DEVICE *), sizeof(HIF_DEVICE *), A_OK, NULL); dispatchEvent(target, ENDPOINT_UNUSED, HTC_TARGET_AVAILABLE, &eventInfo); HTC_DEBUG_PRINTF(ATH_LOG_TRC, "htcTargetInserted - Exit\n"); return A_OK; }