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>
This commit is contained in:
parent
68e887ef21
commit
4e6cbfd09c
|
@ -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 {
|
||||||
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 {
|
||||||
* 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 {
|
||||||
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);
|
||||||
*/
|
*/
|
||||||
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 {
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
}
|
}
|
||||||
#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,
|
||||||
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)
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue