0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include "priv.h"
0025
0026 #include <core/option.h>
0027 #include <subdev/pmu.h>
0028
0029 int
0030 nvkm_therm_temp_get(struct nvkm_therm *therm)
0031 {
0032 if (therm->func->temp_get)
0033 return therm->func->temp_get(therm);
0034 return -ENODEV;
0035 }
0036
0037 static int
0038 nvkm_therm_update_trip(struct nvkm_therm *therm)
0039 {
0040 struct nvbios_therm_trip_point *trip = therm->fan->bios.trip,
0041 *cur_trip = NULL,
0042 *last_trip = therm->last_trip;
0043 u8 temp = therm->func->temp_get(therm);
0044 u16 duty, i;
0045
0046
0047 cur_trip = NULL;
0048 for (i = 0; i < therm->fan->bios.nr_fan_trip; i++) {
0049 if (temp >= trip[i].temp)
0050 cur_trip = &trip[i];
0051 }
0052
0053
0054 if (last_trip && temp <= (last_trip->temp) &&
0055 temp > (last_trip->temp - last_trip->hysteresis))
0056 cur_trip = last_trip;
0057
0058 if (cur_trip) {
0059 duty = cur_trip->fan_duty;
0060 therm->last_trip = cur_trip;
0061 } else {
0062 duty = 0;
0063 therm->last_trip = NULL;
0064 }
0065
0066 return duty;
0067 }
0068
0069 static int
0070 nvkm_therm_compute_linear_duty(struct nvkm_therm *therm, u8 linear_min_temp,
0071 u8 linear_max_temp)
0072 {
0073 u8 temp = therm->func->temp_get(therm);
0074 u16 duty;
0075
0076
0077 if (temp < linear_min_temp)
0078 return therm->fan->bios.min_duty;
0079 else if (temp > linear_max_temp)
0080 return therm->fan->bios.max_duty;
0081
0082
0083 duty = (temp - linear_min_temp);
0084 duty *= (therm->fan->bios.max_duty - therm->fan->bios.min_duty);
0085 duty /= (linear_max_temp - linear_min_temp);
0086 duty += therm->fan->bios.min_duty;
0087 return duty;
0088 }
0089
0090 static int
0091 nvkm_therm_update_linear(struct nvkm_therm *therm)
0092 {
0093 u8 min = therm->fan->bios.linear_min_temp;
0094 u8 max = therm->fan->bios.linear_max_temp;
0095 return nvkm_therm_compute_linear_duty(therm, min, max);
0096 }
0097
0098 static int
0099 nvkm_therm_update_linear_fallback(struct nvkm_therm *therm)
0100 {
0101 u8 max = therm->bios_sensor.thrs_fan_boost.temp;
0102 return nvkm_therm_compute_linear_duty(therm, 30, max);
0103 }
0104
0105 static void
0106 nvkm_therm_update(struct nvkm_therm *therm, int mode)
0107 {
0108 struct nvkm_subdev *subdev = &therm->subdev;
0109 struct nvkm_timer *tmr = subdev->device->timer;
0110 unsigned long flags;
0111 bool immd = true;
0112 bool poll = true;
0113 int duty = -1;
0114
0115 spin_lock_irqsave(&therm->lock, flags);
0116 if (mode < 0)
0117 mode = therm->mode;
0118 therm->mode = mode;
0119
0120 switch (mode) {
0121 case NVKM_THERM_CTRL_MANUAL:
0122 nvkm_timer_alarm(tmr, 0, &therm->alarm);
0123 duty = nvkm_therm_fan_get(therm);
0124 if (duty < 0)
0125 duty = 100;
0126 poll = false;
0127 break;
0128 case NVKM_THERM_CTRL_AUTO:
0129 switch(therm->fan->bios.fan_mode) {
0130 case NVBIOS_THERM_FAN_TRIP:
0131 duty = nvkm_therm_update_trip(therm);
0132 break;
0133 case NVBIOS_THERM_FAN_LINEAR:
0134 duty = nvkm_therm_update_linear(therm);
0135 break;
0136 case NVBIOS_THERM_FAN_OTHER:
0137 if (therm->cstate) {
0138 duty = therm->cstate;
0139 poll = false;
0140 } else {
0141 duty = nvkm_therm_update_linear_fallback(therm);
0142 }
0143 break;
0144 }
0145 immd = false;
0146 break;
0147 case NVKM_THERM_CTRL_NONE:
0148 default:
0149 nvkm_timer_alarm(tmr, 0, &therm->alarm);
0150 poll = false;
0151 }
0152
0153 if (poll)
0154 nvkm_timer_alarm(tmr, 1000000000ULL, &therm->alarm);
0155 spin_unlock_irqrestore(&therm->lock, flags);
0156
0157 if (duty >= 0) {
0158 nvkm_debug(subdev, "FAN target request: %d%%\n", duty);
0159 nvkm_therm_fan_set(therm, immd, duty);
0160 }
0161 }
0162
0163 int
0164 nvkm_therm_cstate(struct nvkm_therm *therm, int fan, int dir)
0165 {
0166 struct nvkm_subdev *subdev = &therm->subdev;
0167 if (!dir || (dir < 0 && fan < therm->cstate) ||
0168 (dir > 0 && fan > therm->cstate)) {
0169 nvkm_debug(subdev, "default fan speed -> %d%%\n", fan);
0170 therm->cstate = fan;
0171 nvkm_therm_update(therm, -1);
0172 }
0173 return 0;
0174 }
0175
0176 static void
0177 nvkm_therm_alarm(struct nvkm_alarm *alarm)
0178 {
0179 struct nvkm_therm *therm =
0180 container_of(alarm, struct nvkm_therm, alarm);
0181 nvkm_therm_update(therm, -1);
0182 }
0183
0184 int
0185 nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode)
0186 {
0187 struct nvkm_subdev *subdev = &therm->subdev;
0188 struct nvkm_device *device = subdev->device;
0189 static const char *name[] = {
0190 "disabled",
0191 "manual",
0192 "automatic"
0193 };
0194
0195
0196 if ((mode >= ARRAY_SIZE(name)) ||
0197 (mode != NVKM_THERM_CTRL_NONE && nvkm_pmu_fan_controlled(device)))
0198 return -EINVAL;
0199
0200
0201
0202 if (mode == NVKM_THERM_CTRL_AUTO &&
0203 therm->func->temp_get(therm) < 0)
0204 return -EINVAL;
0205
0206 if (therm->mode == mode)
0207 return 0;
0208
0209 nvkm_debug(subdev, "fan management: %s\n", name[mode]);
0210 nvkm_therm_update(therm, mode);
0211 return 0;
0212 }
0213
0214 int
0215 nvkm_therm_attr_get(struct nvkm_therm *therm, enum nvkm_therm_attr_type type)
0216 {
0217 switch (type) {
0218 case NVKM_THERM_ATTR_FAN_MIN_DUTY:
0219 return therm->fan->bios.min_duty;
0220 case NVKM_THERM_ATTR_FAN_MAX_DUTY:
0221 return therm->fan->bios.max_duty;
0222 case NVKM_THERM_ATTR_FAN_MODE:
0223 return therm->mode;
0224 case NVKM_THERM_ATTR_THRS_FAN_BOOST:
0225 return therm->bios_sensor.thrs_fan_boost.temp;
0226 case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST:
0227 return therm->bios_sensor.thrs_fan_boost.hysteresis;
0228 case NVKM_THERM_ATTR_THRS_DOWN_CLK:
0229 return therm->bios_sensor.thrs_down_clock.temp;
0230 case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST:
0231 return therm->bios_sensor.thrs_down_clock.hysteresis;
0232 case NVKM_THERM_ATTR_THRS_CRITICAL:
0233 return therm->bios_sensor.thrs_critical.temp;
0234 case NVKM_THERM_ATTR_THRS_CRITICAL_HYST:
0235 return therm->bios_sensor.thrs_critical.hysteresis;
0236 case NVKM_THERM_ATTR_THRS_SHUTDOWN:
0237 return therm->bios_sensor.thrs_shutdown.temp;
0238 case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST:
0239 return therm->bios_sensor.thrs_shutdown.hysteresis;
0240 }
0241
0242 return -EINVAL;
0243 }
0244
0245 int
0246 nvkm_therm_attr_set(struct nvkm_therm *therm,
0247 enum nvkm_therm_attr_type type, int value)
0248 {
0249 switch (type) {
0250 case NVKM_THERM_ATTR_FAN_MIN_DUTY:
0251 if (value < 0)
0252 value = 0;
0253 if (value > therm->fan->bios.max_duty)
0254 value = therm->fan->bios.max_duty;
0255 therm->fan->bios.min_duty = value;
0256 return 0;
0257 case NVKM_THERM_ATTR_FAN_MAX_DUTY:
0258 if (value < 0)
0259 value = 0;
0260 if (value < therm->fan->bios.min_duty)
0261 value = therm->fan->bios.min_duty;
0262 therm->fan->bios.max_duty = value;
0263 return 0;
0264 case NVKM_THERM_ATTR_FAN_MODE:
0265 return nvkm_therm_fan_mode(therm, value);
0266 case NVKM_THERM_ATTR_THRS_FAN_BOOST:
0267 therm->bios_sensor.thrs_fan_boost.temp = value;
0268 therm->func->program_alarms(therm);
0269 return 0;
0270 case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST:
0271 therm->bios_sensor.thrs_fan_boost.hysteresis = value;
0272 therm->func->program_alarms(therm);
0273 return 0;
0274 case NVKM_THERM_ATTR_THRS_DOWN_CLK:
0275 therm->bios_sensor.thrs_down_clock.temp = value;
0276 therm->func->program_alarms(therm);
0277 return 0;
0278 case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST:
0279 therm->bios_sensor.thrs_down_clock.hysteresis = value;
0280 therm->func->program_alarms(therm);
0281 return 0;
0282 case NVKM_THERM_ATTR_THRS_CRITICAL:
0283 therm->bios_sensor.thrs_critical.temp = value;
0284 therm->func->program_alarms(therm);
0285 return 0;
0286 case NVKM_THERM_ATTR_THRS_CRITICAL_HYST:
0287 therm->bios_sensor.thrs_critical.hysteresis = value;
0288 therm->func->program_alarms(therm);
0289 return 0;
0290 case NVKM_THERM_ATTR_THRS_SHUTDOWN:
0291 therm->bios_sensor.thrs_shutdown.temp = value;
0292 therm->func->program_alarms(therm);
0293 return 0;
0294 case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST:
0295 therm->bios_sensor.thrs_shutdown.hysteresis = value;
0296 therm->func->program_alarms(therm);
0297 return 0;
0298 }
0299
0300 return -EINVAL;
0301 }
0302
0303 void
0304 nvkm_therm_clkgate_enable(struct nvkm_therm *therm)
0305 {
0306 if (!therm || !therm->func->clkgate_enable || !therm->clkgating_enabled)
0307 return;
0308
0309 nvkm_debug(&therm->subdev,
0310 "Enabling clockgating\n");
0311 therm->func->clkgate_enable(therm);
0312 }
0313
0314 void
0315 nvkm_therm_clkgate_fini(struct nvkm_therm *therm, bool suspend)
0316 {
0317 if (!therm || !therm->func->clkgate_fini || !therm->clkgating_enabled)
0318 return;
0319
0320 nvkm_debug(&therm->subdev,
0321 "Preparing clockgating for %s\n",
0322 suspend ? "suspend" : "fini");
0323 therm->func->clkgate_fini(therm, suspend);
0324 }
0325
0326 static void
0327 nvkm_therm_clkgate_oneinit(struct nvkm_therm *therm)
0328 {
0329 if (!therm->func->clkgate_enable || !therm->clkgating_enabled)
0330 return;
0331
0332 nvkm_info(&therm->subdev, "Clockgating enabled\n");
0333 }
0334
0335 static void
0336 nvkm_therm_intr(struct nvkm_subdev *subdev)
0337 {
0338 struct nvkm_therm *therm = nvkm_therm(subdev);
0339 if (therm->func->intr)
0340 therm->func->intr(therm);
0341 }
0342
0343 static int
0344 nvkm_therm_fini(struct nvkm_subdev *subdev, bool suspend)
0345 {
0346 struct nvkm_therm *therm = nvkm_therm(subdev);
0347
0348 if (therm->func->fini)
0349 therm->func->fini(therm);
0350
0351 nvkm_therm_fan_fini(therm, suspend);
0352 nvkm_therm_sensor_fini(therm, suspend);
0353
0354 if (suspend) {
0355 therm->suspend = therm->mode;
0356 therm->mode = NVKM_THERM_CTRL_NONE;
0357 }
0358
0359 return 0;
0360 }
0361
0362 static int
0363 nvkm_therm_oneinit(struct nvkm_subdev *subdev)
0364 {
0365 struct nvkm_therm *therm = nvkm_therm(subdev);
0366 nvkm_therm_sensor_ctor(therm);
0367 nvkm_therm_ic_ctor(therm);
0368 nvkm_therm_fan_ctor(therm);
0369 nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO);
0370 nvkm_therm_sensor_preinit(therm);
0371 nvkm_therm_clkgate_oneinit(therm);
0372 return 0;
0373 }
0374
0375 static int
0376 nvkm_therm_init(struct nvkm_subdev *subdev)
0377 {
0378 struct nvkm_therm *therm = nvkm_therm(subdev);
0379
0380 if (therm->func->init)
0381 therm->func->init(therm);
0382
0383 if (therm->suspend >= 0) {
0384
0385 if (therm->suspend > 0)
0386 nvkm_therm_fan_set(therm, true, therm->fan->percent);
0387
0388 nvkm_therm_fan_mode(therm, therm->suspend);
0389 }
0390
0391 nvkm_therm_sensor_init(therm);
0392 nvkm_therm_fan_init(therm);
0393 return 0;
0394 }
0395
0396 void
0397 nvkm_therm_clkgate_init(struct nvkm_therm *therm,
0398 const struct nvkm_therm_clkgate_pack *p)
0399 {
0400 if (!therm || !therm->func->clkgate_init || !therm->clkgating_enabled)
0401 return;
0402
0403 therm->func->clkgate_init(therm, p);
0404 }
0405
0406 static void *
0407 nvkm_therm_dtor(struct nvkm_subdev *subdev)
0408 {
0409 struct nvkm_therm *therm = nvkm_therm(subdev);
0410 kfree(therm->fan);
0411 return therm;
0412 }
0413
0414 static const struct nvkm_subdev_func
0415 nvkm_therm = {
0416 .dtor = nvkm_therm_dtor,
0417 .oneinit = nvkm_therm_oneinit,
0418 .init = nvkm_therm_init,
0419 .fini = nvkm_therm_fini,
0420 .intr = nvkm_therm_intr,
0421 };
0422
0423 void
0424 nvkm_therm_ctor(struct nvkm_therm *therm, struct nvkm_device *device, enum nvkm_subdev_type type,
0425 int inst, const struct nvkm_therm_func *func)
0426 {
0427 nvkm_subdev_ctor(&nvkm_therm, device, type, inst, &therm->subdev);
0428 therm->func = func;
0429
0430 nvkm_alarm_init(&therm->alarm, nvkm_therm_alarm);
0431 spin_lock_init(&therm->lock);
0432 spin_lock_init(&therm->sensor.alarm_program_lock);
0433
0434 therm->fan_get = nvkm_therm_fan_user_get;
0435 therm->fan_set = nvkm_therm_fan_user_set;
0436 therm->attr_get = nvkm_therm_attr_get;
0437 therm->attr_set = nvkm_therm_attr_set;
0438 therm->mode = therm->suspend = -1;
0439
0440 therm->clkgating_enabled = nvkm_boolopt(device->cfgopt,
0441 "NvPmEnableGating", false);
0442 }
0443
0444 int
0445 nvkm_therm_new_(const struct nvkm_therm_func *func, struct nvkm_device *device,
0446 enum nvkm_subdev_type type, int inst, struct nvkm_therm **ptherm)
0447 {
0448 struct nvkm_therm *therm;
0449
0450 if (!(therm = *ptherm = kzalloc(sizeof(*therm), GFP_KERNEL)))
0451 return -ENOMEM;
0452
0453 nvkm_therm_ctor(therm, device, type, inst, func);
0454 return 0;
0455 }