Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.17-rc3 479 lines 11 kB view raw
1/* 2 * intel_soc_dts_thermal.c 3 * Copyright (c) 2014, Intel Corporation. 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms and conditions of the GNU General Public License, 7 * version 2, as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 */ 15 16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 17 18#include <linux/module.h> 19#include <linux/slab.h> 20#include <linux/interrupt.h> 21#include <linux/thermal.h> 22#include <asm/cpu_device_id.h> 23#include <asm/iosf_mbi.h> 24 25#define SOC_DTS_OFFSET_ENABLE 0xB0 26#define SOC_DTS_OFFSET_TEMP 0xB1 27 28#define SOC_DTS_OFFSET_PTPS 0xB2 29#define SOC_DTS_OFFSET_PTTS 0xB3 30#define SOC_DTS_OFFSET_PTTSS 0xB4 31#define SOC_DTS_OFFSET_PTMC 0x80 32#define SOC_DTS_TE_AUX0 0xB5 33#define SOC_DTS_TE_AUX1 0xB6 34 35#define SOC_DTS_AUX0_ENABLE_BIT BIT(0) 36#define SOC_DTS_AUX1_ENABLE_BIT BIT(1) 37#define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16) 38#define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17) 39#define SOC_DTS_TE_SCI_ENABLE BIT(9) 40#define SOC_DTS_TE_SMI_ENABLE BIT(10) 41#define SOC_DTS_TE_MSI_ENABLE BIT(11) 42#define SOC_DTS_TE_APICA_ENABLE BIT(14) 43#define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4) 44 45/* DTS encoding for TJ MAX temperature */ 46#define SOC_DTS_TJMAX_ENCODING 0x7F 47 48/* IRQ 86 is a fixed APIC interrupt for BYT DTS Aux threshold notifications */ 49#define BYT_SOC_DTS_APIC_IRQ 86 50 51/* Only 2 out of 4 is allowed for OSPM */ 52#define SOC_MAX_DTS_TRIPS 2 53 54/* Mask for two trips in status bits */ 55#define SOC_DTS_TRIP_MASK 0x03 56 57/* DTS0 and DTS 1 */ 58#define SOC_MAX_DTS_SENSORS 2 59 60#define CRITICAL_OFFSET_FROM_TJ_MAX 5000 61 62struct soc_sensor_entry { 63 int id; 64 u32 tj_max; 65 u32 temp_mask; 66 u32 temp_shift; 67 u32 store_status; 68 struct thermal_zone_device *tzone; 69}; 70 71static struct soc_sensor_entry *soc_dts[SOC_MAX_DTS_SENSORS]; 72 73static int crit_offset = CRITICAL_OFFSET_FROM_TJ_MAX; 74module_param(crit_offset, int, 0644); 75MODULE_PARM_DESC(crit_offset, 76 "Critical Temperature offset from tj max in millidegree Celsius."); 77 78static DEFINE_MUTEX(aux_update_mutex); 79static spinlock_t intr_notify_lock; 80static int soc_dts_thres_irq; 81 82static int get_tj_max(u32 *tj_max) 83{ 84 u32 eax, edx; 85 u32 val; 86 int err; 87 88 err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); 89 if (err) 90 goto err_ret; 91 else { 92 val = (eax >> 16) & 0xff; 93 if (val) 94 *tj_max = val * 1000; 95 else { 96 err = -EINVAL; 97 goto err_ret; 98 } 99 } 100 101 return 0; 102err_ret: 103 *tj_max = 0; 104 105 return err; 106} 107 108static int sys_get_trip_temp(struct thermal_zone_device *tzd, 109 int trip, unsigned long *temp) 110{ 111 int status; 112 u32 out; 113 struct soc_sensor_entry *aux_entry; 114 115 aux_entry = tzd->devdata; 116 117 if (!trip) { 118 /* Just return the critical temp */ 119 *temp = aux_entry->tj_max - crit_offset; 120 return 0; 121 } 122 123 mutex_lock(&aux_update_mutex); 124 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 125 SOC_DTS_OFFSET_PTPS, &out); 126 mutex_unlock(&aux_update_mutex); 127 if (status) 128 return status; 129 130 out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING; 131 132 if (!out) 133 *temp = 0; 134 else 135 *temp = aux_entry->tj_max - out * 1000; 136 137 return 0; 138} 139 140static int update_trip_temp(struct soc_sensor_entry *aux_entry, 141 int thres_index, unsigned long temp) 142{ 143 int status; 144 u32 temp_out; 145 u32 out; 146 u32 store_ptps; 147 u32 store_ptmc; 148 u32 store_te_out; 149 u32 te_out; 150 151 u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE | 152 SOC_DTS_TE_MSI_ENABLE; 153 154 temp_out = (aux_entry->tj_max - temp) / 1000; 155 156 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 157 SOC_DTS_OFFSET_PTPS, &store_ptps); 158 if (status) 159 return status; 160 161 out = (store_ptps & ~(0xFF << (thres_index * 8))); 162 out |= (temp_out & 0xFF) << (thres_index * 8); 163 status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 164 SOC_DTS_OFFSET_PTPS, out); 165 if (status) 166 return status; 167 pr_debug("update_trip_temp PTPS = %x\n", out); 168 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 169 SOC_DTS_OFFSET_PTMC, &out); 170 if (status) 171 goto err_restore_ptps; 172 173 store_ptmc = out; 174 175 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 176 SOC_DTS_TE_AUX0 + thres_index, 177 &te_out); 178 if (status) 179 goto err_restore_ptmc; 180 181 store_te_out = te_out; 182 183 /* Enable for CPU module 0 and module 1 */ 184 out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT | 185 SOC_DTS_CPU_MODULE1_ENABLE_BIT); 186 if (temp) { 187 if (thres_index) 188 out |= SOC_DTS_AUX1_ENABLE_BIT; 189 else 190 out |= SOC_DTS_AUX0_ENABLE_BIT; 191 te_out |= int_enable_bit; 192 } else { 193 if (thres_index) 194 out &= ~SOC_DTS_AUX1_ENABLE_BIT; 195 else 196 out &= ~SOC_DTS_AUX0_ENABLE_BIT; 197 te_out &= ~int_enable_bit; 198 } 199 status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 200 SOC_DTS_OFFSET_PTMC, out); 201 if (status) 202 goto err_restore_te_out; 203 204 status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 205 SOC_DTS_TE_AUX0 + thres_index, 206 te_out); 207 if (status) 208 goto err_restore_te_out; 209 210 return 0; 211 212err_restore_te_out: 213 iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 214 SOC_DTS_OFFSET_PTMC, store_te_out); 215err_restore_ptmc: 216 iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 217 SOC_DTS_OFFSET_PTMC, store_ptmc); 218err_restore_ptps: 219 iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 220 SOC_DTS_OFFSET_PTPS, store_ptps); 221 /* Nothing we can do if restore fails */ 222 223 return status; 224} 225 226static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 227 unsigned long temp) 228{ 229 struct soc_sensor_entry *aux_entry = tzd->devdata; 230 int status; 231 232 if (temp > (aux_entry->tj_max - crit_offset)) 233 return -EINVAL; 234 235 mutex_lock(&aux_update_mutex); 236 status = update_trip_temp(tzd->devdata, trip, temp); 237 mutex_unlock(&aux_update_mutex); 238 239 return status; 240} 241 242static int sys_get_trip_type(struct thermal_zone_device *thermal, 243 int trip, enum thermal_trip_type *type) 244{ 245 if (trip) 246 *type = THERMAL_TRIP_PASSIVE; 247 else 248 *type = THERMAL_TRIP_CRITICAL; 249 250 return 0; 251} 252 253static int sys_get_curr_temp(struct thermal_zone_device *tzd, 254 unsigned long *temp) 255{ 256 int status; 257 u32 out; 258 struct soc_sensor_entry *aux_entry; 259 260 aux_entry = tzd->devdata; 261 262 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 263 SOC_DTS_OFFSET_TEMP, &out); 264 if (status) 265 return status; 266 267 out = (out & aux_entry->temp_mask) >> aux_entry->temp_shift; 268 out -= SOC_DTS_TJMAX_ENCODING; 269 *temp = aux_entry->tj_max - out * 1000; 270 271 return 0; 272} 273 274static struct thermal_zone_device_ops tzone_ops = { 275 .get_temp = sys_get_curr_temp, 276 .get_trip_temp = sys_get_trip_temp, 277 .get_trip_type = sys_get_trip_type, 278 .set_trip_temp = sys_set_trip_temp, 279}; 280 281static void free_soc_dts(struct soc_sensor_entry *aux_entry) 282{ 283 if (aux_entry) { 284 iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 285 SOC_DTS_OFFSET_ENABLE, aux_entry->store_status); 286 thermal_zone_device_unregister(aux_entry->tzone); 287 kfree(aux_entry); 288 } 289} 290 291static int soc_dts_enable(int id) 292{ 293 u32 out; 294 int ret; 295 296 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 297 SOC_DTS_OFFSET_ENABLE, &out); 298 if (ret) 299 return ret; 300 301 if (!(out & BIT(id))) { 302 out |= BIT(id); 303 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 304 SOC_DTS_OFFSET_ENABLE, out); 305 if (ret) 306 return ret; 307 } 308 309 return ret; 310} 311 312static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) 313{ 314 struct soc_sensor_entry *aux_entry; 315 char name[10]; 316 int err; 317 318 aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); 319 if (!aux_entry) { 320 err = -ENOMEM; 321 return ERR_PTR(-ENOMEM); 322 } 323 324 /* Store status to restor on exit */ 325 err = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 326 SOC_DTS_OFFSET_ENABLE, 327 &aux_entry->store_status); 328 if (err) 329 goto err_ret; 330 331 aux_entry->id = id; 332 aux_entry->tj_max = tj_max; 333 aux_entry->temp_mask = 0x00FF << (id * 8); 334 aux_entry->temp_shift = id * 8; 335 snprintf(name, sizeof(name), "soc_dts%d", id); 336 aux_entry->tzone = thermal_zone_device_register(name, 337 SOC_MAX_DTS_TRIPS, 338 0x02, 339 aux_entry, &tzone_ops, NULL, 0, 0); 340 if (IS_ERR(aux_entry->tzone)) { 341 err = PTR_ERR(aux_entry->tzone); 342 goto err_ret; 343 } 344 345 err = soc_dts_enable(id); 346 if (err) 347 goto err_aux_status; 348 349 return aux_entry; 350 351err_aux_status: 352 thermal_zone_device_unregister(aux_entry->tzone); 353err_ret: 354 kfree(aux_entry); 355 return ERR_PTR(err); 356} 357 358static void proc_thermal_interrupt(void) 359{ 360 u32 sticky_out; 361 int status; 362 u32 ptmc_out; 363 364 /* Clear APIC interrupt */ 365 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 366 SOC_DTS_OFFSET_PTMC, &ptmc_out); 367 368 ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT; 369 status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 370 SOC_DTS_OFFSET_PTMC, ptmc_out); 371 372 /* Read status here */ 373 status = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, 374 SOC_DTS_OFFSET_PTTSS, &sticky_out); 375 pr_debug("status %d PTTSS %x\n", status, sticky_out); 376 if (sticky_out & SOC_DTS_TRIP_MASK) { 377 int i; 378 /* reset sticky bit */ 379 status = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE, 380 SOC_DTS_OFFSET_PTTSS, sticky_out); 381 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 382 pr_debug("TZD update for zone %d\n", i); 383 thermal_zone_device_update(soc_dts[i]->tzone); 384 } 385 } 386 387} 388 389static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) 390{ 391 unsigned long flags; 392 393 spin_lock_irqsave(&intr_notify_lock, flags); 394 proc_thermal_interrupt(); 395 spin_unlock_irqrestore(&intr_notify_lock, flags); 396 pr_debug("proc_thermal_interrupt\n"); 397 398 return IRQ_HANDLED; 399} 400 401static const struct x86_cpu_id soc_thermal_ids[] = { 402 { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, 403 {} 404}; 405MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); 406 407static int __init intel_soc_thermal_init(void) 408{ 409 u32 tj_max; 410 int err = 0; 411 int i; 412 const struct x86_cpu_id *match_cpu; 413 414 match_cpu = x86_match_cpu(soc_thermal_ids); 415 if (!match_cpu) 416 return -ENODEV; 417 418 if (get_tj_max(&tj_max)) 419 return -EINVAL; 420 421 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 422 soc_dts[i] = alloc_soc_dts(i, tj_max); 423 if (IS_ERR(soc_dts[i])) { 424 err = PTR_ERR(soc_dts[i]); 425 goto err_free; 426 } 427 } 428 429 spin_lock_init(&intr_notify_lock); 430 431 soc_dts_thres_irq = (int)match_cpu->driver_data; 432 433 err = request_threaded_irq(soc_dts_thres_irq, NULL, 434 soc_irq_thread_fn, 435 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 436 "soc_dts", soc_dts); 437 if (err) { 438 pr_err("request_threaded_irq ret %d\n", err); 439 goto err_free; 440 } 441 442 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 443 err = update_trip_temp(soc_dts[i], 0, tj_max - crit_offset); 444 if (err) 445 goto err_trip_temp; 446 } 447 448 return 0; 449 450err_trip_temp: 451 i = SOC_MAX_DTS_SENSORS; 452 free_irq(soc_dts_thres_irq, soc_dts); 453err_free: 454 while (--i >= 0) 455 free_soc_dts(soc_dts[i]); 456 457 return err; 458} 459 460static void __exit intel_soc_thermal_exit(void) 461{ 462 int i; 463 464 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 465 update_trip_temp(soc_dts[i], 0, 0); 466 467 free_irq(soc_dts_thres_irq, soc_dts); 468 469 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 470 free_soc_dts(soc_dts[i]); 471 472} 473 474module_init(intel_soc_thermal_init) 475module_exit(intel_soc_thermal_exit) 476 477MODULE_DESCRIPTION("Intel SoC DTS Thermal Driver"); 478MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 479MODULE_LICENSE("GPL v2");