linux/drivers/net/wireless
Johannes Berg f0f74a0e65 iwlwifi: fix PS disable status race
iwlwifi internally needs to keep track of whether PS
is enabled in the firmware or not. To do this, it keeps
a bit in the status flags, called STATUS_POWER_PMI.

The code to set this bit looks as follows:

static int iwl_set_power(struct iwl_priv *priv, void *cmd)
{
	return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
				      sizeof(struct iwl_powertable_cmd),
				      cmd, NULL);
}

int iwl_power_update_mode(...)
{
	[...]
	if (final_mode != IWL_POWER_MODE_CAM)
		set_bit(STATUS_POWER_PMI, &priv->status);

	iwl_update_power_cmd(priv, &cmd, final_mode);
	cmd.keep_alive_beacons = 0;

	if (final_mode == IWL_POWER_INDEX_5)
		cmd.flags |= IWL_POWER_FAST_PD;

	ret = iwl_set_power(priv, &cmd);

	if (final_mode == IWL_POWER_MODE_CAM)
		clear_bit(STATUS_POWER_PMI, &priv->status);
	else
		set_bit(STATUS_POWER_PMI, &priv->status);

	if (priv->cfg->ops->lib->update_chain_flags && update_chains)
		priv->cfg->ops->lib->update_chain_flags(priv);
	[...]
}

Now, this bit really needs to track what the _firmware_
thinks, not what the driver thinks. Therefore, there is
a race condition here -- the driver sets the bit before
it knows that the async command sent to the card in the
iwl_set_power function has been processed. As a result,
the call to update_chain_flags() may think that the card
has been woken up (PMI bit cleared) while in reality it
hasn't processed the async POWER_TABLE_CMD yet.

This leads to bugs -- any commands the update_chain_flags
function sends can get stuck and subsequent commands also
fail.

The fix is almost trivial: since there's no reason to send
an async command here (in fact, there almost never should
be since many mac80211 callbacks can sleep) just make the
function wait for the card to process the command and then
return and clear the PMI bit.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Acked-by: Mohamed Abbas <mohamed.abbas@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2009-05-11 15:23:58 -04:00
..
ath ath9k: remove redundant AR9285 checks 2009-05-06 15:15:06 -04:00
b43 mac80211: unify config_interface and bss_info_changed 2009-05-06 15:14:36 -04:00
b43legacy mac80211: unify config_interface and bss_info_changed 2009-05-06 15:14:36 -04:00
hostap wireless: remove some (bogus?) 'may be used uninitialized' warnings 2009-04-24 15:41:41 -04:00
ipw2x00 Wireless: remove driver_data direct access of struct device 2009-05-06 15:15:01 -04:00
iwlwifi iwlwifi: fix PS disable status race 2009-05-11 15:23:58 -04:00
libertas libertas: fix format warning 2009-04-24 15:41:37 -04:00
libertas_tf mac80211: unify config_interface and bss_info_changed 2009-05-06 15:14:36 -04:00
orinoco orinoco: correct timeout logic in __orinoco_hw_set_tkip_key() 2009-04-16 10:39:17 -04:00
p54 p54: call p54_wake_free_queues on every p54_free_skb and p54_rx_frame_sent 2009-05-06 15:15:05 -04:00
prism54 dma-mapping: replace all DMA_32BIT_MASK macro with DMA_BIT_MASK(32) 2009-04-07 08:31:11 -07:00
rt2x00 rt2x00: Fix chipset detection for rt73usb 2009-05-11 15:23:56 -04:00
rtl818x mac80211: unify config_interface and bss_info_changed 2009-05-06 15:14:36 -04:00
wl12xx wireless: WL12XX should depend on GENERIC_HARDIRQS 2009-05-11 15:23:54 -04:00
zd1211rw mac80211: unify config_interface and bss_info_changed 2009-05-06 15:14:36 -04:00
adm8211.c mac80211: unify config_interface and bss_info_changed 2009-05-06 15:14:36 -04:00
adm8211.h
airo_cs.c
airo.c airo: queue SIOCSIWAUTH-requested auth mode change for next commit 2009-04-16 10:39:10 -04:00
airo.h
arlan-main.c Merge branch 'linus' into percpu-cpumask-x86-for-linus-2 2009-03-28 04:26:01 +01:00
arlan-proc.c
arlan.h
at76c50x-usb.c mac80211: unify config_interface and bss_info_changed 2009-05-06 15:14:36 -04:00
at76c50x-usb.h
atmel_cs.c Wireless: remove driver_data direct access of struct device 2009-05-06 15:15:01 -04:00
atmel_pci.c
atmel.c atmel: fix netdev ops conversion 2009-04-21 02:08:51 -07:00
atmel.h
i82586.h
i82593.h
Kconfig wl12xx: add driver 2009-05-06 15:14:54 -04:00
mac80211_hwsim.c mac80211: move HT operation mode BSS info 2009-05-11 15:23:57 -04:00
Makefile wl12xx: add driver 2009-05-06 15:14:54 -04:00
mwl8k.c mac80211: move HT operation mode BSS info 2009-05-11 15:23:57 -04:00
netwave_cs.c
ray_cs.c
ray_cs.h
rayctl.h
rndis_wlan.c rndis_wlan: fix initialization order for workqueue&workers 2009-04-28 15:59:48 -04:00
strip.c
wavelan_cs.c
wavelan_cs.h
wavelan_cs.p.h
wavelan.c wireless: convert wavelan to net_device_ops 2009-03-27 00:46:46 -07:00
wavelan.h
wavelan.p.h wireless: convert wavelan to net_device_ops 2009-03-27 00:46:46 -07:00
wl3501_cs.c
wl3501.h
zd1201.c wireless: remove duplicated .ndo_set_mac_address 2009-03-29 13:52:21 -07:00
zd1201.h