linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
To: linux-wireless@vger.kernel.org
Cc: Daniel Drake <dsd@gentoo.org>,
	"John W. Linville" <linville@tuxdriver.com>,
	Ulrich Kunitz <kune@deine-taler.de>
Subject: [PATCH] zd1211rw: change endpoint types of EP_REGS_OUT and EP_INT_IN from interrupt to bulk
Date: Sun, 06 Feb 2011 10:35:22 +0200	[thread overview]
Message-ID: <20110206083522.16858.24185.stgit@fate.lan> (raw)

This fixes high CPU usage when writing beacon frame to hardware. With this
patch CPU usage of kworker on Intel Atom with 100 TU beacon interval goes
from ~10% down to <1%.

Checking vendor driver appears it's also ignoring fact that endpoints are
interrupt type and is using bulk urbs on these.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
 drivers/net/wireless/zd1211rw/zd_usb.c |   62 +++++++++++++++++++++++---------
 drivers/net/wireless/zd1211rw/zd_usb.h |    1 -
 2 files changed, 44 insertions(+), 19 deletions(-)

diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index f6df366..65aff96 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -452,19 +452,6 @@ resubmit:
 	return;
 }
 
-static inline int int_urb_interval(struct usb_device *udev)
-{
-	switch (udev->speed) {
-	case USB_SPEED_HIGH:
-		return 4;
-	case USB_SPEED_LOW:
-		return 10;
-	case USB_SPEED_FULL:
-	default:
-		return 1;
-	}
-}
-
 static inline int usb_int_enabled(struct zd_usb *usb)
 {
 	unsigned long flags;
@@ -511,10 +498,9 @@ int zd_usb_enable_int(struct zd_usb *usb)
 		goto error_set_urb_null;
 	}
 
-	usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
+	usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_INT_IN),
 			 intr->buffer, USB_MAX_EP_INT_BUFFER,
-			 int_urb_complete, usb,
-			 intr->interval);
+			 int_urb_complete, usb);
 	urb->transfer_dma = intr->buffer_dma;
 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
@@ -1118,7 +1104,6 @@ static inline void init_usb_interrupt(struct zd_usb *usb)
 	struct zd_usb_interrupt *intr = &usb->intr;
 
 	spin_lock_init(&intr->lock);
-	intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
 	init_completion(&intr->read_regs.completion);
 	intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
 }
@@ -1263,10 +1248,32 @@ static int eject_installer(struct usb_interface *intf)
 	return 0;
 }
 
+static int usb_endpoint_int_to_bulk(struct usb_device *udev, unsigned int pipe)
+{
+	struct usb_host_endpoint *ep;
+
+	ep = usb_pipe_endpoint(udev, pipe);
+	if (!ep)
+		return -EPIPE;
+
+	switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_INT:
+		ep->desc.bmAttributes &= ~USB_ENDPOINT_XFERTYPE_MASK;
+		ep->desc.bmAttributes |= USB_ENDPOINT_XFER_BULK;
+		ep->desc.bInterval = 0;
+		/* passthru */
+	case USB_ENDPOINT_XFER_BULK:
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
 int zd_usb_init_hw(struct zd_usb *usb)
 {
 	int r;
 	struct zd_mac *mac = zd_usb_to_mac(usb);
+	struct usb_device *udev = zd_usb_to_usbdev(usb);
 
 	dev_dbg_f(zd_usb_dev(usb), "\n");
 
@@ -1277,13 +1284,32 @@ int zd_usb_init_hw(struct zd_usb *usb)
 		return r;
 	}
 
-	r = usb_reset_configuration(zd_usb_to_usbdev(usb));
+	r = usb_reset_configuration(udev);
 	if (r) {
 		dev_dbg_f(zd_usb_dev(usb),
 			"couldn't reset configuration. Error number %d\n", r);
 		return r;
 	}
 
+	/* Change EP_REGS_OUT and EP_INT_IN to bulk endpoints. This solves high
+	 * CPU usage of zd_mac_beacon_config.
+	 */
+	r = usb_endpoint_int_to_bulk(udev, usb_sndintpipe(udev, EP_REGS_OUT));
+	if (r) {
+		dev_dbg_f(zd_usb_dev(usb),
+			  "couldn't change EP_REGS_OUT endpoint type to bulk. "
+			  "Error number %d\n", r);
+		return r;
+	}
+
+	r = usb_endpoint_int_to_bulk(udev, usb_rcvintpipe(udev, EP_INT_IN));
+	if (r) {
+		dev_dbg_f(zd_usb_dev(usb),
+			  "couldn't change EP_INT_IN endpoint type to bulk. "
+			  "Error number %d\n", r);
+		return r;
+	}
+
 	r = zd_mac_init_hw(mac->hw);
 	if (r) {
 		dev_dbg_f(zd_usb_dev(usb),
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 2d688f4..333bb84 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -168,7 +168,6 @@ struct zd_usb_interrupt {
 	struct urb *urb;
 	void *buffer;
 	dma_addr_t buffer_dma;
-	int interval;
 	u8 read_regs_enabled:1;
 };
 


             reply	other threads:[~2011-02-06  8:35 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-02-06  8:35 Jussi Kivilinna [this message]
2011-02-06  9:16 ` [PATCH] zd1211rw: change endpoint types of EP_REGS_OUT and EP_INT_IN from interrupt to bulk Sujith
2011-02-06 11:35   ` Jussi Kivilinna
2011-02-15 18:49 ` John W. Linville
2011-02-16  1:08   ` Jussi Kivilinna

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110206083522.16858.24185.stgit@fate.lan \
    --to=jussi.kivilinna@mbnet.fi \
    --cc=dsd@gentoo.org \
    --cc=kune@deine-taler.de \
    --cc=linux-wireless@vger.kernel.org \
    --cc=linville@tuxdriver.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).