ath6kl: power down hardware when interface is down
authorKalle Valo <kvalo@qca.qualcomm.com>
Sun, 30 Oct 2011 19:16:15 +0000 (21:16 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Fri, 11 Nov 2011 10:58:59 +0000 (12:58 +0200)
The benefit from this is that user space can control hardware's power state
by putting interface up and down. This is handy if firmware gets to some
weird state.

The downside will be that putting interface up takes a bit longer,
I was measuring ~500 ms during interface up.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/bmi.h
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/htc.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c

index 5a4c24d9c2da7d70866c696e06d18800769f6aa4..a962fe4c6b7e43d612b8cda710df01239a55305d 100644 (file)
@@ -670,6 +670,11 @@ int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
        return ret;
 }
 
+void ath6kl_bmi_reset(struct ath6kl *ar)
+{
+       ar->bmi.done_sent = false;
+}
+
 int ath6kl_bmi_init(struct ath6kl *ar)
 {
        ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
index 96851d5df24b604e6f6079728012a8c0dc7ef1cb..009e8f650ab1dc7f2f5de82c78fd9930074d846d 100644 (file)
@@ -230,6 +230,8 @@ struct ath6kl_bmi_target_info {
 
 int ath6kl_bmi_init(struct ath6kl *ar);
 void ath6kl_bmi_cleanup(struct ath6kl *ar);
+void ath6kl_bmi_reset(struct ath6kl *ar);
+
 int ath6kl_bmi_done(struct ath6kl *ar);
 int ath6kl_bmi_get_target_info(struct ath6kl *ar,
                               struct ath6kl_bmi_target_info *targ_info);
index 5ac415ee924377edf8a41fd35b491d4de0f80d11..1ac0dd1a035bb3852af5876160e08463770218cd 100644 (file)
@@ -447,6 +447,7 @@ enum ath6kl_dev_state {
        DESTROY_IN_PROGRESS,
        SKIP_SCAN,
        ROAM_TBL_PEND,
+       FIRST_BOOT,
 };
 
 struct ath6kl {
@@ -662,4 +663,7 @@ void ath6kl_deinit_if_data(struct ath6kl_vif *vif);
 void ath6kl_core_free(struct ath6kl *ar);
 struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
 void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready);
+int ath6kl_init_hw_start(struct ath6kl *ar);
+int ath6kl_init_hw_stop(struct ath6kl *ar);
+
 #endif /* CORE_H */
index 04b4070240aa087717010165d5351d0730709185..99220d437670fb78c7d5601524f9d7734cf61076 100644 (file)
@@ -2622,6 +2622,9 @@ int ath6kl_htc_start(struct htc_target *target)
        struct htc_packet *packet;
        int status;
 
+       memset(&target->dev->irq_proc_reg, 0,
+              sizeof(target->dev->irq_proc_reg));
+
        /* Disable interrupts at the chip level */
        ath6kl_hif_disable_intrs(target->dev);
 
index 2ee6a5eced651bcd2c8b1bbb1bb65f56d6d8e039..237b73c6f42aca89c7a5cb50bf8825ea0868497b 100644 (file)
@@ -1421,11 +1421,13 @@ static int ath6kl_init_hw_params(struct ath6kl *ar)
        return 0;
 }
 
-static int ath6kl_hw_start(struct ath6kl *ar)
+int ath6kl_init_hw_start(struct ath6kl *ar)
 {
        long timeleft;
        int ret, i;
 
+       ath6kl_dbg(ATH6KL_DBG_BOOT, "hw start\n");
+
        ret = ath6kl_hif_power_on(ar);
        if (ret)
                return ret;
@@ -1517,6 +1519,25 @@ err_power_off:
        return ret;
 }
 
+int ath6kl_init_hw_stop(struct ath6kl *ar)
+{
+       int ret;
+
+       ath6kl_dbg(ATH6KL_DBG_BOOT, "hw stop\n");
+
+       ath6kl_htc_stop(ar->htc_target);
+
+       ath6kl_hif_stop(ar);
+
+       ath6kl_bmi_reset(ar);
+
+       ret = ath6kl_hif_power_off(ar);
+       if (ret)
+               ath6kl_warn("failed to power off hif: %d\n", ret);
+
+       return 0;
+}
+
 int ath6kl_core_init(struct ath6kl *ar)
 {
        struct ath6kl_bmi_target_info targ_info;
@@ -1629,9 +1650,11 @@ int ath6kl_core_init(struct ath6kl *ar)
        ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
                            WIPHY_FLAG_HAVE_AP_SME;
 
-       ret = ath6kl_hw_start(ar);
+       set_bit(FIRST_BOOT, &ar->flag);
+
+       ret = ath6kl_init_hw_start(ar);
        if (ret) {
-               ath6kl_err("Failed to boot hardware: %d\n", ret);
+               ath6kl_err("Failed to start hardware: %d\n", ret);
                goto err_rxbuf_cleanup;
        }
 
@@ -1641,6 +1664,12 @@ int ath6kl_core_init(struct ath6kl *ar)
         */
        memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
 
+       ret = ath6kl_init_hw_stop(ar);
+       if (ret) {
+               ath6kl_err("Failed to stop hardware: %d\n", ret);
+               goto err_htc_cleanup;
+       }
+
        return ret;
 
 err_rxbuf_cleanup:
index 3b2a7e8a24b9cea3674cb398e59695131354ad99..717ed22abc31d576375cca3d707e304f1dc6797b 100644 (file)
@@ -673,10 +673,12 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
        set_bit(WMI_READY, &ar->flag);
        wake_up(&ar->event_wq);
 
-       ath6kl_info("hw %s fw %s%s\n",
-                   get_hw_id_string(ar->wiphy->hw_version),
-                   ar->wiphy->fw_version,
-                   test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
+       if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
+               ath6kl_info("hw %s fw %s%s\n",
+                           get_hw_id_string(ar->wiphy->hw_version),
+                           ar->wiphy->fw_version,
+                           test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
+       }
 }
 
 void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
@@ -1112,6 +1114,12 @@ struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar)
 static int ath6kl_open(struct net_device *dev)
 {
        struct ath6kl_vif *vif = netdev_priv(dev);
+       int ret;
+
+       /* FIXME: how to handle multi vif support? */
+       ret = ath6kl_init_hw_start(vif->ar);
+       if (ret)
+               return ret;
 
        set_bit(WLAN_ENABLED, &vif->flags);
 
@@ -1128,6 +1136,7 @@ static int ath6kl_close(struct net_device *dev)
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
+       int ret;
 
        netif_stop_queue(dev);
 
@@ -1143,6 +1152,11 @@ static int ath6kl_close(struct net_device *dev)
 
        ath6kl_cfg80211_scan_complete_event(vif, -ECANCELED);
 
+       /* FIXME: how to handle multi vif support? */
+       ret = ath6kl_init_hw_stop(ar);
+       if (ret)
+               return ret;
+
        return 0;
 }