iwmc3200wifi: CT kill support
authorSamuel Ortiz <sameo@linux.intel.com>
Fri, 16 Oct 2009 05:18:48 +0000 (13:18 +0800)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 27 Oct 2009 20:48:24 +0000 (16:48 -0400)
We set the initial CT (Temperature control) value to 110 degrees.
If the chip goes over that threshold, we hard block the device which will turn
it down. At the same time we schedule a 30 seconds delayed work that unblock
the device (and userspace is supposed to bring it back up), hoping that the
chip will have cooled down by then...

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/iwmc3200wifi/commands.c
drivers/net/wireless/iwmc3200wifi/commands.h
drivers/net/wireless/iwmc3200wifi/fw.c
drivers/net/wireless/iwmc3200wifi/iwm.h
drivers/net/wireless/iwmc3200wifi/lmac.h
drivers/net/wireless/iwmc3200wifi/main.c
drivers/net/wireless/iwmc3200wifi/netdev.c
drivers/net/wireless/iwmc3200wifi/rx.c

index 23b52fa2605ff93256e52565adf839bcd4069944..aeea909992fe01f1b59856f9516db50830d06eb7 100644 (file)
@@ -274,6 +274,17 @@ int iwm_send_calib_results(struct iwm_priv *iwm)
        return ret;
 }
 
+int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit)
+{
+       struct iwm_ct_kill_cfg_cmd cmd;
+
+       cmd.entry_threshold = entry;
+       cmd.exit_threshold = exit;
+
+       return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd,
+                                        sizeof(struct iwm_ct_kill_cfg_cmd), 0);
+}
+
 int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp)
 {
        struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
index 4e183be1f26272cfe526781b50d199855619abe9..e486f8e89378ef9c60b7f685ed6ab5af0392973b 100644 (file)
@@ -396,6 +396,7 @@ int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
 int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested);
 int iwm_send_calib_results(struct iwm_priv *iwm);
 int iwm_store_rxiq_calib_result(struct iwm_priv *iwm);
+int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit);
 
 /* UMAC commands */
 int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
index 6b0bcad758ca03c5db8796557a6aff8d90b50c89..f02d571b0a1367f4d487471a2f14d4d0cb70eb03 100644 (file)
@@ -398,6 +398,8 @@ int iwm_load_fw(struct iwm_priv *iwm)
        iwm_send_prio_table(iwm);
        iwm_send_calib_results(iwm);
        iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
+       iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry,
+                            iwm->conf.ct_kill_exit);
 
        return 0;
 
index 1b02a4e2a1aca8d14aa9cbcde2067ff4a207990d..fe0ab80994dd917625e9ff6562e62bb43b3a13cf 100644 (file)
@@ -65,6 +65,8 @@ struct iwm_conf {
        u32 sdio_ior_timeout;
        unsigned long calib_map;
        unsigned long expected_calib_map;
+       u8 ct_kill_entry;
+       u8 ct_kill_exit;
        bool reset_on_fatal_err;
        bool auto_connect;
        bool wimax_not_present;
@@ -276,6 +278,7 @@ struct iwm_priv {
        struct iw_statistics wstats;
        struct delayed_work stats_request;
        struct delayed_work disconnect;
+       struct delayed_work ct_kill_delay;
 
        struct iwm_debugfs dbg;
 
index 6c1a14c4480f7deb654a979fc4455e4ebbb6e0f6..a3a79b5e28985e3485ac08cb20c3afe1c4343193 100644 (file)
@@ -187,6 +187,14 @@ struct iwm_coex_prio_table_cmd {
                                     COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \
                                     COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK)
 
+/* CT kill config command */
+struct iwm_ct_kill_cfg_cmd {
+       u32 exit_threshold;
+       u32 reserved;
+       u32 entry_threshold;
+} __attribute__ ((packed));
+
+
 /* LMAC OP CODES */
 #define REPLY_PAD                      0x0
 #define REPLY_ALIVE                    0x1
index 170f33706490dbf4c8af441eef00184d27644259..3147fe7b5130734adb188c24d9169a4c20f72b5f 100644 (file)
@@ -63,6 +63,8 @@ static struct iwm_conf def_iwm_conf = {
                                  BIT(PHY_CALIBRATE_TX_IQ_CMD)  |
                                  BIT(PHY_CALIBRATE_RX_IQ_CMD)  |
                                  BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD),
+       .ct_kill_entry          = 110,
+       .ct_kill_exit           = 110,
        .reset_on_fatal_err     = 1,
        .auto_connect           = 1,
        .wimax_not_present      = 0,
@@ -133,6 +135,17 @@ static void iwm_disconnect_work(struct work_struct *work)
        cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL);
 }
 
+static void iwm_ct_kill_work(struct work_struct *work)
+{
+       struct iwm_priv *iwm =
+               container_of(work, struct iwm_priv, ct_kill_delay.work);
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
+
+       IWM_INFO(iwm, "CT kill delay timeout\n");
+
+       wiphy_rfkill_set_hw_state(wiphy, false);
+}
+
 static int __iwm_up(struct iwm_priv *iwm);
 static int __iwm_down(struct iwm_priv *iwm);
 
@@ -225,6 +238,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
        iwm->scan_id = 1;
        INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request);
        INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work);
+       INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work);
        INIT_WORK(&iwm->reset_worker, iwm_reset_worker);
        INIT_LIST_HEAD(&iwm->bss_list);
 
index 35ec006c2d2c31184d6526484d28d2e1c29764a4..4f8dbdd7b917b2e59e159dc2be3b942350875f54 100644 (file)
@@ -152,6 +152,7 @@ void iwm_if_free(struct iwm_priv *iwm)
        if (!iwm_to_ndev(iwm))
                return;
 
+       cancel_delayed_work_sync(&iwm->ct_kill_delay);
        free_netdev(iwm_to_ndev(iwm));
        iwm_priv_deinit(iwm);
        kfree(iwm->umac_profile);
index 40dbcbc16593b163e36cd7f3031cbb64187d904e..14a2a0b3d614e51b90b4c7d4c24ce6de87cb4772 100644 (file)
@@ -1078,6 +1078,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
        return 0;
 }
 
+#define CT_KILL_DELAY (30 * HZ)
 static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
                              unsigned long buf_size, struct iwm_wifi_cmd *cmd)
 {
@@ -1090,7 +1091,20 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
                 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
                 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
 
-       wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
+       if (flags & IWM_CARD_STATE_CTKILL_DISABLED) {
+               /*
+                * We got a CTKILL event: We bring the interface down in
+                * oder to cool the device down, and try to bring it up
+                * 30 seconds later. If it's still too hot, we'll go through
+                * this code path again.
+                */
+               cancel_delayed_work_sync(&iwm->ct_kill_delay);
+               schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY);
+       }
+
+       wiphy_rfkill_set_hw_state(wiphy, flags &
+                                 (IWM_CARD_STATE_HW_DISABLED |
+                                  IWM_CARD_STATE_CTKILL_DISABLED));
 
        return 0;
 }