From f10723841e624c0726c70356b31d91befed01dd6 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 3 Sep 2012 15:49:09 -0400 Subject: libertas sdio: fix suspend when interface is down When the interface is down, the hardware is powered off. However, the suspend handler currently tries to send host sleep commands (when wakeup params are set) in this configuration, causing a system hang when going into suspend (the commands will never complete). Avoid this by detecting this situation and simply returning from the suspend handler without doing anything special. Signed-off-by: Daniel Drake Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net/wireless/libertas') diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index e970897f6ab5..4cb234349fbf 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -1326,6 +1326,11 @@ static int if_sdio_suspend(struct device *dev) mmc_pm_flag_t flags = sdio_get_host_pm_caps(func); + /* If we're powered off anyway, just let the mmc layer remove the + * card. */ + if (!lbs_iface_active(card->priv)) + return -ENOSYS; + dev_info(dev, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), flags); -- cgit v1.2.3 From 871fc09f1c8a9c0652afa7c673ae401fdb3f4aeb Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 11 Sep 2012 11:38:11 -0400 Subject: libertas: set mac control synchronously during init CMD_MAC_CONTROL is currently sent async to the firmware, and is sent from the lbs_setup_firmware() path during device init. This means that device init can complete with commands pending, and the if_sdio driver will sometimes power down the device (after init) with this command still pending. This was causing an occasional spurious command timeout after init, leading to a device reset. Fix this by making CMD_MAC_CONTROL synchronous when called from the lbs_setup_firmware() path. Signed-off-by: Daniel Drake Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 16 ++++++++++++++++ drivers/net/wireless/libertas/cmd.h | 1 + drivers/net/wireless/libertas/main.c | 4 +++- 3 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/libertas') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 26e68326710b..aaa297315c47 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1159,6 +1159,22 @@ void lbs_set_mac_control(struct lbs_private *priv) lbs_deb_leave(LBS_DEB_CMD); } +int lbs_set_mac_control_sync(struct lbs_private *priv) +{ + struct cmd_ds_mac_control cmd; + int ret = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(priv->mac_control); + cmd.reserved = 0; + ret = lbs_cmd_with_response(priv, CMD_MAC_CONTROL, &cmd); + + lbs_deb_leave(LBS_DEB_CMD); + return ret; +} + /** * lbs_allocate_cmd_buffer - allocates the command buffer and links * it to command free queue diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index ab07608e13d0..4279e8ab95f2 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -96,6 +96,7 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv); int lbs_set_radio(struct lbs_private *priv, u8 preamble, u8 radio_on); void lbs_set_mac_control(struct lbs_private *priv); +int lbs_set_mac_control_sync(struct lbs_private *priv); int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, s16 *maxlevel); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index fe1ea43c5149..0c02f0483d1f 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -682,8 +682,10 @@ static int lbs_setup_firmware(struct lbs_private *priv) /* Send cmd to FW to enable 11D function */ ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_11D_ENABLE, 1); + if (ret) + goto done; - lbs_set_mac_control(priv); + ret = lbs_set_mac_control_sync(priv); done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); return ret; -- cgit v1.2.3