diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-07-29 16:14:13 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-16 14:39:46 -0400 |
commit | 4e6cbfd09c66893e5134c9896e9af353c2322b66 (patch) | |
tree | 274e8374c2b097058a5152da3bf6cf62d99dbad7 | |
parent | 68e887ef21dfd9adcf896ef92a9676bf9036a0aa (diff) |
mac80211: support use of NAPI for bottom-half processing
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>
-rw-r--r-- | include/net/mac80211.h | 24 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 5 | ||||
-rw-r--r-- | net/mac80211/iface.c | 4 | ||||
-rw-r--r-- | 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 b0787a1dea9..3f1e03b521e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1102,6 +1102,10 @@ enum ieee80211_hw_flags { | |||
1102 | * | 1102 | * |
1103 | * @max_rates: maximum number of alternate rate retry stages | 1103 | * @max_rates: maximum number of alternate rate retry stages |
1104 | * @max_rate_tries: maximum number of tries for each stage | 1104 | * @max_rate_tries: maximum number of tries for each stage |
1105 | * | ||
1106 | * @napi_weight: weight used for NAPI polling. You must specify an | ||
1107 | * appropriate value here if a napi_poll operation is provided | ||
1108 | * by your driver. | ||
1105 | */ | 1109 | */ |
1106 | struct ieee80211_hw { | 1110 | struct ieee80211_hw { |
1107 | struct ieee80211_conf conf; | 1111 | struct ieee80211_conf conf; |
@@ -1113,6 +1117,7 @@ struct ieee80211_hw { | |||
1113 | int channel_change_time; | 1117 | int channel_change_time; |
1114 | int vif_data_size; | 1118 | int vif_data_size; |
1115 | int sta_data_size; | 1119 | int sta_data_size; |
1120 | int napi_weight; | ||
1116 | u16 queues; | 1121 | u16 queues; |
1117 | u16 max_listen_interval; | 1122 | u16 max_listen_interval; |
1118 | s8 max_signal; | 1123 | s8 max_signal; |
@@ -1687,6 +1692,8 @@ enum ieee80211_ampdu_mlme_action { | |||
1687 | * switch operation for CSAs received from the AP may implement this | 1692 | * switch operation for CSAs received from the AP may implement this |
1688 | * callback. They must then call ieee80211_chswitch_done() to indicate | 1693 | * callback. They must then call ieee80211_chswitch_done() to indicate |
1689 | * completion of the channel switch. | 1694 | * completion of the channel switch. |
1695 | * | ||
1696 | * @napi_poll: Poll Rx queue for incoming data frames. | ||
1690 | */ | 1697 | */ |
1691 | struct ieee80211_ops { | 1698 | struct ieee80211_ops { |
1692 | int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | 1699 | int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); |
@@ -1752,6 +1759,7 @@ struct ieee80211_ops { | |||
1752 | void (*flush)(struct ieee80211_hw *hw, bool drop); | 1759 | void (*flush)(struct ieee80211_hw *hw, bool drop); |
1753 | void (*channel_switch)(struct ieee80211_hw *hw, | 1760 | void (*channel_switch)(struct ieee80211_hw *hw, |
1754 | struct ieee80211_channel_switch *ch_switch); | 1761 | struct ieee80211_channel_switch *ch_switch); |
1762 | int (*napi_poll)(struct ieee80211_hw *hw, int budget); | ||
1755 | }; | 1763 | }; |
1756 | 1764 | ||
1757 | /** | 1765 | /** |
@@ -1897,6 +1905,22 @@ void ieee80211_free_hw(struct ieee80211_hw *hw); | |||
1897 | */ | 1905 | */ |
1898 | void ieee80211_restart_hw(struct ieee80211_hw *hw); | 1906 | void ieee80211_restart_hw(struct ieee80211_hw *hw); |
1899 | 1907 | ||
1908 | /** ieee80211_napi_schedule - schedule NAPI poll | ||
1909 | * | ||
1910 | * Use this function to schedule NAPI polling on a device. | ||
1911 | * | ||
1912 | * @hw: the hardware to start polling | ||
1913 | */ | ||
1914 | void ieee80211_napi_schedule(struct ieee80211_hw *hw); | ||
1915 | |||
1916 | /** ieee80211_napi_complete - complete NAPI polling | ||
1917 | * | ||
1918 | * Use this function to finish NAPI polling on a device. | ||
1919 | * | ||
1920 | * @hw: the hardware to stop polling | ||
1921 | */ | ||
1922 | void ieee80211_napi_complete(struct ieee80211_hw *hw); | ||
1923 | |||
1900 | /** | 1924 | /** |
1901 | * ieee80211_rx - receive frame | 1925 | * ieee80211_rx - receive frame |
1902 | * | 1926 | * |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 65e0ed6c297..79d56454484 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -870,6 +870,11 @@ struct ieee80211_local { | |||
870 | struct dentry *keys; | 870 | struct dentry *keys; |
871 | } debugfs; | 871 | } debugfs; |
872 | #endif | 872 | #endif |
873 | |||
874 | /* dummy netdev for use w/ NAPI */ | ||
875 | struct net_device napi_dev; | ||
876 | |||
877 | struct napi_struct napi; | ||
873 | }; | 878 | }; |
874 | 879 | ||
875 | static inline struct ieee80211_sub_if_data * | 880 | static inline struct ieee80211_sub_if_data * |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index ebbe264e2b0..c1008a9d7bf 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -187,6 +187,8 @@ static int ieee80211_open(struct net_device *dev) | |||
187 | res = drv_start(local); | 187 | res = drv_start(local); |
188 | if (res) | 188 | if (res) |
189 | goto err_del_bss; | 189 | goto err_del_bss; |
190 | if (local->ops->napi_poll) | ||
191 | napi_enable(&local->napi); | ||
190 | /* we're brought up, everything changes */ | 192 | /* we're brought up, everything changes */ |
191 | hw_reconf_flags = ~0; | 193 | hw_reconf_flags = ~0; |
192 | ieee80211_led_radio(local, true); | 194 | ieee80211_led_radio(local, true); |
@@ -519,6 +521,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
519 | ieee80211_recalc_ps(local, -1); | 521 | ieee80211_recalc_ps(local, -1); |
520 | 522 | ||
521 | if (local->open_count == 0) { | 523 | if (local->open_count == 0) { |
524 | if (local->ops->napi_poll) | ||
525 | napi_disable(&local->napi); | ||
522 | ieee80211_clear_tx_pending(local); | 526 | ieee80211_clear_tx_pending(local); |
523 | ieee80211_stop_device(local); | 527 | ieee80211_stop_device(local); |
524 | 528 | ||
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 798a91b100c..1ed956c9cb8 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -390,6 +390,30 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, | |||
390 | } | 390 | } |
391 | #endif | 391 | #endif |
392 | 392 | ||
393 | static int ieee80211_napi_poll(struct napi_struct *napi, int budget) | ||
394 | { | ||
395 | struct ieee80211_local *local = | ||
396 | container_of(napi, struct ieee80211_local, napi); | ||
397 | |||
398 | return local->ops->napi_poll(&local->hw, budget); | ||
399 | } | ||
400 | |||
401 | void ieee80211_napi_schedule(struct ieee80211_hw *hw) | ||
402 | { | ||
403 | struct ieee80211_local *local = hw_to_local(hw); | ||
404 | |||
405 | napi_schedule(&local->napi); | ||
406 | } | ||
407 | EXPORT_SYMBOL(ieee80211_napi_schedule); | ||
408 | |||
409 | void ieee80211_napi_complete(struct ieee80211_hw *hw) | ||
410 | { | ||
411 | struct ieee80211_local *local = hw_to_local(hw); | ||
412 | |||
413 | napi_complete(&local->napi); | ||
414 | } | ||
415 | EXPORT_SYMBOL(ieee80211_napi_complete); | ||
416 | |||
393 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 417 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
394 | const struct ieee80211_ops *ops) | 418 | const struct ieee80211_ops *ops) |
395 | { | 419 | { |
@@ -494,6 +518,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
494 | skb_queue_head_init(&local->skb_queue); | 518 | skb_queue_head_init(&local->skb_queue); |
495 | skb_queue_head_init(&local->skb_queue_unreliable); | 519 | skb_queue_head_init(&local->skb_queue_unreliable); |
496 | 520 | ||
521 | /* init dummy netdev for use w/ NAPI */ | ||
522 | init_dummy_netdev(&local->napi_dev); | ||
523 | |||
497 | return local_to_hw(local); | 524 | return local_to_hw(local); |
498 | } | 525 | } |
499 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 526 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
@@ -683,6 +710,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
683 | goto fail_ifa; | 710 | goto fail_ifa; |
684 | #endif | 711 | #endif |
685 | 712 | ||
713 | netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll, | ||
714 | local->hw.napi_weight); | ||
715 | |||
686 | return 0; | 716 | return 0; |
687 | 717 | ||
688 | #ifdef CONFIG_INET | 718 | #ifdef CONFIG_INET |