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