📄 htc_send.c
字号:
/* * Copyright (c) 2004-2006 Atheros Communications Inc. * * Wireless Network driver for Atheros AR6001 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * * This file contains the routines handling the transmit path. */#include "htc_internal.h"/* ------ Global Variable Declarations ------- */extern A_MUTEX_T creditCS;#ifdef DEBUGextern A_UINT32 debughtc;extern A_UINT32 txcreditsavailable[HTC_MAILBOX_NUM_MAX];extern A_UINT32 txcreditsconsumed[HTC_MAILBOX_NUM_MAX];#ifdef HTC_SYNCextern A_UINT32 txcreditintrenable[HTC_MAILBOX_NUM_MAX];extern A_UINT32 txcreditintrenableaggregate[HTC_MAILBOX_NUM_MAX];#endif#endifextern A_UINT32 tx_attempt[HTC_MAILBOX_NUM_MAX]; /* Num of attempts to add */extern A_UINT32 tx_post[HTC_MAILBOX_NUM_MAX]; /* Num of attemps succeded */extern A_UINT32 tx_complete[HTC_MAILBOX_NUM_MAX]; /* Num of tx complete *//* ------ Functions ------ */A_STATUSHTCBufferSend(HTC_TARGET *target, HTC_ENDPOINT_ID endPointId, A_UCHAR *buffer, A_UINT32 length, void *cookie){ A_STATUS status; HTC_ENDPOINT *endPoint; HTC_DATA_REQUEST_QUEUE *sendQueue; AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND, ("HTCBufferSend: Enter (endPointId: %d, buffer: 0x%p, length: %d, cookie: 0x%p)\n", endPointId, buffer, length, cookie)); AR_DEBUG_ASSERT((endPointId >= ENDPOINT1) && (endPointId <= ENDPOINT4)); AR_DEBUG_ASSERT(length); /* Extract the end point instance */ endPoint = &target->endPoint[endPointId]; AR_DEBUG_ASSERT(endPoint != NULL); sendQueue = &endPoint->sendQueue; AR_DEBUG_ASSERT(sendQueue != NULL); AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND, ("mboxQueue: %p\n", sendQueue)); /* * Add this posted buffer to the pending send queue. We need to allocate * a bufferElement to store the packet information and we borrow that * buffer from the pending send queue. If circumstances allow us to * transmit it right away then we dequeue it otherwise we let it remain * to be picked in the interrupt handler context. */ tx_attempt[endPointId] += 1; if (!endPoint->enabled) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Endpoint not enabled: %d\n", GET_ENDPOINT_ID(endPoint))); AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("tx_attempt[%d] = %d, tx_post[%d] = %d, tx_complete[%d] = %d\n", endPointId, tx_attempt[endPointId], endPointId, tx_post[endPointId], endPointId, tx_complete[endPointId])); return A_ERROR; } status = addToMboxQueue(sendQueue, buffer, length, 0, cookie); if (status != A_OK) { AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_SEND, ("Mailbox (%d) PSQ full. Unable to add buffer\n", endPointId)); AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("tx_attempt[%d] = %d, tx_post[%d] = %d, tx_complete[%d] = %d\n", endPointId, tx_attempt[endPointId], endPointId, tx_post[endPointId], endPointId, tx_complete[endPointId])); return A_ERROR; } tx_post[endPointId] += 1; /* * The frame shall be dequeued and sent if there are any credits * available. */ htcSendFrame(endPoint); AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND, ("HTCBufferSend: Exit\n")); return A_OK;}voidhtcSendFrame(HTC_ENDPOINT *endPoint){ A_STATUS status; A_UINT32 address; HIF_DATAMODE dmode; HTC_TARGET *target; HIF_REQUEST request; A_UINT32 frameLength; A_UINT32 paddedLength; HTC_EVENT_INFO eventInfo; A_UINT8 txCreditsConsumed; A_UINT8 txCreditsAvailable; HTC_ENDPOINT_ID endPointId; HTC_QUEUE_ELEMENT *element; HTC_MBOX_BUFFER *mboxBuffer; HTC_REG_REQUEST_LIST *regList; HTC_DATA_REQUEST_QUEUE *sendQueue;#ifdef HTC_SYNC HTC_REG_BUFFER *regBuffer;#endif AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND, ("htcSendFrame - Enter\n")); /* Get the context */ AR_DEBUG_ASSERT(endPoint != NULL); endPointId = GET_ENDPOINT_ID(endPoint); target = endPoint->target; AR_DEBUG_ASSERT(target != NULL); sendQueue = &endPoint->sendQueue; AR_DEBUG_ASSERT(sendQueue != NULL); regList = &target->regList; AR_DEBUG_ASSERT(regList != NULL); /* * Transmit the frames as long as we have the credits available and * the queue is not out of them */ AR_DEBUG_PRINTF(ATH_DEBUG_SYNC, ("Critical Section (credit): LOCK at line %d in file %s\n", __LINE__, __FILE__)); A_MUTEX_LOCK(&creditCS); txCreditsAvailable = GET_TX_CREDITS_AVAILABLE(endPoint); txCreditsConsumed = GET_TX_CREDITS_CONSUMED(endPoint); SET_TX_CREDITS_AVAILABLE(endPoint, 0); SET_TX_CREDITS_CONSUMED(endPoint, txCreditsConsumed + txCreditsAvailable); AR_DEBUG_PRINTF(ATH_DEBUG_SYNC, ("Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__)); A_MUTEX_UNLOCK(&creditCS); /* * Send the packet only when there are packets to be sent and there * are positive number of credits available. */ while((!IS_DATA_QUEUE_EMPTY(sendQueue)) && txCreditsAvailable) { /* Get the request buffer from the Pending Send Queue */ element = removeFromMboxQueue(sendQueue); mboxBuffer = GET_MBOX_BUFFER(element); /* * Prepend the actual length in the first 2 bytes of the outgoing * packet. */ mboxBuffer->buffer -= HTC_HEADER_LEN; A_MEMCPY(mboxBuffer->buffer, &mboxBuffer->bufferLength, HTC_HEADER_LEN); /* * Adjust the length in the block mode only when its not an integral * multiple of the block size. Assumption is that the block size is * a power of 2. */ frameLength = mboxBuffer->bufferLength + HTC_HEADER_LEN; paddedLength = (frameLength + (endPoint->blockSize - 1)) & (~(endPoint->blockSize - 1)); mboxBuffer->actualLength = paddedLength; AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND, ("Original frame length: %d, Padded frame length: %d\n", frameLength, paddedLength)); AR_DEBUG_PRINTBUF(mboxBuffer->buffer, mboxBuffer->actualLength); AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND, ("Available Tx credits: %d\n", txCreditsAvailable)); /* Frame the interface request */ dmode = (endPoint->blockSize > 1) ? HIF_BLOCK_BASIS : HIF_BYTE_BASIS; HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_ASYNCHRONOUS, dmode, HIF_INCREMENTAL_ADDRESS); address = endPoint->address; /* Send the data to the bus driver */ status = HIFReadWrite(target->device, address, mboxBuffer->buffer, mboxBuffer->actualLength, &request, element);#ifndef HTC_SYNC if (status != A_OK) {#else if (status != A_OK && status != A_PENDING) {#endif AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_SEND, ("Frame transmission failed\n")); AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_SEND, ("EndPoint: %d, Tx credits available: %d\n", endPointId, GET_TX_CREDITS_AVAILABLE(endPoint))); /* * We need to check just in case the callback routine was called * with the error status before we reach this point and in that * context we fee up the buffer so its just a conservative design. */ if (!IS_ELEMENT_FREE(element)) { mboxBuffer->buffer += HTC_HEADER_LEN; FRAME_EVENT(eventInfo, mboxBuffer->buffer, mboxBuffer->bufferLength, mboxBuffer->actualLength, A_ECANCELED, mboxBuffer->cookie); RECYCLE_DATA_REQUEST_ELEMENT(element); dispatchEvent(target, endPointId, HTC_BUFFER_SENT, &eventInfo); } AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND, ("htcSendFrame - Exit\n")); return; }#ifdef HTC_SYNC else if (status == A_OK) { element->completionCB(element, status); }#endif txCreditsAvailable -= 1; txCreditsConsumed += 1;#ifdef DEBUG txcreditsavailable[endPointId] = txCreditsAvailable; txcreditsconsumed[endPointId] = txCreditsConsumed;#endif /* DEBUG */ if (!txCreditsAvailable) { AR_DEBUG_ASSERT(txCreditsConsumed); /* * Instead of taking an interrupt we can just poll for more * credits that might have been queued up by now. */ HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_ASYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(TX_CREDIT_COUNTER_DECREMENT_REG, endPointId); element = allocateRegRequestElement(target); AR_DEBUG_ASSERT(element != NULL); FILL_REG_BUFFER(element, &endPoint->txCreditsAvailable[1], txCreditsConsumed, TX_CREDIT_COUNTER_DECREMENT_REG, endPointId); status = HIFReadWrite(target->device, address, &endPoint->txCreditsAvailable[1], txCreditsConsumed, &request, element);#ifndef HTC_SYNC AR_DEBUG_ASSERT(status == A_OK); AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND, ("htcSendFrame - Exit\n")); return;#else AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING); if ( status == A_OK ) { AR_DEBUG_PRINTF(ATH_DEBUG_SYNC, ("Critical Section (credit): LOCK at line %d in file %s \n", __LINE__, __FILE__)); A_MUTEX_LOCK(&creditCS); regBuffer = GET_REG_BUFFER(element); /* Calculate the number of credits available */ AR_DEBUG_ASSERT(GET_TX_CREDITS_CONSUMED(endPoint) == \ regBuffer->length); 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); AR_DEBUG_PRINTF(ATH_DEBUG_SYNC, ("Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__)); A_MUTEX_UNLOCK(&creditCS); AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND, ("Pulling %d tx credits from the target\n", txCreditsAvailable)); #ifdef DEBUG txcreditsavailable[endPointId] = txCreditsAvailable; txcreditsconsumed[endPointId] = txCreditsConsumed; #endif /* DEBUG */ freeRegRequestElement(element); if (!txCreditsAvailable) { /* Enable the Tx credit counter interrupt so that we can get * the credits posted by the target */ htcEnableCreditCounterInterrupt(target, endPointId); /* Counter Interrupts have been enabled if * txCreditsAvailable is still 0 after polling. We need to * return here as there is nothing we can send till we get * a Counter Interrupt. */ return; } }#endif } } AR_DEBUG_PRINTF(ATH_DEBUG_SYNC, ("Critical Section (credit): LOCK at line %d in file %s\n", __LINE__, __FILE__)); A_MUTEX_LOCK(&creditCS); SET_TX_CREDITS_AVAILABLE(endPoint, txCreditsAvailable); SET_TX_CREDITS_CONSUMED(endPoint, txCreditsConsumed); AR_DEBUG_PRINTF(ATH_DEBUG_SYNC, ("Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__)); A_MUTEX_UNLOCK(&creditCS); AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND, ("htcSendFrame - Exit\n"));}voidhtcSendBlkSize(HTC_ENDPOINT *endPoint){ A_STATUS status; A_UINT32 address; HTC_TARGET *target; HIF_REQUEST request; HTC_ENDPOINT_ID endPointId; HTC_QUEUE_ELEMENT *element; HTC_MBOX_BUFFER *mboxBuffer; HTC_DATA_REQUEST_QUEUE *sendQueue; HTC_REG_REQUEST_LIST *regList; /* Get the context */ AR_DEBUG_ASSERT(endPoint != NULL); target = endPoint->target; AR_DEBUG_ASSERT(target != NULL); regList = &target->regList; AR_DEBUG_ASSERT(regList != NULL); sendQueue = &endPoint->sendQueue; AR_DEBUG_ASSERT(sendQueue != NULL); endPointId = GET_ENDPOINT_ID(endPoint); /* Decrement the tx credit count */ AR_DEBUG_ASSERT(endPoint->txCreditsConsumed == 0); endPoint->txCreditsConsumed = 1; HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_ASYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS); address = getRegAddr(TX_CREDIT_COUNTER_DECREMENT_REG, endPointId); element = allocateRegRequestElement(target); AR_DEBUG_ASSERT(element != NULL); FILL_REG_BUFFER(element, &endPoint->txCreditsAvailable[1], endPoint->txCreditsConsumed, TX_CREDIT_COUNTER_DECREMENT_REG, endPointId); status = HIFReadWrite(target->device, address, &endPoint->txCreditsAvailable[1], endPoint->txCreditsConsumed, &request, element);#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 /* Negotiate the maximum block size for the endpoint */ addToMboxQueue(sendQueue, (A_UCHAR *)&endPoint->blockSize, sizeof(endPoint->blockSize), sizeof(endPoint->blockSize), NULL); element = removeFromMboxQueue(sendQueue); element->completionCB = htcBlkSzNegCompletionCB; mboxBuffer = GET_MBOX_BUFFER(element); HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_ASYNCHRONOUS, HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS); address = endPoint->address; status = HIFReadWrite(target->device, address, mboxBuffer->buffer, mboxBuffer->bufferLength, &request, element);#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 AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND, ("Mailbox(%d), Block size: %d\n", endPointId, endPoint->blockSize));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -