[PATCH] Get rid of transmit queue
Marcelo Tosatti
marcelo at kvack.org
Wed Jun 7 19:27:22 EDT 2006
Hi,
Marvell's driver has a transmit queue, buffering operations between
start_xmit and the chip.
This is scheme is flawed, though, as there is only one placeholder for
data in-flight via USB bus - the code queues multiple USB Request Block
requests without waiting for the previous one to complete, potentially
thrashing the contents of the single placeholder.
It is possible to queue several URB's to the host controller for
increased throughput, might be interesting to try that later. There is
no need to use a thread for doing the parallel submission work.
So remove it and do direct transfers from start_xmit. The queue is
restarted after the USB tx callback is receive.
Needs testing.
Signed-off-by: Marcelo Tosatti <marcelo at kvack.org>
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 6b61be4..93a60d1 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -146,6 +146,7 @@ static void if_usb_write_bulk_callback(s
PRINTM(INFO, "URB status is successfull\n");
PRINTM(INFO, "Actual length transmitted %d\n", urb->actual_length);
priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+ os_start_queue(priv);
}
if (!cardp->IsFWDnld) {
diff --git a/drivers/net/wireless/libertas/os_macros.h b/drivers/net/wireless/libertas/os_macros.h
index 54695f5..eaa878f 100644
--- a/drivers/net/wireless/libertas/os_macros.h
+++ b/drivers/net/wireless/libertas/os_macros.h
@@ -64,21 +64,6 @@ #define IPFIELD_ALIGN_OFFSET 2
return 0;
}
-static inline void os_free_tx_packet(wlan_private *priv)
-{
- ulong flags;
-
- spin_lock_irqsave(&priv->adapter->CurrentTxLock, flags);
-
- if (priv->adapter->CurrentTxSkb) {
- kfree_skb(priv->adapter->CurrentTxSkb);
- }
-
- priv->adapter->CurrentTxSkb = NULL;
-
- spin_unlock_irqrestore(&priv->adapter->CurrentTxLock, flags);
-}
-
/* netif carrier_on/off and start(wake)/stop_queue handling
carrier_on carrier_off start_queue stop_queue
open x(connect) x(disconnect) x
diff --git a/drivers/net/wireless/libertas/wlan_cmdresp.c b/drivers/net/wireless/libertas/wlan_cmdresp.c
index 94711ac..dc38a6f 100644
--- a/drivers/net/wireless/libertas/wlan_cmdresp.c
+++ b/drivers/net/wireless/libertas/wlan_cmdresp.c
@@ -84,7 +84,8 @@ void MacEventDisconnected(wlan_private *
SIOCGIWAP, &wrqu, NULL);
/* Free Tx and Rx packets */
- os_free_tx_packet(priv);
+ kfree_skb(priv->adapter->CurrentTxSkb);
+ priv->adapter->CurrentTxSkb = NULL;
wlan_send_rxskbQ(priv);
/* report disconnect to upper layer */
@@ -110,8 +111,6 @@ void MacEventDisconnected(wlan_private *
/* reset internal flags */
Adapter->AdHocCreated = FALSE;
- cleanup_txqueues(priv);
-
Adapter->SecInfo.WPAEnabled = FALSE;
Adapter->SecInfo.WPA2Enabled = FALSE;
Adapter->Wpa_ie_len = 0;
diff --git a/drivers/net/wireless/libertas/wlan_decl.h b/drivers/net/wireless/libertas/wlan_decl.h
index ed0368d..d936906 100644
--- a/drivers/net/wireless/libertas/wlan_decl.h
+++ b/drivers/net/wireless/libertas/wlan_decl.h
@@ -80,7 +80,7 @@ void wlan_proc_remove(wlan_private *priv
void wlan_debug_entry(wlan_private *priv, struct net_device *dev);
void wlan_debug_remove(wlan_private *priv);
int wlan_process_rx_command(wlan_private * priv);
-void wlan_process_tx(wlan_private * priv);
+int wlan_process_tx(wlan_private * priv, struct sk_buff *skb);
void CleanupAndInsertCmd(wlan_private * priv, struct CmdCtrlNode * pTempCmd);
void MrvDrvCommandTimerFunction(void *FunctionContext);
@@ -114,8 +114,5 @@ #if WIRELESS_EXT > 14
void send_iwevcustom_event(wlan_private *priv, s8 *str);
#endif
-void cleanup_txqueues(wlan_private *priv);
-void wlan_process_txqueue(wlan_private * priv);
-
#endif /* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/wlan_dev.h b/drivers/net/wireless/libertas/wlan_dev.h
index 0f8d124..38c96b1 100644
--- a/drivers/net/wireless/libertas/wlan_dev.h
+++ b/drivers/net/wireless/libertas/wlan_dev.h
@@ -303,8 +303,6 @@ #endif /* REASSOCIATION */
spinlock_t TxSpinLock;
struct sk_buff *CurrentTxSkb;
struct sk_buff RxSkbQ;
- struct sk_buff TxSkbQ;
- u32 TxSkbNum;
u16 TxLockFlag;
u16 gen_null_pkg;
spinlock_t CurrentTxLock;
diff --git a/drivers/net/wireless/libertas/wlan_fw.c b/drivers/net/wireless/libertas/wlan_fw.c
index 53e4794..356b6ac 100644
--- a/drivers/net/wireless/libertas/wlan_fw.c
+++ b/drivers/net/wireless/libertas/wlan_fw.c
@@ -301,10 +301,6 @@ #define SHORT_PREAMBLE_ALLOWED 1
Adapter->IntCounter = Adapter->IntCounterSaved = 0;
INIT_LIST_HEAD((struct list_head *)&Adapter->RxSkbQ);
- INIT_LIST_HEAD((struct list_head *)&Adapter->TxSkbQ);
- Adapter->TxSkbNum = 0;
-
-
Adapter->EncryptionStatus = Wlan802_11WEPDisabled;
spin_lock_init(&Adapter->CurrentTxLock);
diff --git a/drivers/net/wireless/libertas/wlan_main.c b/drivers/net/wireless/libertas/wlan_main.c
index 97e0466..41ef1df 100644
--- a/drivers/net/wireless/libertas/wlan_main.c
+++ b/drivers/net/wireless/libertas/wlan_main.c
@@ -415,27 +415,20 @@ #endif /* ENABLE_PM */
*/
static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- int ret;
+ int ret = 0;
wlan_private *priv = dev->priv;
ENTER();
-
+ os_stop_queue(priv);
- if (wlan_tx_packet(priv, skb)) {
- /* Transmit failed */
- ret = WLAN_STATUS_FAILURE;
+ if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) {
+ priv->stats.tx_dropped++;
goto done;
- } else {
- /* Transmit succeeded */
- if(priv->adapter->TxSkbNum >= MAX_NUM_IN_TX_Q)
- {
- UpdateTransStart(dev);
- os_stop_queue(priv);
- }
}
-
- ret = WLAN_STATUS_SUCCESS;
+
+ if (wlan_process_tx(priv, skb) == 0)
+ UpdateTransStart(dev);
done:
LEAVE();
@@ -671,7 +664,6 @@ static int wlan_service_main_thread(void
) ||
(
!Adapter->IntCounter
- && (priv->wlan_dev.dnld_sent || !Adapter->TxSkbNum )
&& (priv->wlan_dev.dnld_sent || Adapter->CurCmd ||
list_empty(&Adapter->CmdPendingQ))
)
@@ -801,11 +793,6 @@ static int wlan_service_main_thread(void
ExecuteNextCommand(priv);
}
-
- if(!priv->wlan_dev.dnld_sent && (Adapter->TxLockFlag == 0)
- && !list_empty((struct list_head *)&priv->adapter->TxSkbQ)){
- wlan_process_txqueue(priv);
- }
}
wlan_deactivate_thread(thread);
@@ -1026,7 +1013,6 @@ #endif
/* Flush all the packets upto the OS before stopping */
wlan_send_rxskbQ(priv);
- cleanup_txqueues(priv);
os_stop_queue(priv);
os_carrier_off(priv);
@@ -1070,55 +1056,6 @@ #endif
return WLAN_STATUS_SUCCESS;
}
-/********************************************************
- Global Functions
-********************************************************/
-/**
- * @brief Cleanup TX queue
- * @param priv pointer to wlan_private
- * @return N/A
-*/
-void cleanup_txqueues(wlan_private *priv)
-{
- struct sk_buff *delNode, *Q;
-
- Q = &priv->adapter->TxSkbQ;
- while (!list_empty((struct list_head *)Q)) {
- delNode = Q->next;
- list_del((struct list_head *)delNode);
- kfree_skb(delNode);
- }
- priv->adapter->TxSkbNum = 0;
-}
-
-
-/**
- * @brief handle TX Queue
- * @param priv pointer to wlan_private
- * @return N/A
-*/
-void wlan_process_txqueue(wlan_private * priv)
-{
- wlan_adapter *Adapter = priv->adapter;
- ulong flags;
- struct sk_buff *Q;
- ENTER();
- spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
- if(Adapter->TxSkbNum > 0){
- Q = &priv->adapter->TxSkbQ;
- Adapter->CurrentTxSkb = Q->next;
- list_del((struct list_head *) Adapter->CurrentTxSkb);
- Adapter->TxSkbNum --;
- }
- spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
- if (Adapter->CurrentTxSkb) {
- wlan_process_tx(priv);
- }
-
- LEAVE();
-}
-
-
/**
* @brief This function sends the rx packets to the os from the skb queue
*
diff --git a/drivers/net/wireless/libertas/wlan_tx.c b/drivers/net/wireless/libertas/wlan_tx.c
index 5423ebe..704d947 100644
--- a/drivers/net/wireless/libertas/wlan_tx.c
+++ b/drivers/net/wireless/libertas/wlan_tx.c
@@ -172,15 +172,14 @@ done:
if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
/* Keep the skb to echo it back once Tx feedback is
received from FW */
- skb_orphan(priv->adapter->CurrentTxSkb);
+ skb_orphan(skb);
/* stop processing outgoing pkts */
os_stop_queue(priv);
/* freeze any packets already in our queues */
priv->adapter->TxLockFlag = 1;
- } else
- {
- os_free_tx_packet(priv);
- os_start_queue(priv);
+ } else {
+ dev_kfree_skb_any(skb);
+ priv->adapter->CurrentTxSkb = NULL;
}
LEAVE();
@@ -198,12 +197,14 @@ done:
* @param priv A pointer to wlan_private structure
* @return n/a
*/
-void wlan_process_tx(wlan_private *priv)
+int wlan_process_tx(wlan_private *priv, struct sk_buff *skb)
{
unsigned long flags;
- wlan_adapter *Adapter = priv->adapter;
+ int ret = WLAN_STATUS_FAILURE;
ENTER();
+
+ HEXDUMP("TX Data", skb->data, MIN(skb->len, 100));
if(priv->wlan_dev.dnld_sent) {
PRINTM(MSG, "TX Error: dnld_sent = %d, not sending\n",
@@ -211,8 +212,9 @@ void wlan_process_tx(wlan_private *priv)
goto done;
}
+ priv->adapter->CurrentTxSkb = skb;
- SendSinglePacket(priv, Adapter->CurrentTxSkb);
+ ret = SendSinglePacket(priv, skb);
spin_lock_irqsave(&driver_lock, flags);
priv->adapter->HisRegCpy &= ~HIS_TxDnLdRdy;
@@ -220,41 +222,9 @@ void wlan_process_tx(wlan_private *priv)
done:
LEAVE();
-}
-
-/**
- * @brief This function queues the packet received from
- * kernel/upper layer and wake up the main thread to handle it.
- *
- * @param priv A pointer to wlan_private structure
- * @param skb A pointer to skb which includes TX packet
- * @return WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
- */
-int wlan_tx_packet(wlan_private *priv, struct sk_buff *skb)
-{
- ulong flags;
- wlan_adapter *Adapter = priv->adapter;
- int ret = WLAN_STATUS_SUCCESS;
-
- ENTER();
-
- HEXDUMP("TX Data", skb->data, MIN(skb->len, 100));
-
- spin_lock_irqsave(&Adapter->CurrentTxLock, flags);
-
- {
- Adapter->TxSkbNum ++;
- list_add_tail((struct list_head *) skb,(struct list_head *) &priv->adapter->TxSkbQ);
- wake_up_interruptible(&priv->MainThread.waitQ);
- }
- spin_unlock_irqrestore(&Adapter->CurrentTxLock, flags);
-
- LEAVE();
-
return ret;
}
-
/**
* @brief This function tells firmware to send a NULL data packet.
*
More information about the libertas-dev
mailing list