linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] mac80211: support use of NAPI for bottom-half processing
@ 2010-07-29 20:14 John W. Linville
  2010-07-29 20:14 ` [PATCH 2/2] rtl8180: use " John W. Linville
  2010-07-29 20:39 ` [PATCH 1/2] mac80211: support use of " Johannes Berg
  0 siblings, 2 replies; 6+ messages in thread
From: John W. Linville @ 2010-07-29 20:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: John W. Linville

This patch implement basic infrastructure to support use of NAPI by
mac80211-based hardware drivers.

Because mac80211 devices can support multiple netdevs, a dummy netdev
is used for interfacing with the NAPI code in the core of the network
stack.  That structure is hidden from the hardware drivers, but the
actual napi_struct is exposed in the ieee80211_hw structure so that the
poll routines in drivers can retrieve that structure.  Hardware drivers
can also specify their own weight value for NAPI polling.

Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 include/net/mac80211.h     |    8 ++++++++
 net/mac80211/ieee80211_i.h |    3 +++
 net/mac80211/iface.c       |    4 ++++
 net/mac80211/main.c        |    6 ++++++
 4 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 20d372e..88223b4 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1094,6 +1094,9 @@ enum ieee80211_hw_flags {
  *
  * @max_rates: maximum number of alternate rate retry stages
  * @max_rate_tries: maximum number of tries for each stage
+ *
+ * @napi: NAPI control structure
+ * @napi_weight: weight used for NAPI polling
  */
 struct ieee80211_hw {
 	struct ieee80211_conf conf;
@@ -1105,6 +1108,8 @@ struct ieee80211_hw {
 	int channel_change_time;
 	int vif_data_size;
 	int sta_data_size;
+	struct napi_struct napi;
+	int napi_weight;
 	u16 queues;
 	u16 max_listen_interval;
 	s8 max_signal;
@@ -1679,6 +1684,8 @@ enum ieee80211_ampdu_mlme_action {
  *	switch operation for CSAs received from the AP may implement this
  *	callback. They must then call ieee80211_chswitch_done() to indicate
  *	completion of the channel switch.
+ *
+ * @napi_poll: Poll Rx queue for incoming data frames.
  */
 struct ieee80211_ops {
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1744,6 +1751,7 @@ struct ieee80211_ops {
 	void (*flush)(struct ieee80211_hw *hw, bool drop);
 	void (*channel_switch)(struct ieee80211_hw *hw,
 			       struct ieee80211_channel_switch *ch_switch);
+	int (*napi_poll)(struct napi_struct *napi, int budget);
 };
 
 /**
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c6b5c2d..2c6ac97 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -869,6 +869,9 @@ struct ieee80211_local {
 		struct dentry *keys;
 	} debugfs;
 #endif
+
+	/* dummy netdev for use w/ NAPI */
+	struct net_device napi_dev;
 };
 
 static inline struct ieee80211_sub_if_data *
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ebbe264..827f25d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -187,6 +187,8 @@ static int ieee80211_open(struct net_device *dev)
 		res = drv_start(local);
 		if (res)
 			goto err_del_bss;
+		if (local->ops->napi_poll)
+			napi_enable(&local->hw.napi);
 		/* we're brought up, everything changes */
 		hw_reconf_flags = ~0;
 		ieee80211_led_radio(local, true);
@@ -519,6 +521,8 @@ static int ieee80211_stop(struct net_device *dev)
 	ieee80211_recalc_ps(local, -1);
 
 	if (local->open_count == 0) {
+		if (local->ops->napi_poll)
+			napi_disable(&local->hw.napi);
 		ieee80211_clear_tx_pending(local);
 		ieee80211_stop_device(local);
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 0e95c75..79ca2ba 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -491,6 +491,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	skb_queue_head_init(&local->skb_queue);
 	skb_queue_head_init(&local->skb_queue_unreliable);
 
+	/* init dummy netdev for use w/ NAPI */
+	init_dummy_netdev(&local->napi_dev);
+
 	return local_to_hw(local);
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -680,6 +683,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 		goto fail_ifa;
 #endif
 
+	netif_napi_add(&local->napi_dev, &local->hw.napi, local->ops->napi_poll,
+			local->hw.napi_weight);
+
 	return 0;
 
  fail_ifa:
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] rtl8180: use NAPI for bottom-half processing
  2010-07-29 20:14 [PATCH 1/2] mac80211: support use of NAPI for bottom-half processing John W. Linville
@ 2010-07-29 20:14 ` John W. Linville
  2010-07-29 20:39 ` [PATCH 1/2] mac80211: support use of " Johannes Berg
  1 sibling, 0 replies; 6+ messages in thread
From: John W. Linville @ 2010-07-29 20:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: John W. Linville

Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 drivers/net/wireless/rtl818x/rtl8180_dev.c |  130 +++++++++++++++-------------
 1 files changed, 71 insertions(+), 59 deletions(-)

diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index d8b186a..b89daec 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -99,19 +99,68 @@ void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 	}
 }
 
-static void rtl8180_handle_rx(struct ieee80211_hw *dev)
+static void rtl8180_handle_tx(struct ieee80211_hw *dev)
 {
 	struct rtl8180_priv *priv = dev->priv;
-	unsigned int count = 32;
+	struct rtl8180_tx_ring *ring;
+	int prio;
+
+	spin_lock(&priv->lock);
+
+	for (prio = 3; prio >= 0; prio--) {
+		ring = &priv->tx_ring[prio];
+
+		while (skb_queue_len(&ring->queue)) {
+			struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
+			struct sk_buff *skb;
+			struct ieee80211_tx_info *info;
+			u32 flags = le32_to_cpu(entry->flags);
+
+			if (flags & RTL818X_TX_DESC_FLAG_OWN)
+				break;
+
+			ring->idx = (ring->idx + 1) % ring->entries;
+			skb = __skb_dequeue(&ring->queue);
+			pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
+					 skb->len, PCI_DMA_TODEVICE);
+
+			info = IEEE80211_SKB_CB(skb);
+			ieee80211_tx_info_clear_status(info);
+
+			if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+			    (flags & RTL818X_TX_DESC_FLAG_TX_OK))
+				info->flags |= IEEE80211_TX_STAT_ACK;
+
+			info->status.rates[0].count = (flags & 0xFF) + 1;
+			info->status.rates[1].idx = -1;
+
+			ieee80211_tx_status(dev, skb);
+			if (ring->entries - skb_queue_len(&ring->queue) == 2)
+				ieee80211_wake_queue(dev, prio);
+		}
+	}
+
+	spin_unlock(&priv->lock);
+}
+
+static int rtl8180_poll(struct napi_struct *napi, int budget)
+{
+	struct ieee80211_hw *dev =
+		container_of(napi, struct ieee80211_hw, napi);
+	struct rtl8180_priv *priv = dev->priv;
+	unsigned int count = 0;
 	u8 signal, agc, sq;
 
-	while (count--) {
+	/* handle pending Tx queue cleanup */
+	rtl8180_handle_tx(dev);
+
+	while (count++ < budget) {
 		struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
 		struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
 		u32 flags = le32_to_cpu(entry->flags);
 
 		if (flags & RTL818X_RX_DESC_FLAG_OWN)
-			return;
+			break;
 
 		if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
 				      RTL818X_RX_DESC_FLAG_FOF |
@@ -151,7 +200,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 				rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 
 			memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
-			ieee80211_rx_irqsafe(dev, skb);
+			ieee80211_rx(dev, skb);
 
 			skb = new_skb;
 			priv->rx_buf[priv->rx_idx] = skb;
@@ -168,41 +217,16 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 			entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
 		priv->rx_idx = (priv->rx_idx + 1) % 32;
 	}
-}
-
-static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
-{
-	struct rtl8180_priv *priv = dev->priv;
-	struct rtl8180_tx_ring *ring = &priv->tx_ring[prio];
-
-	while (skb_queue_len(&ring->queue)) {
-		struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
-		struct sk_buff *skb;
-		struct ieee80211_tx_info *info;
-		u32 flags = le32_to_cpu(entry->flags);
-
-		if (flags & RTL818X_TX_DESC_FLAG_OWN)
-			return;
-
-		ring->idx = (ring->idx + 1) % ring->entries;
-		skb = __skb_dequeue(&ring->queue);
-		pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
-				 skb->len, PCI_DMA_TODEVICE);
-
-		info = IEEE80211_SKB_CB(skb);
-		ieee80211_tx_info_clear_status(info);
-
-		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-		    (flags & RTL818X_TX_DESC_FLAG_TX_OK))
-			info->flags |= IEEE80211_TX_STAT_ACK;
 
-		info->status.rates[0].count = (flags & 0xFF) + 1;
-		info->status.rates[1].idx = -1;
+	if (count < budget) {
+		/* disable polling */
+		napi_complete(napi);
 
-		ieee80211_tx_status_irqsafe(dev, skb);
-		if (ring->entries - skb_queue_len(&ring->queue) == 2)
-			ieee80211_wake_queue(dev, prio);
+		/* enable interrupts */
+		rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
 	}
+
+	return count;
 }
 
 static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
@@ -211,31 +235,17 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
 	struct rtl8180_priv *priv = dev->priv;
 	u16 reg;
 
-	spin_lock(&priv->lock);
 	reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS);
-	if (unlikely(reg == 0xFFFF)) {
-		spin_unlock(&priv->lock);
+	if (unlikely(reg == 0xFFFF))
 		return IRQ_HANDLED;
-	}
 
 	rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
 
-	if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR))
-		rtl8180_handle_tx(dev, 3);
-
-	if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR))
-		rtl8180_handle_tx(dev, 2);
-
-	if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
-		rtl8180_handle_tx(dev, 1);
-
-	if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR))
-		rtl8180_handle_tx(dev, 0);
-
-	if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR))
-		rtl8180_handle_rx(dev);
+	/* disable interrupts */
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
-	spin_unlock(&priv->lock);
+	/* enable polling */
+	napi_schedule(&dev->napi);
 
 	return IRQ_HANDLED;
 }
@@ -247,7 +257,6 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	struct rtl8180_priv *priv = dev->priv;
 	struct rtl8180_tx_ring *ring;
 	struct rtl8180_tx_desc *entry;
-	unsigned long flags;
 	unsigned int idx, prio;
 	dma_addr_t mapping;
 	u32 tx_flags;
@@ -294,7 +303,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 			plcp_len |= 1 << 15;
 	}
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock(&priv->lock);
 
 	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
@@ -318,7 +327,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	if (ring->entries - skb_queue_len(&ring->queue) < 2)
 		ieee80211_stop_queue(dev, prio);
 
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock(&priv->lock);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
 
@@ -861,6 +870,7 @@ static const struct ieee80211_ops rtl8180_ops = {
 	.prepare_multicast	= rtl8180_prepare_multicast,
 	.configure_filter	= rtl8180_configure_filter,
 	.get_tsf		= rtl8180_get_tsf,
+	.napi_poll		= rtl8180_poll,
 };
 
 static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -992,6 +1002,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
 	dev->queues = 1;
 	dev->max_signal = 65;
 
+	dev->napi_weight = 64;
+
 	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
 	reg &= RTL818X_TX_CONF_HWVER_MASK;
 	switch (reg) {
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] mac80211: support use of NAPI for bottom-half processing
  2010-07-29 20:14 [PATCH 1/2] mac80211: support use of NAPI for bottom-half processing John W. Linville
  2010-07-29 20:14 ` [PATCH 2/2] rtl8180: use " John W. Linville
@ 2010-07-29 20:39 ` Johannes Berg
  2010-07-29 20:42   ` Johannes Berg
                     ` (2 more replies)
  1 sibling, 3 replies; 6+ messages in thread
From: Johannes Berg @ 2010-07-29 20:39 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless

On Thu, 2010-07-29 at 16:14 -0400, John W. Linville wrote:

> +	struct napi_struct napi;
> +	int napi_weight;

Why is the napi struct visible to drivers? Ok .. I see later.

> @@ -1679,6 +1684,8 @@ enum ieee80211_ampdu_mlme_action {
>   *	switch operation for CSAs received from the AP may implement this
>   *	callback. They must then call ieee80211_chswitch_done() to indicate
>   *	completion of the channel switch.
> + *
> + * @napi_poll: Poll Rx queue for incoming data frames.

should this document that napi_weight must be set?

> +	int (*napi_poll)(struct napi_struct *napi, int budget);

I'd prefer passing the hw here and having mac80211 wrap it in a simple
function that does the container_of magic? Anything preventing that?
Then the napi struct can be hidden from drivers.

johannes


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] mac80211: support use of NAPI for bottom-half processing
  2010-07-29 20:39 ` [PATCH 1/2] mac80211: support use of " Johannes Berg
@ 2010-07-29 20:42   ` Johannes Berg
  2010-07-29 21:14   ` [PATCH v2 " John W. Linville
  2010-07-29 21:14   ` [PATCH v2 2/2] rtl8180: use " John W. Linville
  2 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2010-07-29 20:42 UTC (permalink / raw)
  To: John W. Linville; +Cc: linux-wireless

On Thu, 2010-07-29 at 22:39 +0200, Johannes Berg wrote:

> > +	int (*napi_poll)(struct napi_struct *napi, int budget);
> 
> I'd prefer passing the hw here and having mac80211 wrap it in a simple
> function that does the container_of magic? Anything preventing that?
> Then the napi struct can be hidden from drivers.

Ok actually that requires wrapping napi_complete() too, that doesn't
seem worth it. Can you wrap the container_of() in an inline though and
maybe do "struct napi_struct _napi;" and document it shouldn't really be
touched or something?

johannes


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/2] mac80211: support use of NAPI for bottom-half processing
  2010-07-29 20:39 ` [PATCH 1/2] mac80211: support use of " Johannes Berg
  2010-07-29 20:42   ` Johannes Berg
@ 2010-07-29 21:14   ` John W. Linville
  2010-07-29 21:14   ` [PATCH v2 2/2] rtl8180: use " John W. Linville
  2 siblings, 0 replies; 6+ messages in thread
From: John W. Linville @ 2010-07-29 21:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, John W. Linville

This patch implement basic infrastructure to support use of NAPI by
mac80211-based hardware drivers.

Because mac80211 devices can support multiple netdevs, a dummy netdev
is used for interfacing with the NAPI code in the core of the network
stack.  That structure is hidden from the hardware drivers, but the
actual napi_struct is exposed in the ieee80211_hw structure so that the
poll routines in drivers can retrieve that structure.  Hardware drivers
can also specify their own weight value for NAPI polling.

Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
v2 -> hide napi_struct as suggested by johill

 include/net/mac80211.h     |   24 ++++++++++++++++++++++++
 net/mac80211/ieee80211_i.h |    5 +++++
 net/mac80211/iface.c       |    4 ++++
 net/mac80211/main.c        |   30 ++++++++++++++++++++++++++++++
 4 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f85fc8a..64171c1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1102,6 +1102,10 @@ enum ieee80211_hw_flags {
  *
  * @max_rates: maximum number of alternate rate retry stages
  * @max_rate_tries: maximum number of tries for each stage
+ *
+ * @napi_weight: weight used for NAPI polling.  You must specify an
+ *	appropriate value here if a napi_poll operation is provided
+ *	by your driver.
  */
 struct ieee80211_hw {
 	struct ieee80211_conf conf;
@@ -1113,6 +1117,7 @@ struct ieee80211_hw {
 	int channel_change_time;
 	int vif_data_size;
 	int sta_data_size;
+	int napi_weight;
 	u16 queues;
 	u16 max_listen_interval;
 	s8 max_signal;
@@ -1687,6 +1692,8 @@ enum ieee80211_ampdu_mlme_action {
  *	switch operation for CSAs received from the AP may implement this
  *	callback. They must then call ieee80211_chswitch_done() to indicate
  *	completion of the channel switch.
+ *
+ * @napi_poll: Poll Rx queue for incoming data frames.
  */
 struct ieee80211_ops {
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1752,6 +1759,7 @@ struct ieee80211_ops {
 	void (*flush)(struct ieee80211_hw *hw, bool drop);
 	void (*channel_switch)(struct ieee80211_hw *hw,
 			       struct ieee80211_channel_switch *ch_switch);
+	int (*napi_poll)(struct ieee80211_hw *hw, int budget);
 };
 
 /**
@@ -1897,6 +1905,22 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
  */
 void ieee80211_restart_hw(struct ieee80211_hw *hw);
 
+/** ieee80211_napi_schedule - schedule NAPI poll
+ *
+ * Use this function to schedule NAPI polling on a device.
+ *
+ * @hw: the hardware to start polling
+ */
+void ieee80211_napi_schedule(struct ieee80211_hw *hw);
+
+/** ieee80211_napi_complete - complete NAPI polling
+ *
+ * Use this function to finish NAPI polling on a device.
+ *
+ * @hw: the hardware to stop polling
+ */
+void ieee80211_napi_complete(struct ieee80211_hw *hw);
+
 /**
  * ieee80211_rx - receive frame
  *
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 65e0ed6..79d5645 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -870,6 +870,11 @@ struct ieee80211_local {
 		struct dentry *keys;
 	} debugfs;
 #endif
+
+	/* dummy netdev for use w/ NAPI */
+	struct net_device napi_dev;
+
+	struct napi_struct napi;
 };
 
 static inline struct ieee80211_sub_if_data *
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index ebbe264..c1008a9 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -187,6 +187,8 @@ static int ieee80211_open(struct net_device *dev)
 		res = drv_start(local);
 		if (res)
 			goto err_del_bss;
+		if (local->ops->napi_poll)
+			napi_enable(&local->napi);
 		/* we're brought up, everything changes */
 		hw_reconf_flags = ~0;
 		ieee80211_led_radio(local, true);
@@ -519,6 +521,8 @@ static int ieee80211_stop(struct net_device *dev)
 	ieee80211_recalc_ps(local, -1);
 
 	if (local->open_count == 0) {
+		if (local->ops->napi_poll)
+			napi_disable(&local->napi);
 		ieee80211_clear_tx_pending(local);
 		ieee80211_stop_device(local);
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 7cc4f91..98bb5c0 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -390,6 +390,30 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
 }
 #endif
 
+static int ieee80211_napi_poll(struct napi_struct *napi, int budget)
+{
+	struct ieee80211_local *local =
+		container_of(napi, struct ieee80211_local, napi);
+
+	return local->ops->napi_poll(&local->hw, budget);
+}
+
+void ieee80211_napi_schedule(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	napi_schedule(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_schedule);
+
+void ieee80211_napi_complete(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	napi_complete(&local->napi);
+}
+EXPORT_SYMBOL(ieee80211_napi_complete);
+
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 					const struct ieee80211_ops *ops)
 {
@@ -494,6 +518,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	skb_queue_head_init(&local->skb_queue);
 	skb_queue_head_init(&local->skb_queue_unreliable);
 
+	/* init dummy netdev for use w/ NAPI */
+	init_dummy_netdev(&local->napi_dev);
+
 	return local_to_hw(local);
 }
 EXPORT_SYMBOL(ieee80211_alloc_hw);
@@ -683,6 +710,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 		goto fail_ifa;
 #endif
 
+	netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
+			local->hw.napi_weight);
+
 	return 0;
 
  fail_ifa:
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/2] rtl8180: use NAPI for bottom-half processing
  2010-07-29 20:39 ` [PATCH 1/2] mac80211: support use of " Johannes Berg
  2010-07-29 20:42   ` Johannes Berg
  2010-07-29 21:14   ` [PATCH v2 " John W. Linville
@ 2010-07-29 21:14   ` John W. Linville
  2 siblings, 0 replies; 6+ messages in thread
From: John W. Linville @ 2010-07-29 21:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, John W. Linville

Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
v2 -> hide napi_struct as suggested by johill

 drivers/net/wireless/rtl818x/rtl8180_dev.c |  128 +++++++++++++++-------------
 1 files changed, 69 insertions(+), 59 deletions(-)

diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 1d81785..c879660 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -99,19 +99,66 @@ void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 	}
 }
 
-static void rtl8180_handle_rx(struct ieee80211_hw *dev)
+static void rtl8180_handle_tx(struct ieee80211_hw *dev)
 {
 	struct rtl8180_priv *priv = dev->priv;
-	unsigned int count = 32;
+	struct rtl8180_tx_ring *ring;
+	int prio;
+
+	spin_lock(&priv->lock);
+
+	for (prio = 3; prio >= 0; prio--) {
+		ring = &priv->tx_ring[prio];
+
+		while (skb_queue_len(&ring->queue)) {
+			struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
+			struct sk_buff *skb;
+			struct ieee80211_tx_info *info;
+			u32 flags = le32_to_cpu(entry->flags);
+
+			if (flags & RTL818X_TX_DESC_FLAG_OWN)
+				break;
+
+			ring->idx = (ring->idx + 1) % ring->entries;
+			skb = __skb_dequeue(&ring->queue);
+			pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
+					 skb->len, PCI_DMA_TODEVICE);
+
+			info = IEEE80211_SKB_CB(skb);
+			ieee80211_tx_info_clear_status(info);
+
+			if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+			    (flags & RTL818X_TX_DESC_FLAG_TX_OK))
+				info->flags |= IEEE80211_TX_STAT_ACK;
+
+			info->status.rates[0].count = (flags & 0xFF) + 1;
+			info->status.rates[1].idx = -1;
+
+			ieee80211_tx_status(dev, skb);
+			if (ring->entries - skb_queue_len(&ring->queue) == 2)
+				ieee80211_wake_queue(dev, prio);
+		}
+	}
+
+	spin_unlock(&priv->lock);
+}
+
+static int rtl8180_poll(struct ieee80211_hw *dev, int budget)
+{
+	struct rtl8180_priv *priv = dev->priv;
+	unsigned int count = 0;
 	u8 signal, agc, sq;
 
-	while (count--) {
+	/* handle pending Tx queue cleanup */
+	rtl8180_handle_tx(dev);
+
+	while (count++ < budget) {
 		struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx];
 		struct sk_buff *skb = priv->rx_buf[priv->rx_idx];
 		u32 flags = le32_to_cpu(entry->flags);
 
 		if (flags & RTL818X_RX_DESC_FLAG_OWN)
-			return;
+			break;
 
 		if (unlikely(flags & (RTL818X_RX_DESC_FLAG_DMA_FAIL |
 				      RTL818X_RX_DESC_FLAG_FOF |
@@ -151,7 +198,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 				rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 
 			memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
-			ieee80211_rx_irqsafe(dev, skb);
+			ieee80211_rx(dev, skb);
 
 			skb = new_skb;
 			priv->rx_buf[priv->rx_idx] = skb;
@@ -168,41 +215,16 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
 			entry->flags |= cpu_to_le32(RTL818X_RX_DESC_FLAG_EOR);
 		priv->rx_idx = (priv->rx_idx + 1) % 32;
 	}
-}
-
-static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
-{
-	struct rtl8180_priv *priv = dev->priv;
-	struct rtl8180_tx_ring *ring = &priv->tx_ring[prio];
-
-	while (skb_queue_len(&ring->queue)) {
-		struct rtl8180_tx_desc *entry = &ring->desc[ring->idx];
-		struct sk_buff *skb;
-		struct ieee80211_tx_info *info;
-		u32 flags = le32_to_cpu(entry->flags);
-
-		if (flags & RTL818X_TX_DESC_FLAG_OWN)
-			return;
-
-		ring->idx = (ring->idx + 1) % ring->entries;
-		skb = __skb_dequeue(&ring->queue);
-		pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf),
-				 skb->len, PCI_DMA_TODEVICE);
-
-		info = IEEE80211_SKB_CB(skb);
-		ieee80211_tx_info_clear_status(info);
-
-		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-		    (flags & RTL818X_TX_DESC_FLAG_TX_OK))
-			info->flags |= IEEE80211_TX_STAT_ACK;
 
-		info->status.rates[0].count = (flags & 0xFF) + 1;
-		info->status.rates[1].idx = -1;
+	if (count < budget) {
+		/* disable polling */
+		ieee80211_napi_complete(dev);
 
-		ieee80211_tx_status_irqsafe(dev, skb);
-		if (ring->entries - skb_queue_len(&ring->queue) == 2)
-			ieee80211_wake_queue(dev, prio);
+		/* enable interrupts */
+		rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
 	}
+
+	return count;
 }
 
 static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
@@ -211,31 +233,17 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
 	struct rtl8180_priv *priv = dev->priv;
 	u16 reg;
 
-	spin_lock(&priv->lock);
 	reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS);
-	if (unlikely(reg == 0xFFFF)) {
-		spin_unlock(&priv->lock);
+	if (unlikely(reg == 0xFFFF))
 		return IRQ_HANDLED;
-	}
 
 	rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg);
 
-	if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR))
-		rtl8180_handle_tx(dev, 3);
-
-	if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR))
-		rtl8180_handle_tx(dev, 2);
-
-	if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR))
-		rtl8180_handle_tx(dev, 1);
-
-	if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR))
-		rtl8180_handle_tx(dev, 0);
-
-	if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR))
-		rtl8180_handle_rx(dev);
+	/* disable interrupts */
+	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
-	spin_unlock(&priv->lock);
+	/* enable polling */
+	ieee80211_napi_schedule(dev);
 
 	return IRQ_HANDLED;
 }
@@ -247,7 +255,6 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	struct rtl8180_priv *priv = dev->priv;
 	struct rtl8180_tx_ring *ring;
 	struct rtl8180_tx_desc *entry;
-	unsigned long flags;
 	unsigned int idx, prio;
 	dma_addr_t mapping;
 	u32 tx_flags;
@@ -294,7 +301,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 			plcp_len |= 1 << 15;
 	}
 
-	spin_lock_irqsave(&priv->lock, flags);
+	spin_lock(&priv->lock);
 
 	if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 		if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
@@ -318,7 +325,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 	if (ring->entries - skb_queue_len(&ring->queue) < 2)
 		ieee80211_stop_queue(dev, prio);
 
-	spin_unlock_irqrestore(&priv->lock, flags);
+	spin_unlock(&priv->lock);
 
 	rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
 
@@ -859,6 +866,7 @@ static const struct ieee80211_ops rtl8180_ops = {
 	.prepare_multicast	= rtl8180_prepare_multicast,
 	.configure_filter	= rtl8180_configure_filter,
 	.get_tsf		= rtl8180_get_tsf,
+	.napi_poll		= rtl8180_poll,
 };
 
 static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -990,6 +998,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
 	dev->queues = 1;
 	dev->max_signal = 65;
 
+	dev->napi_weight = 64;
+
 	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
 	reg &= RTL818X_TX_CONF_HWVER_MASK;
 	switch (reg) {
-- 
1.7.1.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-07-29 21:15 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-29 20:14 [PATCH 1/2] mac80211: support use of NAPI for bottom-half processing John W. Linville
2010-07-29 20:14 ` [PATCH 2/2] rtl8180: use " John W. Linville
2010-07-29 20:39 ` [PATCH 1/2] mac80211: support use of " Johannes Berg
2010-07-29 20:42   ` Johannes Berg
2010-07-29 21:14   ` [PATCH v2 " John W. Linville
2010-07-29 21:14   ` [PATCH v2 2/2] rtl8180: use " John W. Linville

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).