linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 4/7] ath9k_htc: Simplify RX URB management
@ 2010-03-29 10:37 Sujith
  0 siblings, 0 replies; only message in thread
From: Sujith @ 2010-03-29 10:37 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This patch introduces the usage of URB anchors,
thus reducing a large amount of code dealing with
URB maintenance within the driver. The RX callback now
takes care of freeing the SKB associated with each URB.

Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c |  125 +++++++++++------------------
 drivers/net/wireless/ath/ath9k/hif_usb.h |    7 +-
 2 files changed, 50 insertions(+), 82 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index fc4f6e8..e584a29 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -299,6 +299,8 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
 		ret = hif_usb_send_regout(hif_dev, skb);
 		break;
 	default:
+		dev_err(&hif_dev->udev->dev,
+			"ath9k_htc: Invalid TX pipe: %d\n", pipe_id);
 		ret = -EINVAL;
 		break;
 	}
@@ -408,14 +410,11 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
 			}
 		} else {
 			RX_STAT_INC(skb_dropped);
-			dev_kfree_skb_any(skb);
 			return;
 		}
 	}
 
 err:
-	dev_kfree_skb_any(skb);
-
 	for (i = 0; i < pool_index; i++) {
 		ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i],
 				 skb_pool[i]->len, USB_WLAN_RX_PIPE);
@@ -426,11 +425,13 @@ err:
 static void ath9k_hif_usb_rx_cb(struct urb *urb)
 {
 	struct sk_buff *skb = (struct sk_buff *) urb->context;
-	struct sk_buff *nskb;
 	struct hif_device_usb *hif_dev = (struct hif_device_usb *)
 		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 	int ret;
 
+	if (!skb)
+		return;
+
 	if (!hif_dev)
 		goto free;
 
@@ -448,34 +449,19 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
 
 	if (likely(urb->actual_length != 0)) {
 		skb_put(skb, urb->actual_length);
-
-		nskb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_ATOMIC);
-		if (!nskb)
-			goto resubmit;
-
-		usb_fill_bulk_urb(urb, hif_dev->udev,
-				  usb_rcvbulkpipe(hif_dev->udev,
-						  USB_WLAN_RX_PIPE),
-				  nskb->data, MAX_RX_BUF_SIZE,
-				  ath9k_hif_usb_rx_cb, nskb);
-
-		ret = usb_submit_urb(urb, GFP_ATOMIC);
-		if (ret) {
-			dev_kfree_skb_any(nskb);
-			goto free;
-		}
-
 		ath9k_hif_usb_rx_stream(hif_dev, skb);
-		return;
 	}
 
 resubmit:
 	skb_reset_tail_pointer(skb);
 	skb_trim(skb, 0);
 
+	usb_anchor_urb(urb, &hif_dev->rx_submitted);
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret)
+	if (ret) {
+		usb_unanchor_urb(urb);
 		goto free;
+	}
 
 	return;
 free:
@@ -490,6 +476,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 		usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 	int ret;
 
+	if (!skb)
+		return;
+
 	if (!hif_dev)
 		goto free;
 
@@ -540,6 +529,7 @@ resubmit:
 	return;
 free:
 	dev_kfree_skb_any(skb);
+	urb->context = NULL;
 }
 
 static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
@@ -609,78 +599,59 @@ err:
 	return -ENOMEM;
 }
 
-static void ath9k_hif_usb_dealloc_rx_skbs(struct hif_device_usb *hif_dev)
-{
-	int i;
-
-	for (i = 0; i < MAX_RX_URB_NUM; i++) {
-		if (hif_dev->wlan_rx_data_urb[i]) {
-			if (hif_dev->wlan_rx_data_urb[i]->transfer_buffer)
-				dev_kfree_skb_any((void *)
-					  hif_dev->wlan_rx_data_urb[i]->context);
-		}
-	}
-}
-
 static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev)
 {
-	int i;
-
-	for (i = 0; i < MAX_RX_URB_NUM; i++) {
-		if (hif_dev->wlan_rx_data_urb[i]) {
-			usb_kill_urb(hif_dev->wlan_rx_data_urb[i]);
-			usb_free_urb(hif_dev->wlan_rx_data_urb[i]);
-			hif_dev->wlan_rx_data_urb[i] = NULL;
-		}
-	}
-}
-
-static int ath9k_hif_usb_prep_rx_urb(struct hif_device_usb *hif_dev,
-				     struct urb *urb)
-{
-	struct sk_buff *skb;
-
-	skb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL);
-	if (!skb)
-		return -ENOMEM;
-
-	usb_fill_bulk_urb(urb, hif_dev->udev,
-			  usb_rcvbulkpipe(hif_dev->udev, USB_WLAN_RX_PIPE),
-			  skb->data, MAX_RX_BUF_SIZE,
-			  ath9k_hif_usb_rx_cb, skb);
-	return 0;
+	usb_kill_anchored_urbs(&hif_dev->rx_submitted);
 }
 
 static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
 {
+	struct urb *urb = NULL;
+	struct sk_buff *skb = NULL;
 	int i, ret;
 
+	init_usb_anchor(&hif_dev->rx_submitted);
+
 	for (i = 0; i < MAX_RX_URB_NUM; i++) {
 
 		/* Allocate URB */
-		hif_dev->wlan_rx_data_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
-		if (hif_dev->wlan_rx_data_urb[i] == NULL) {
+		urb = usb_alloc_urb(0, GFP_KERNEL);
+		if (urb == NULL) {
 			ret = -ENOMEM;
-			goto err_rx_urb;
+			goto err_urb;
 		}
 
 		/* Allocate buffer */
-		ret = ath9k_hif_usb_prep_rx_urb(hif_dev,
-						hif_dev->wlan_rx_data_urb[i]);
-		if (ret)
-			goto err_rx_urb;
+		skb = __dev_alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL);
+		if (!skb) {
+			ret = -ENOMEM;
+			goto err_skb;
+		}
 
-		/* Submit URB */
-		ret = usb_submit_urb(hif_dev->wlan_rx_data_urb[i], GFP_KERNEL);
-		if (ret)
-			goto err_rx_urb;
+		usb_fill_bulk_urb(urb, hif_dev->udev,
+				  usb_rcvbulkpipe(hif_dev->udev,
+						  USB_WLAN_RX_PIPE),
+				  skb->data, MAX_RX_BUF_SIZE,
+				  ath9k_hif_usb_rx_cb, skb);
 
+		/* Anchor URB */
+		usb_anchor_urb(urb, &hif_dev->rx_submitted);
+
+		/* Submit URB */
+		ret = usb_submit_urb(urb, GFP_KERNEL);
+		if (ret) {
+			usb_unanchor_urb(urb);
+			goto err_submit;
+		}
 	}
 
 	return 0;
 
-err_rx_urb:
-	ath9k_hif_usb_dealloc_rx_skbs(hif_dev);
+err_submit:
+	dev_kfree_skb_any(skb);
+err_skb:
+	usb_free_urb(urb);
+err_urb:
 	ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
 	return ret;
 }
@@ -689,6 +660,8 @@ static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev)
 {
 	if (hif_dev->reg_in_urb) {
 		usb_kill_urb(hif_dev->reg_in_urb);
+		if (hif_dev->reg_in_urb->context)
+			dev_kfree_skb_any((void *)hif_dev->reg_in_urb->context);
 		usb_free_urb(hif_dev->reg_in_urb);
 		hif_dev->reg_in_urb = NULL;
 	}
@@ -712,12 +685,10 @@ static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
 			 ath9k_hif_usb_reg_in_cb, skb, 1);
 
 	if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
-		goto err_skb;
+		goto err;
 
 	return 0;
 
-err_skb:
-	dev_kfree_skb_any(skb);
 err:
 	ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
 	return -ENOMEM;
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 7cc3762..ea9257b 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -85,18 +85,15 @@ struct hif_device_usb {
 	struct usb_interface *interface;
 	const struct firmware *firmware;
 	struct htc_target *htc_handle;
-	u8 flags;
-
 	struct hif_usb_tx tx;
-
-	struct urb *wlan_rx_data_urb[MAX_RX_URB_NUM];
 	struct urb *reg_in_urb;
-
+	struct usb_anchor rx_submitted;
 	struct sk_buff *remain_skb;
 	int rx_remain_len;
 	int rx_pkt_len;
 	int rx_transfer_len;
 	int rx_pad_len;
+	u8 flags; /* HIF_USB_* */
 };
 
 int ath9k_hif_usb_init(void);
-- 
1.7.0.3


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2010-03-29 10:17 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-03-29 10:37 [PATCH 4/7] ath9k_htc: Simplify RX URB management Sujith

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).