usb: dwc3: rockchip: fix possible circular deadlock
[firefly-linux-kernel-4.4.55.git] / drivers / thermal / thermal_core.c
index 3d5f8f432b5b1f750b95ce741bc1066418bb4fb0..b26e6f7a050c3d126422c5871350d46dd64f3f04 100644 (file)
@@ -520,6 +520,47 @@ exit:
 }
 EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
 
+static void thermal_zone_set_trips(struct thermal_zone_device *tz)
+{
+       int low = -INT_MAX;
+       int high = INT_MAX;
+       int trip_temp, hysteresis;
+       int temp = tz->temperature;
+       int i, ret;
+
+       if (!tz->ops->set_trips)
+               return;
+
+       for (i = 0; i < tz->trips; i++) {
+               int trip_low;
+
+               tz->ops->get_trip_temp(tz, i, &trip_temp);
+               tz->ops->get_trip_hyst(tz, i, &hysteresis);
+
+               trip_low = trip_temp - hysteresis;
+
+               if (trip_low < temp && trip_low > low)
+                       low = trip_low;
+
+               if (trip_temp > temp && trip_temp < high)
+                       high = trip_temp;
+       }
+
+       /* No need to change trip points */
+       if (tz->prev_low_trip == low && tz->prev_high_trip == high)
+               return;
+
+       tz->prev_low_trip = low;
+       tz->prev_high_trip = high;
+
+       dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
+                       low, high);
+
+       ret = tz->ops->set_trips(tz, low, high);
+       if (ret)
+               dev_err(&tz->device, "Failed to set trips: %d\n", ret);
+}
+
 static void update_temperature(struct thermal_zone_device *tz)
 {
        int temp, ret;
@@ -569,6 +610,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
 
        update_temperature(tz);
 
+       thermal_zone_set_trips(tz);
+
        for (count = 0; count < tz->trips; count++)
                handle_thermal_trip(tz, count);
 }
@@ -688,7 +731,7 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
 {
        struct thermal_zone_device *tz = to_thermal_zone(dev);
        int trip, ret;
-       unsigned long temperature;
+       int temperature;
 
        if (!tz->ops->set_trip_temp)
                return -EPERM;
@@ -696,11 +739,14 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
        if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
                return -EINVAL;
 
-       if (kstrtoul(buf, 10, &temperature))
+       if (kstrtoint(buf, 10, &temperature))
                return -EINVAL;
 
        ret = tz->ops->set_trip_temp(tz, trip, temperature);
 
+       if (!ret)
+               thermal_zone_set_trips(tz);
+
        return ret ? ret : count;
 }
 
@@ -750,6 +796,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
         */
        ret = tz->ops->set_trip_hyst(tz, trip, temperature);
 
+       if (!ret)
+               thermal_zone_set_trips(tz);
+
        return ret ? ret : count;
 }
 
@@ -895,9 +944,9 @@ emul_temp_store(struct device *dev, struct device_attribute *attr,
 {
        struct thermal_zone_device *tz = to_thermal_zone(dev);
        int ret = 0;
-       unsigned long temperature;
+       int temperature;
 
-       if (kstrtoul(buf, 10, &temperature))
+       if (kstrtoint(buf, 10, &temperature))
                return -EINVAL;
 
        if (!tz->ops->set_emul_temp) {
@@ -955,7 +1004,7 @@ static DEVICE_ATTR(sustainable_power, S_IWUSR | S_IRUGO, sustainable_power_show,
        struct thermal_zone_device *tz = to_thermal_zone(dev);          \
                                                                        \
        if (tz->tzp)                                                    \
-               return sprintf(buf, "%u\n", tz->tzp->name);             \
+               return sprintf(buf, "%d\n", tz->tzp->name);             \
        else                                                            \
                return -EIO;                                            \
        }                                                               \
@@ -1839,6 +1888,9 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
        tz->trips = trips;
        tz->passive_delay = passive_delay;
        tz->polling_delay = polling_delay;
+       tz->prev_low_trip = INT_MAX;
+       tz->prev_high_trip = -INT_MAX;
+
        /* A new thermal zone needs to be updated anyway. */
        atomic_set(&tz->need_update, 1);