Skip to content

Commit

Permalink
mac80211: annotate sleeping driver ops
Browse files Browse the repository at this point in the history
To make it easier to notice cases of calling sleeping ops in atomic context,
annotate driver-ops.h with appropiate might_sleep() calls. At the same time,
also document in mac80211.h the op functions with missing contexts.

mac80211 doesn't seem to use get_tx_stats anywhere currently. Just to be on
the safe side, I documented it to be atomic, but hopefully the op can be
removed in the future.

Compile-tested only.

Signed-off-by: Kalle Valo <kalle.valo@iki.fi>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Kalle Valo authored and John W. Linville committed Dec 28, 2009
1 parent 095d5ef commit e1781ed
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 16 deletions.
43 changes: 31 additions & 12 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -1383,15 +1383,15 @@ enum ieee80211_ampdu_mlme_action {
* When the device is started it should not have a MAC address
* to avoid acknowledging frames before a non-monitor device
* is added.
* Must be implemented.
* Must be implemented and can sleep.
*
* @stop: Called after last netdevice attached to the hardware
* is disabled. This should turn off the hardware (at least
* it must turn off frame reception.)
* May be called right after add_interface if that rejects
* an interface. If you added any work onto the mac80211 workqueue
* you should ensure to cancel it on this callback.
* Must be implemented.
* Must be implemented and can sleep.
*
* @add_interface: Called when a netdevice attached to the hardware is
* enabled. Because it is not called for monitor mode devices, @start
Expand All @@ -1401,7 +1401,7 @@ enum ieee80211_ampdu_mlme_action {
* interface is given in the conf parameter.
* The callback may refuse to add an interface by returning a
* negative error code (which will be seen in userspace.)
* Must be implemented.
* Must be implemented and can sleep.
*
* @remove_interface: Notifies a driver that an interface is going down.
* The @stop callback is called after this if it is the last interface
Expand All @@ -1410,40 +1410,43 @@ enum ieee80211_ampdu_mlme_action {
* must be cleared so the device no longer acknowledges packets,
* the mac_addr member of the conf structure is, however, set to the
* MAC address of the device going away.
* Hence, this callback must be implemented.
* Hence, this callback must be implemented. It can sleep.
*
* @config: Handler for configuration requests. IEEE 802.11 code calls this
* function to change hardware configuration, e.g., channel.
* This function should never fail but returns a negative error code
* if it does.
* if it does. The callback can sleep.
*
* @bss_info_changed: Handler for configuration requests related to BSS
* parameters that may vary during BSS's lifespan, and may affect low
* level driver (e.g. assoc/disassoc status, erp parameters).
* This function should not be used if no BSS has been set, unless
* for association indication. The @changed parameter indicates which
* of the bss parameters has changed when a call is made.
* of the bss parameters has changed when a call is made. The callback
* can sleep.
*
* @prepare_multicast: Prepare for multicast filter configuration.
* This callback is optional, and its return value is passed
* to configure_filter(). This callback must be atomic.
*
* @configure_filter: Configure the device's RX filter.
* See the section "Frame filtering" for more information.
* This callback must be implemented.
* This callback must be implemented and can sleep.
*
* @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
* must be set or cleared for a given STA. Must be atomic.
*
* @set_key: See the section "Hardware crypto acceleration"
* This callback can sleep, and is only called between add_interface
* and remove_interface calls, i.e. while the given virtual interface
* This callback is only called between add_interface and
* remove_interface calls, i.e. while the given virtual interface
* is enabled.
* Returns a negative error code if the key can't be added.
* The callback can sleep.
*
* @update_tkip_key: See the section "Hardware crypto acceleration"
* This callback will be called in the context of Rx. Called for drivers
* which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
* The callback can sleep.
*
* @hw_scan: Ask the hardware to service the scan request, no need to start
* the scan state machine in stack. The scan must honour the channel
Expand All @@ -1457,21 +1460,28 @@ enum ieee80211_ampdu_mlme_action {
* When the scan finishes, ieee80211_scan_completed() must be called;
* note that it also must be called when the scan cannot finish due to
* any error unless this callback returned a negative error code.
* The callback can sleep.
*
* @sw_scan_start: Notifier function that is called just before a software scan
* is started. Can be NULL, if the driver doesn't need this notification.
* The callback can sleep.
*
* @sw_scan_complete: Notifier function that is called just after a software scan
* finished. Can be NULL, if the driver doesn't need this notification.
* @sw_scan_complete: Notifier function that is called just after a
* software scan finished. Can be NULL, if the driver doesn't need
* this notification.
* The callback can sleep.
*
* @get_stats: Return low-level statistics.
* Returns zero if statistics are available.
* The callback can sleep.
*
* @get_tkip_seq: If your device implements TKIP encryption in hardware this
* callback should be provided to read the TKIP transmit IVs (both IV32
* and IV16) for the given key from hardware.
* The callback must be atomic.
*
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
* The callback can sleep.
*
* @sta_notify: Notifies low level driver about addition, removal or power
* state transition of an associated station, AP, IBSS/WDS/mesh peer etc.
Expand All @@ -1480,30 +1490,36 @@ enum ieee80211_ampdu_mlme_action {
* @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
* bursting) for a hardware TX queue.
* Returns a negative error code on failure.
* The callback can sleep.
*
* @get_tx_stats: Get statistics of the current TX queue status. This is used
* to get number of currently queued packets (queue length), maximum queue
* size (limit), and total number of packets sent using each TX queue
* (count). The 'stats' pointer points to an array that has hw->queues
* items.
* The callback must be atomic.
*
* @get_tsf: Get the current TSF timer value from firmware/hardware. Currently,
* this is only used for IBSS mode BSSID merging and debugging. Is not a
* required function.
* The callback can sleep.
*
* @set_tsf: Set the TSF timer to the specified value in the firmware/hardware.
* Currently, this is only used for IBSS mode debugging. Is not a
* required function.
* The callback can sleep.
*
* @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize
* with other STAs in the IBSS. This is only used in IBSS mode. This
* function is optional if the firmware/hardware takes full care of
* TSF synchronization.
* The callback can sleep.
*
* @tx_last_beacon: Determine whether the last IBSS beacon was sent by us.
* This is needed only for IBSS mode and the result of this function is
* used to determine whether to reply to Probe Requests.
* Returns non-zero if this device sent the last beacon.
* The callback can sleep.
*
* @ampdu_action: Perform a certain A-MPDU action
* The RA/TID combination determines the destination and TID we want
Expand All @@ -1512,16 +1528,19 @@ enum ieee80211_ampdu_mlme_action {
* is the first frame we expect to perform the action on. Notice
* that TX/RX_STOP can pass NULL for this parameter.
* Returns a negative error code on failure.
* The callback must be atomic.
*
* @rfkill_poll: Poll rfkill hardware state. If you need this, you also
* need to set wiphy->rfkill_poll to %true before registration,
* and need to call wiphy_rfkill_set_hw_state() in the callback.
* The callback can sleep.
*
* @testmode_cmd: Implement a cfg80211 test mode command.
* The callback can sleep.
*
* @flush: Flush all pending frames from the hardware queue, making sure
* that the hardware queues are empty. If the parameter @drop is set
* to %true, pending frames may be dropped.
* to %true, pending frames may be dropped. The callback can sleep.
*/
struct ieee80211_ops {
int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
Expand Down
60 changes: 56 additions & 4 deletions net/mac80211/driver-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ static inline int drv_start(struct ieee80211_local *local)
{
int ret;

might_sleep();

local->started = true;
smp_mb();
ret = local->ops->start(&local->hw);
Expand All @@ -23,6 +25,8 @@ static inline int drv_start(struct ieee80211_local *local)

static inline void drv_stop(struct ieee80211_local *local)
{
might_sleep();

local->ops->stop(&local->hw);
trace_drv_stop(local);

Expand All @@ -38,21 +42,31 @@ static inline void drv_stop(struct ieee80211_local *local)
static inline int drv_add_interface(struct ieee80211_local *local,
struct ieee80211_vif *vif)
{
int ret = local->ops->add_interface(&local->hw, vif);
int ret;

might_sleep();

ret = local->ops->add_interface(&local->hw, vif);
trace_drv_add_interface(local, vif_to_sdata(vif), ret);
return ret;
}

static inline void drv_remove_interface(struct ieee80211_local *local,
struct ieee80211_vif *vif)
{
might_sleep();

local->ops->remove_interface(&local->hw, vif);
trace_drv_remove_interface(local, vif_to_sdata(vif));
}

static inline int drv_config(struct ieee80211_local *local, u32 changed)
{
int ret = local->ops->config(&local->hw, changed);
int ret;

might_sleep();

ret = local->ops->config(&local->hw, changed);
trace_drv_config(local, changed, ret);
return ret;
}
Expand All @@ -62,6 +76,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
struct ieee80211_bss_conf *info,
u32 changed)
{
might_sleep();

if (local->ops->bss_info_changed)
local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
trace_drv_bss_info_changed(local, sdata, info, changed);
Expand Down Expand Up @@ -111,7 +127,11 @@ static inline int drv_set_key(struct ieee80211_local *local,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
int ret;

might_sleep();

ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
trace_drv_set_key(local, cmd, sdata, sta, key, ret);
return ret;
}
Expand All @@ -121,6 +141,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
const u8 *address, u32 iv32,
u16 *phase1key)
{
might_sleep();

if (local->ops->update_tkip_key)
local->ops->update_tkip_key(&local->hw, conf, address,
iv32, phase1key);
Expand All @@ -130,20 +152,28 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
static inline int drv_hw_scan(struct ieee80211_local *local,
struct cfg80211_scan_request *req)
{
int ret = local->ops->hw_scan(&local->hw, req);
int ret;

might_sleep();

ret = local->ops->hw_scan(&local->hw, req);
trace_drv_hw_scan(local, req, ret);
return ret;
}

static inline void drv_sw_scan_start(struct ieee80211_local *local)
{
might_sleep();

if (local->ops->sw_scan_start)
local->ops->sw_scan_start(&local->hw);
trace_drv_sw_scan_start(local);
}

static inline void drv_sw_scan_complete(struct ieee80211_local *local)
{
might_sleep();

if (local->ops->sw_scan_complete)
local->ops->sw_scan_complete(&local->hw);
trace_drv_sw_scan_complete(local);
Expand All @@ -154,6 +184,8 @@ static inline int drv_get_stats(struct ieee80211_local *local,
{
int ret = -EOPNOTSUPP;

might_sleep();

if (local->ops->get_stats)
ret = local->ops->get_stats(&local->hw, stats);
trace_drv_get_stats(local, stats, ret);
Expand All @@ -173,6 +205,9 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local,
u32 value)
{
int ret = 0;

might_sleep();

if (local->ops->set_rts_threshold)
ret = local->ops->set_rts_threshold(&local->hw, value);
trace_drv_set_rts_threshold(local, value, ret);
Expand All @@ -193,6 +228,9 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
int ret = -EOPNOTSUPP;

might_sleep();

if (local->ops->conf_tx)
ret = local->ops->conf_tx(&local->hw, queue, params);
trace_drv_conf_tx(local, queue, params, ret);
Expand All @@ -210,6 +248,9 @@ static inline int drv_get_tx_stats(struct ieee80211_local *local,
static inline u64 drv_get_tsf(struct ieee80211_local *local)
{
u64 ret = -1ULL;

might_sleep();

if (local->ops->get_tsf)
ret = local->ops->get_tsf(&local->hw);
trace_drv_get_tsf(local, ret);
Expand All @@ -218,13 +259,17 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local)

static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
{
might_sleep();

if (local->ops->set_tsf)
local->ops->set_tsf(&local->hw, tsf);
trace_drv_set_tsf(local, tsf);
}

static inline void drv_reset_tsf(struct ieee80211_local *local)
{
might_sleep();

if (local->ops->reset_tsf)
local->ops->reset_tsf(&local->hw);
trace_drv_reset_tsf(local);
Expand All @@ -233,6 +278,9 @@ static inline void drv_reset_tsf(struct ieee80211_local *local)
static inline int drv_tx_last_beacon(struct ieee80211_local *local)
{
int ret = 1;

might_sleep();

if (local->ops->tx_last_beacon)
ret = local->ops->tx_last_beacon(&local->hw);
trace_drv_tx_last_beacon(local, ret);
Expand All @@ -256,12 +304,16 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,

static inline void drv_rfkill_poll(struct ieee80211_local *local)
{
might_sleep();

if (local->ops->rfkill_poll)
local->ops->rfkill_poll(&local->hw);
}

static inline void drv_flush(struct ieee80211_local *local, bool drop)
{
might_sleep();

trace_drv_flush(local, drop);
if (local->ops->flush)
local->ops->flush(&local->hw, drop);
Expand Down

0 comments on commit e1781ed

Please sign in to comment.