Commit 4e6cbfd0 authored by John W. Linville's avatar John W. Linville

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: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 68e887ef
...@@ -1102,6 +1102,10 @@ enum ieee80211_hw_flags { ...@@ -1102,6 +1102,10 @@ enum ieee80211_hw_flags {
* *
* @max_rates: maximum number of alternate rate retry stages * @max_rates: maximum number of alternate rate retry stages
* @max_rate_tries: maximum number of tries for each stage * @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_hw {
struct ieee80211_conf conf; struct ieee80211_conf conf;
...@@ -1113,6 +1117,7 @@ struct ieee80211_hw { ...@@ -1113,6 +1117,7 @@ struct ieee80211_hw {
int channel_change_time; int channel_change_time;
int vif_data_size; int vif_data_size;
int sta_data_size; int sta_data_size;
int napi_weight;
u16 queues; u16 queues;
u16 max_listen_interval; u16 max_listen_interval;
s8 max_signal; s8 max_signal;
...@@ -1687,6 +1692,8 @@ enum ieee80211_ampdu_mlme_action { ...@@ -1687,6 +1692,8 @@ enum ieee80211_ampdu_mlme_action {
* switch operation for CSAs received from the AP may implement this * switch operation for CSAs received from the AP may implement this
* callback. They must then call ieee80211_chswitch_done() to indicate * callback. They must then call ieee80211_chswitch_done() to indicate
* completion of the channel switch. * completion of the channel switch.
*
* @napi_poll: Poll Rx queue for incoming data frames.
*/ */
struct ieee80211_ops { struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
...@@ -1752,6 +1759,7 @@ struct ieee80211_ops { ...@@ -1752,6 +1759,7 @@ struct ieee80211_ops {
void (*flush)(struct ieee80211_hw *hw, bool drop); void (*flush)(struct ieee80211_hw *hw, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw, void (*channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_channel_switch *ch_switch); 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); ...@@ -1897,6 +1905,22 @@ void ieee80211_free_hw(struct ieee80211_hw *hw);
*/ */
void ieee80211_restart_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 * ieee80211_rx - receive frame
* *
......
...@@ -870,6 +870,11 @@ struct ieee80211_local { ...@@ -870,6 +870,11 @@ struct ieee80211_local {
struct dentry *keys; struct dentry *keys;
} debugfs; } debugfs;
#endif #endif
/* dummy netdev for use w/ NAPI */
struct net_device napi_dev;
struct napi_struct napi;
}; };
static inline struct ieee80211_sub_if_data * static inline struct ieee80211_sub_if_data *
......
...@@ -187,6 +187,8 @@ static int ieee80211_open(struct net_device *dev) ...@@ -187,6 +187,8 @@ static int ieee80211_open(struct net_device *dev)
res = drv_start(local); res = drv_start(local);
if (res) if (res)
goto err_del_bss; goto err_del_bss;
if (local->ops->napi_poll)
napi_enable(&local->napi);
/* we're brought up, everything changes */ /* we're brought up, everything changes */
hw_reconf_flags = ~0; hw_reconf_flags = ~0;
ieee80211_led_radio(local, true); ieee80211_led_radio(local, true);
...@@ -519,6 +521,8 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -519,6 +521,8 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_recalc_ps(local, -1); ieee80211_recalc_ps(local, -1);
if (local->open_count == 0) { if (local->open_count == 0) {
if (local->ops->napi_poll)
napi_disable(&local->napi);
ieee80211_clear_tx_pending(local); ieee80211_clear_tx_pending(local);
ieee80211_stop_device(local); ieee80211_stop_device(local);
......
...@@ -390,6 +390,30 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, ...@@ -390,6 +390,30 @@ static int ieee80211_ifa_changed(struct notifier_block *nb,
} }
#endif #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, struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops) const struct ieee80211_ops *ops)
{ {
...@@ -494,6 +518,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, ...@@ -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);
skb_queue_head_init(&local->skb_queue_unreliable); 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); return local_to_hw(local);
} }
EXPORT_SYMBOL(ieee80211_alloc_hw); EXPORT_SYMBOL(ieee80211_alloc_hw);
...@@ -683,6 +710,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -683,6 +710,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_ifa; goto fail_ifa;
#endif #endif
netif_napi_add(&local->napi_dev, &local->napi, ieee80211_napi_poll,
local->hw.napi_weight);
return 0; return 0;
#ifdef CONFIG_INET #ifdef CONFIG_INET
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment