Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+24 −0
Original line number Original line Diff line number Diff line
@@ -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
 *
 *
+5 −0
Original line number Original line Diff line number Diff line
@@ -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 *
+4 −0
Original line number Original line Diff line number Diff line
@@ -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);


+30 −0
Original line number Original line Diff line number Diff line
@@ -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