iwlwifi: mvm: avoid panics with thermal device usage
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 28 Feb 2016 08:15:08 +0000 (10:15 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Sun, 6 Mar 2016 20:01:32 +0000 (22:01 +0200)
Thermal zone device registration can fail, and in this case
we don't want to remove WiFi functionality. This is why the
thermal zone registration function is void, and the flows
continue even if the thermal zone device registration failed.
Same applies for the cooling device.

This means that we at least need to remember that the thermal
zone device didn't register properly and take the minimal
precautions to avoid panic'ing when we access it.

This was missing.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/tt.c

index ab410b4659f3ba7fc8114c51447c56ab624acd0d..b869db9afc52ea5de222141144be10c567b155b1 100644 (file)
@@ -1575,7 +1575,6 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
 int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp);
 void iwl_mvm_ct_kill_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb);
 int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm);
-int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm);
 int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget);
 
 /* Location Aware Regulatory */
index 999bcb898be884e9ff30b317b3aba1d7d2a108b0..0a02e9835d6bfce7cacdb564648afd7c9846f9ff 100644 (file)
@@ -211,10 +211,14 @@ void iwl_mvm_temp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
         * the firmware and hence to take the mutex.
         * Avoid the deadlock by unlocking the mutex here.
         */
-       mutex_unlock(&mvm->mutex);
-       thermal_notify_framework(mvm->tz_device.tzone,
-                                mvm->tz_device.fw_trips_index[ths_crossed]);
-       mutex_lock(&mvm->mutex);
+       if (mvm->tz_device.tzone) {
+               struct iwl_mvm_thermal_device *tz_dev = &mvm->tz_device;
+
+               mutex_unlock(&mvm->mutex);
+               thermal_notify_framework(tz_dev->tzone,
+                                        tz_dev->fw_trips_index[ths_crossed]);
+               mutex_lock(&mvm->mutex);
+       }
 #endif /* CONFIG_THERMAL */
 }
 
@@ -520,16 +524,20 @@ int iwl_mvm_send_temp_report_ths_cmd(struct iwl_mvm *mvm)
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (!mvm->tz_device.tzone)
+               return -EINVAL;
+
        /* The driver holds array of temperature trips that are unsorted
         * and uncompressed, the FW should get it compressed and sorted
         */
 
        /* compress temp_trips to cmd array, remove uninitialized values*/
-       for (i = 0; i < IWL_MAX_DTS_TRIPS; i++)
+       for (i = 0; i < IWL_MAX_DTS_TRIPS; i++) {
                if (mvm->tz_device.temp_trips[i] != S16_MIN) {
                        cmd.thresholds[idx++] =
                                cpu_to_le16(mvm->tz_device.temp_trips[i]);
                }
+       }
        cmd.num_temps = cpu_to_le32(idx);
 
        if (!idx)
@@ -696,6 +704,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
                IWL_DEBUG_TEMP(mvm,
                               "Failed to register to thermal zone (err = %ld)\n",
                               PTR_ERR(mvm->tz_device.tzone));
+               mvm->tz_device.tzone = NULL;
                return;
        }
 
@@ -750,6 +759,10 @@ int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 budget)
                return ret;
        }
 
+       /* can happen if the registration failed */
+       if (!mvm->cooling_dev.cdev)
+               return -EINVAL;
+
        if (op == CTDP_CMD_OPERATION_START)
                mvm->cooling_dev.cur_state = budget;
 
@@ -812,15 +825,12 @@ static struct thermal_cooling_device_ops tcooling_ops = {
        .set_cur_state = iwl_mvm_tcool_set_cur_state,
 };
 
-int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
+static void iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
 {
        char name[] = "iwlwifi";
 
-       if (!iwl_mvm_is_ctdp_supported(mvm)) {
-               mvm->cooling_dev.cdev = NULL;
-
-               return 0;
-       }
+       if (!iwl_mvm_is_ctdp_supported(mvm))
+               return;
 
        BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
 
@@ -833,34 +843,29 @@ int iwl_mvm_cooling_device_register(struct iwl_mvm *mvm)
                IWL_DEBUG_TEMP(mvm,
                               "Failed to register to cooling device (err = %ld)\n",
                               PTR_ERR(mvm->cooling_dev.cdev));
-               return PTR_ERR(mvm->cooling_dev.cdev);
+               mvm->cooling_dev.cdev = NULL;
+               return;
        }
-
-       return 0;
 }
 
 static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
 {
-       if (!iwl_mvm_is_tt_in_fw(mvm))
+       if (!iwl_mvm_is_tt_in_fw(mvm) || !mvm->tz_device.tzone)
                return;
 
-       if (mvm->tz_device.tzone) {
-               IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
-               thermal_zone_device_unregister(mvm->tz_device.tzone);
-               mvm->tz_device.tzone = NULL;
-       }
+       IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
+       thermal_zone_device_unregister(mvm->tz_device.tzone);
+       mvm->tz_device.tzone = NULL;
 }
 
 static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
 {
-       if (!iwl_mvm_is_ctdp_supported(mvm))
+       if (!iwl_mvm_is_ctdp_supported(mvm) || !mvm->cooling_dev.cdev)
                return;
 
-       if (mvm->cooling_dev.cdev) {
-               IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
-               thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
-               mvm->cooling_dev.cdev = NULL;
-       }
+       IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
+       thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
+       mvm->cooling_dev.cdev = NULL;
 }
 #endif /* CONFIG_THERMAL */