www.pudn.com > CEWifiDriverAR6000-21374.zip > htc_send.c


//------------------------------------------------------------------------------ 
//  
//    Copyright (c) 2006 Microsoft Corporation.  All rights reserved. 
//    Copyright (c) 2006 Atheros Corporation.  All rights reserved. 
// 
//    The use and distribution terms for this software are covered by the 
//    Microsoft Limited Permissive License (Ms-LPL)  
//    http://www.microsoft.com/resources/sharedsource/licensingbasics/limitedpermissivelicense.mspx  
//    which can be found in the file MS-LPL.txt at the root of this distribution. 
//    By using this software in any fashion, you are agreeing to be bound by 
//    the terms of this license. 
// 
//    The software is licensed “as-is.”  
//    You must not remove this notice, or any other, from this software. 
//  
//  
//  
//    Windows CE Wifi Driver for AR-6000 
//  
//------------------------------------------------------------------------------ 
//============================================================================== 
// This file contains the routines handling the transmit path. 
// 
// Author(s): ="Atheros" 
//============================================================================== 
 
 
#include "htc_internal.h" 
 
/* ------ Global Variable Declarations ------- */ 
extern A_MUTEX_T creditCS,txCS; 
 
#ifdef DEBUG 
extern A_UINT32 debughtc; 
extern A_UINT32 txcreditsavailable[HTC_MAILBOX_NUM_MAX]; 
extern A_UINT32 txcreditsconsumed[HTC_MAILBOX_NUM_MAX]; 
#ifdef HTC_SYNC 
extern A_UINT32 txcreditintrenable[HTC_MAILBOX_NUM_MAX]; 
extern A_UINT32 txcreditintrenableaggregate[HTC_MAILBOX_NUM_MAX]; 
#endif 
#endif 
 
extern 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 */ 
 
void htcSendFrameLocked(HTC_ENDPOINT *endPoint); 
 
/* ------ Functions ------ */ 
A_STATUS  
HTCBufferSend(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; 
 
    HTC_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_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); 
    HTC_DEBUG_PRINTF(ATH_LOG_INF | ATH_LOG_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) { 
        HTC_DEBUG_PRINTF(ATH_LOG_ERR | ATH_LOG_SEND, "Endpoint not enabled: %d\n",  
                                        GET_ENDPOINT_ID(endPoint)); 
        HTC_DEBUG_PRINTF(ATH_LOG_ERR | ATH_LOG_SEND,  
                        "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) { 
        HTC_DEBUG_PRINTF(ATH_LOG_ERR | ATH_LOG_SEND, 
                        "Mailbox (%d) PSQ full. Unable to add buffer\n",  
                         endPointId); 
        HTC_DEBUG_PRINTF(ATH_LOG_ERR | ATH_LOG_SEND,  
                        "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); 
 
    HTC_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_SEND, "HTCBufferSend: Exit\n"); 
    return A_OK; 
} 
 
void 
htcSendFrame(HTC_ENDPOINT *endPoint)  
{ 
	A_MUTEX_LOCK(&txCS);	 
	htcSendFrameLocked(endPoint); 
	A_MUTEX_UNLOCK(&txCS); 
} 
 
void  
htcSendFrameLocked(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; 
#ifdef ONLY_16BIT 
    A_UINT16 txCreditsConsumed; 
    A_UINT16 txCreditsAvailable; 
#else 
    A_UINT8 txCreditsConsumed; 
    A_UINT8 txCreditsAvailable; 
#endif 
    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 
 
    HTC_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_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  
     */ 
    HTC_DEBUG_PRINTF(ATH_LOG_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); 
    HTC_DEBUG_PRINTF(ATH_LOG_SYNC, 
                    "Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__); 
    A_MUTEX_UNLOCK(&creditCS); 
 
    if (!txCreditsAvailable) { 
        return; 
    } 
 
    /*  
     * 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; 
        HTC_DEBUG_PRINTF(ATH_LOG_INF | ATH_LOG_SEND,   
                        "Original frame length: %d, Padded frame length: %d\n", frameLength, paddedLength); 
 
        HTC_DEBUG_PRINTBUF(mboxBuffer->buffer, (A_UINT16)mboxBuffer->actualLength); 
        HTC_DEBUG_PRINTF(ATH_LOG_INF | ATH_LOG_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 = HIF_MBOX_START_ADDR(endPointId); 
 
        /* 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 
 
            HTC_DEBUG_PRINTF(ATH_LOG_ERR | ATH_LOG_SEND,  
                            "Frame transmission failed\n"); 
            HTC_DEBUG_PRINTF(ATH_LOG_ERR | ATH_LOG_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); 
            } 
            HTC_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_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); 
#ifdef ONLY_16BIT 
            FILL_REG_BUFFER(element, &endPoint->txCreditsAvailable[1],  
                            txCreditsConsumed*2, TX_CREDIT_COUNTER_DECREMENT_REG, 
                            endPointId); 
            status = HIFReadWrite(target->device, address,  
                                  (A_UCHAR *)&endPoint->txCreditsAvailable[1], 
                                  txCreditsConsumed*2, &request, element); 
#else 
            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); 
#endif 
#ifndef HTC_SYNC 
            AR_DEBUG_ASSERT(status == A_OK); 
            HTC_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_SEND,  
                            "htcSendFrame - Exit\n"); 
            return; 
#else 
            AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING); 
			if ( status == A_OK ) { 
 
				HTC_DEBUG_PRINTF(ATH_LOG_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 */ 
#ifdef ONLY_16BIT 
        		AR_DEBUG_ASSERT((GET_TX_CREDITS_CONSUMED(endPoint) * 2) == \ 
					regBuffer->length); 
#else 
        		AR_DEBUG_ASSERT(GET_TX_CREDITS_CONSUMED(endPoint) == \ 
					regBuffer->length); 
#endif 
        		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); 
        		SET_TX_CREDITS_AVAILABLE(endPoint, 0); 
    			SET_TX_CREDITS_CONSUMED(endPoint, txCreditsConsumed + txCreditsAvailable); 
        		HTC_DEBUG_PRINTF(ATH_LOG_SYNC, 
                        "Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__); 
        		A_MUTEX_UNLOCK(&creditCS); 
 
        		HTC_DEBUG_PRINTF(ATH_LOG_INF | ATH_LOG_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 
        } 
    } 
 
    HTC_DEBUG_PRINTF(ATH_LOG_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); 
    HTC_DEBUG_PRINTF(ATH_LOG_SYNC, 
                    "Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__); 
    A_MUTEX_UNLOCK(&creditCS); 
 
    HTC_DEBUG_PRINTF(ATH_LOG_TRC | ATH_LOG_SEND, "htcSendFrame - Exit\n"); 
} 
 
void 
htcSendBlkSize(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); 
#ifdef ONLY_16BIT 
    FILL_REG_BUFFER(element, &endPoint->txCreditsAvailable[1], 
                    endPoint->txCreditsConsumed*2, 
                    TX_CREDIT_COUNTER_DECREMENT_REG, endPointId); 
    status = HIFReadWrite(target->device, address,  
                          (A_UCHAR *)&endPoint->txCreditsAvailable[1],  
                          endPoint->txCreditsConsumed*2, &request, element); 
#else 
    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); 
#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 
 
    /* 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 = HIF_MBOX_START_ADDR(endPointId); 
    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 
 
    HTC_DEBUG_PRINTF(ATH_LOG_INF | ATH_LOG_SEND ,  
                    "Mailbox(%d), Block size: %d\n",  
                    endPointId, endPoint->blockSize); 
}