From 645df9d63189968bb3884d46f6558c3e2b0c935a Mon Sep 17 00:00:00 2001 From: "ivan_p@hotbox.ru" Date: Thu, 26 Mar 2009 15:03:03 +0300 Subject: AR6000 netif_queue_stop non stop, Bug? This patch resolves the following issue: http://lists.openmoko.org/pipermail/openmoko-kernel/2009-March/009643.html Changed: prevent rescheduling network queue at interface opened/connected. Removed: wake network queue at transmit complete. Added: wake network queue at packet queue limit not reached. Signed-off-by: Ivan Petrov --- drivers/ar6000/ar6000/ar6000_drv.c | 46 +++++++++++------------ drivers/ar6000/ar6000/ar6000_drv.h | 1 - drivers/ar6000/ar6000/ar6000_raw_if.c | 1 + drivers/ar6000/htc/htc.c | 1 + drivers/ar6000/htc/htc_send.c | 70 +++++++++++++++++------------------ drivers/ar6000/include/htc_api.h | 3 ++ 6 files changed, 60 insertions(+), 62 deletions(-) (limited to 'drivers/ar6000') diff --git a/drivers/ar6000/ar6000/ar6000_drv.c b/drivers/ar6000/ar6000/ar6000_drv.c index 816557641de..cdf05d1b314 100644 --- a/drivers/ar6000/ar6000/ar6000_drv.c +++ b/drivers/ar6000/ar6000/ar6000_drv.c @@ -238,6 +238,8 @@ static void ar6000_tx_complete(void *Context, HTC_PACKET *pPacket); static void ar6000_tx_queue_full(void *Context, HTC_ENDPOINT_ID Endpoint); +static void ar6000_tx_queue_avail(void *Context, HTC_ENDPOINT_ID Endpoint); + /* * Static variables */ @@ -1149,7 +1151,7 @@ static int ar6000_open(struct net_device *dev) { /* Wake up the queues */ - netif_wake_queue(dev); + netif_start_queue(dev); return 0; } @@ -1278,6 +1280,7 @@ int ar6000_init(struct net_device *dev) connect.EpCallbacks.EpRecv = ar6000_rx; connect.EpCallbacks.EpRecvRefill = ar6000_rx_refill; connect.EpCallbacks.EpSendFull = ar6000_tx_queue_full; + connect.EpCallbacks.EpSendAvail = ar6000_tx_queue_avail; /* set the max queue depth so that our ar6000_tx_queue_full handler gets called. * Linux has the peculiarity of not providing flow control between the * NIC and the network stack. There is no API to indicate that a TX packet @@ -1753,10 +1756,10 @@ applyAPTCHeuristics(AR_SOFTC_T *ar) } #endif /* ADAPTIVE_POWER_THROUGHPUT_CONTROL */ -static void ar6000_tx_queue_full(void *Context, HTC_ENDPOINT_ID Endpoint) +static void +ar6000_tx_queue_full(void *Context, HTC_ENDPOINT_ID Endpoint) { - AR_SOFTC_T *ar = (AR_SOFTC_T *)Context; - + AR_SOFTC_T *ar = (AR_SOFTC_T *)Context; if (Endpoint == arWMIStream2EndpointID(ar,WMI_CONTROL_PRI)) { if (!bypasswmi) { @@ -1771,19 +1774,27 @@ static void ar6000_tx_queue_full(void *Context, HTC_ENDPOINT_ID Endpoint) AR_DEBUG_PRINTF("WMI Control Endpoint is FULL!!! \n"); } } else { - - AR6000_SPIN_LOCK(&ar->arLock, 0); - ar->arNetQueueStopped = TRUE; - AR6000_SPIN_UNLOCK(&ar->arLock, 0); /* one of the data endpoints queues is getting full..need to stop network stack - * the queue will resume in ar6000_tx_complete() */ + * the queue will resume after credits received */ netif_stop_queue(ar->arNetDev); } +} +static void +ar6000_tx_queue_avail(void *Context, HTC_ENDPOINT_ID Endpoint) +{ + AR_SOFTC_T *ar = (AR_SOFTC_T *)Context; + if (Endpoint == arWMIStream2EndpointID(ar,WMI_CONTROL_PRI)) { + /* FIXME: what do for it? */ + } else { + /* Wake up interface, rescheduling prevented. */ + if ((ar->arConnected == TRUE) || (bypasswmi)) { + netif_wake_queue(ar->arNetDev); + } + } } - static void ar6000_tx_complete(void *Context, HTC_PACKET *pPacket) { @@ -1877,10 +1888,6 @@ ar6000_tx_complete(void *Context, HTC_PACKET *pPacket) ar6000_free_cookie(ar, cookie); } - if (ar->arNetQueueStopped) { - ar->arNetQueueStopped = FALSE; - } - AR6000_SPIN_UNLOCK(&ar->arLock, 0); /* lock is released, we can freely call other kernel APIs */ @@ -1888,18 +1895,9 @@ ar6000_tx_complete(void *Context, HTC_PACKET *pPacket) /* this indirectly frees the HTC_PACKET */ A_NETBUF_FREE(skb); - if ((ar->arConnected == TRUE) || (bypasswmi)) { - if (status != A_ECANCELED) { - /* don't wake the queue if we are flushing, other wise it will just - * keep queueing packets, which will keep failing */ - netif_wake_queue(ar->arNetDev); - } - } - if (wakeEvent) { wake_up(&arEvent); } - } /* @@ -2317,7 +2315,7 @@ ar6000_connect_event(AR_SOFTC_T *ar, A_UINT16 channel, A_UINT8 *bssid, /* flush data queues */ ar6000_TxDataCleanup(ar); - netif_wake_queue(ar->arNetDev); + netif_start_queue(ar->arNetDev); if ((OPEN_AUTH == ar->arDot11AuthMode) && (NONE_AUTH == ar->arAuthMode) && diff --git a/drivers/ar6000/ar6000/ar6000_drv.h b/drivers/ar6000/ar6000/ar6000_drv.h index d5ff7774885..784f158d9c4 100644 --- a/drivers/ar6000/ar6000/ar6000_drv.h +++ b/drivers/ar6000/ar6000/ar6000_drv.h @@ -273,7 +273,6 @@ typedef struct ar6_softc { A_BOOL write_buffer_available[HTC_RAW_STREAM_NUM_MAX]; A_BOOL read_buffer_available[HTC_RAW_STREAM_NUM_MAX]; #endif - A_BOOL arNetQueueStopped; A_BOOL arRawIfInit; int arDeviceIndex; COMMON_CREDIT_STATE_INFO arCreditStateInfo; diff --git a/drivers/ar6000/ar6000/ar6000_raw_if.c b/drivers/ar6000/ar6000/ar6000_raw_if.c index 65402b9c8d5..4443bb26733 100644 --- a/drivers/ar6000/ar6000/ar6000_raw_if.c +++ b/drivers/ar6000/ar6000/ar6000_raw_if.c @@ -127,6 +127,7 @@ static A_STATUS ar6000_connect_raw_service(AR_SOFTC_T *ar, /* simple interface, we don't need these optional callbacks */ connect.EpCallbacks.EpRecvRefill = NULL; connect.EpCallbacks.EpSendFull = NULL; + connect.EpCallbacks.EpSendAvail = NULL; connect.MaxSendQueueDepth = RAW_HTC_WRITE_BUFFERS_NUM; /* connect to the raw streams service, we may be able to get 1 or more diff --git a/drivers/ar6000/htc/htc.c b/drivers/ar6000/htc/htc.c index b5e691b962e..63ef90bf916 100644 --- a/drivers/ar6000/htc/htc.c +++ b/drivers/ar6000/htc/htc.c @@ -284,6 +284,7 @@ A_STATUS HTCWaitTarget(HTC_HANDLE HTCHandle) connect.EpCallbacks.EpRecv = HTCControlRecv; connect.EpCallbacks.EpRecvRefill = NULL; /* not needed */ connect.EpCallbacks.EpSendFull = NULL; /* not nedded */ + connect.EpCallbacks.EpSendAvail = NULL; /* not nedded */ connect.MaxSendQueueDepth = NUM_CONTROL_BUFFERS; connect.ServiceID = HTC_CTRL_RSVD_SVC; diff --git a/drivers/ar6000/htc/htc_send.c b/drivers/ar6000/htc/htc_send.c index fd5ef6e2605..62d8bcda5e2 100644 --- a/drivers/ar6000/htc/htc_send.c +++ b/drivers/ar6000/htc/htc_send.c @@ -101,23 +101,22 @@ A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 SendFlags } /* try to send the current packet or a packet at the head of the TX queue, - * if there are no credits, the packet remains in the queue. - * this function always succeeds and returns a flag if the TX queue for - * the endpoint has hit the set limit */ -static A_BOOL HTCTrySend(HTC_TARGET *target, - HTC_ENDPOINT *pEndpoint, - HTC_PACKET *pPacketToSend) + * if there are no credits, the packet remains in the queue. */ +static void HTCTrySend(HTC_TARGET *target, + HTC_PACKET *pPacketToSend, + HTC_ENDPOINT_ID ep) { - HTC_PACKET *pPacket; - int creditsRequired; - int remainder; - A_UINT8 sendFlags; - A_BOOL epFull = FALSE; - - LOCK_HTC_TX(target); + HTC_PACKET *pPacket; + HTC_ENDPOINT *pEndpoint; + int creditsRequired; + A_UINT8 sendFlags; AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (pPkt:0x%X)\n",(A_UINT32)pPacketToSend)); + pEndpoint = &target->EndPoint[ep]; + + LOCK_HTC_TX(target); + if (pPacketToSend != NULL) { /* caller supplied us a packet to queue to the tail of the HTC TX queue before * we check the tx queue */ @@ -143,12 +142,9 @@ static A_BOOL HTCTrySend(HTC_TARGET *target, (A_UINT32)pPacket, pEndpoint->CurrentTxQueueDepth)); /* figure out how many credits this message requires */ - creditsRequired = (pPacket->ActualLength + HTC_HDR_LENGTH) / target->TargetCreditSize; - remainder = (pPacket->ActualLength + HTC_HDR_LENGTH) % target->TargetCreditSize; - - if (remainder) { - creditsRequired++; - } + creditsRequired = pPacket->ActualLength + HTC_HDR_LENGTH; + creditsRequired += target->TargetCreditSize - 1; + creditsRequired /= target->TargetCreditSize; AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d Got:%d\n", creditsRequired, pEndpoint->CreditDist.TxCredits)); @@ -212,14 +208,23 @@ static A_BOOL HTCTrySend(HTC_TARGET *target, } if (pEndpoint->CurrentTxQueueDepth >= pEndpoint->MaxTxQueueDepth) { - /* let caller know that this endpoint has reached the maximum depth */ - epFull = TRUE; + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d, TX queue is full, Depth:%d, Max:%d \n", + ep, pEndpoint->CurrentTxQueueDepth, pEndpoint->MaxTxQueueDepth)); + UNLOCK_HTC_TX(target); + /* queue is now full, let caller know */ + if (pEndpoint->EpCallBacks.EpSendFull != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Calling driver's send full callback.... \n")); + pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext, ep); + } + } else { + UNLOCK_HTC_TX(target); + /* queue is now available for new packet, let caller know */ + if (pEndpoint->EpCallBacks.EpSendAvail) { + pEndpoint->EpCallBacks.EpSendAvail(pEndpoint->EpCallBacks.pContext, ep); + } } - UNLOCK_HTC_TX(target); - AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend: \n")); - return epFull; } /* HTC API - HTCSendPkt */ @@ -251,20 +256,12 @@ A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) pPacket->Completion = HTCSendPktCompletionHandler; pPacket->pContext = target; - if (HTCTrySend(target, pEndpoint, pPacket)) { - AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Endpoint %d, TX queue is full, Depth:%d, Max:%d \n", - ep, pEndpoint->CurrentTxQueueDepth, pEndpoint->MaxTxQueueDepth)); - /* queue is now full, let caller know */ - if (pEndpoint->EpCallBacks.EpSendFull != NULL) { - AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Calling driver's send full callback.... \n")); - pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext, - ep); - } - } + HTCTrySend(target, pPacket, ep); - AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPkt \n")); } while (FALSE); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPkt \n")); + return status; } @@ -292,7 +289,7 @@ static INLINE void HTCCheckEndpointTxQueues(HTC_TARGET *target) * Highest priority queue get's processed first, if there are credits available the * highest priority queue will get a chance to reclaim credits from lower priority * ones */ - HTCTrySend(target, pEndpoint, NULL); + HTCTrySend(target, NULL, pDistItem->Endpoint); } pDistItem = pDistItem->pNext; @@ -480,7 +477,6 @@ void HTCFlushSendPkts(HTC_TARGET *target) HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL); } - } /* HTC API to flush an endpoint's TX queue*/ diff --git a/drivers/ar6000/include/htc_api.h b/drivers/ar6000/include/htc_api.h index 73b7df60ed0..e75692d7efa 100644 --- a/drivers/ar6000/include/htc_api.h +++ b/drivers/ar6000/include/htc_api.h @@ -86,6 +86,8 @@ typedef void (*HTC_EP_RECV_REFILL)(void *, HTC_ENDPOINT_ID Endpoint); * Other OSes require a "per-packet" indication_RAW_STREAM_NUM_MAX for each completed TX packet, this * closed loop mechanism will prevent the network stack from overunning the NIC */ typedef void (*HTC_EP_SEND_QUEUE_FULL)(void *, HTC_ENDPOINT_ID Endpoint); +/* Optional per service connection callback when a send queue is available for receive new packet. */ +typedef void (*HTC_EP_SEND_QUEUE_AVAIL)(void *, HTC_ENDPOINT_ID Endpoint); typedef struct _HTC_EP_CALLBACKS { void *pContext; /* context for each callback */ @@ -93,6 +95,7 @@ typedef struct _HTC_EP_CALLBACKS { HTC_EP_RECV_PKT EpRecv; /* receive callback for connected endpoint */ HTC_EP_RECV_REFILL EpRecvRefill; /* OPTIONAL receive re-fill callback for connected endpoint */ HTC_EP_SEND_QUEUE_FULL EpSendFull; /* OPTIONAL send full callback */ + HTC_EP_SEND_QUEUE_AVAIL EpSendAvail; /* OPTIONAL send available callback */ } HTC_EP_CALLBACKS; /* service connection information */ -- cgit v1.2.3