1 /*
2  *  intel_menlow.c - Intel menlow Driver for thermal management extension
3  *
4  *  Copyright (C) 2008 Intel Corp
5  *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
6  *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
7  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; version 2 of the License.
12  *
13  *  This program is distributed in the hope that it will be useful, but
14  *  WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License along
19  *  with this program; if not, write to the Free Software Foundation, Inc.,
20  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21  *
22  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23  *
24  *  This driver creates the sys I/F for programming the sensors.
25  *  It also implements the driver for intel menlow memory controller (hardware
26  *  id is INT0002) which makes use of the platform specific ACPI methods
27  *  to get/set bandwidth.
28  */
29 
30 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
31 
32 #include <linux/kernel.h>
33 #include <linux/module.h>
34 #include <linux/init.h>
35 #include <linux/slab.h>
36 #include <linux/types.h>
37 #include <linux/pci.h>
38 #include <linux/pm.h>
39 
40 #include <linux/thermal.h>
41 #include <acpi/acpi_bus.h>
42 #include <acpi/acpi_drivers.h>
43 
44 MODULE_AUTHOR("Thomas Sujith");
45 MODULE_AUTHOR("Zhang Rui");
46 MODULE_DESCRIPTION("Intel Menlow platform specific driver");
47 MODULE_LICENSE("GPL");
48 
49 /*
50  * Memory controller device control
51  */
52 
53 #define MEMORY_GET_BANDWIDTH "GTHS"
54 #define MEMORY_SET_BANDWIDTH "STHS"
55 #define MEMORY_ARG_CUR_BANDWIDTH 1
56 #define MEMORY_ARG_MAX_BANDWIDTH 0
57 
58 static void intel_menlow_unregister_sensor(void);
59 
60 /*
61  * GTHS returning 'n' would mean that [0,n-1] states are supported
62  * In that case max_cstate would be n-1
63  * GTHS returning '0' would mean that no bandwidth control states are supported
64  */
memory_get_max_bandwidth(struct thermal_cooling_device * cdev,unsigned long * max_state)65 static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
66 				    unsigned long *max_state)
67 {
68 	struct acpi_device *device = cdev->devdata;
69 	acpi_handle handle = device->handle;
70 	unsigned long long value;
71 	struct acpi_object_list arg_list;
72 	union acpi_object arg;
73 	acpi_status status = AE_OK;
74 
75 	arg_list.count = 1;
76 	arg_list.pointer = &arg;
77 	arg.type = ACPI_TYPE_INTEGER;
78 	arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH;
79 	status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
80 				       &arg_list, &value);
81 	if (ACPI_FAILURE(status))
82 		return -EFAULT;
83 
84 	if (!value)
85 		return -EINVAL;
86 
87 	*max_state = value - 1;
88 	return 0;
89 }
90 
memory_get_cur_bandwidth(struct thermal_cooling_device * cdev,unsigned long * value)91 static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
92 				    unsigned long *value)
93 {
94 	struct acpi_device *device = cdev->devdata;
95 	acpi_handle handle = device->handle;
96 	unsigned long long result;
97 	struct acpi_object_list arg_list;
98 	union acpi_object arg;
99 	acpi_status status = AE_OK;
100 
101 	arg_list.count = 1;
102 	arg_list.pointer = &arg;
103 	arg.type = ACPI_TYPE_INTEGER;
104 	arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
105 	status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
106 				       &arg_list, &result);
107 	if (ACPI_FAILURE(status))
108 		return -EFAULT;
109 
110 	*value = result;
111 	return 0;
112 }
113 
memory_set_cur_bandwidth(struct thermal_cooling_device * cdev,unsigned long state)114 static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
115 				    unsigned long state)
116 {
117 	struct acpi_device *device = cdev->devdata;
118 	acpi_handle handle = device->handle;
119 	struct acpi_object_list arg_list;
120 	union acpi_object arg;
121 	acpi_status status;
122 	unsigned long long temp;
123 	unsigned long max_state;
124 
125 	if (memory_get_max_bandwidth(cdev, &max_state))
126 		return -EFAULT;
127 
128 	if (state > max_state)
129 		return -EINVAL;
130 
131 	arg_list.count = 1;
132 	arg_list.pointer = &arg;
133 	arg.type = ACPI_TYPE_INTEGER;
134 	arg.integer.value = state;
135 
136 	status =
137 	    acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
138 				  &temp);
139 
140 	pr_info("Bandwidth value was %ld: status is %d\n", state, status);
141 	if (ACPI_FAILURE(status))
142 		return -EFAULT;
143 
144 	return 0;
145 }
146 
147 static struct thermal_cooling_device_ops memory_cooling_ops = {
148 	.get_max_state = memory_get_max_bandwidth,
149 	.get_cur_state = memory_get_cur_bandwidth,
150 	.set_cur_state = memory_set_cur_bandwidth,
151 };
152 
153 /*
154  * Memory Device Management
155  */
intel_menlow_memory_add(struct acpi_device * device)156 static int intel_menlow_memory_add(struct acpi_device *device)
157 {
158 	int result = -ENODEV;
159 	acpi_status status = AE_OK;
160 	acpi_handle dummy;
161 	struct thermal_cooling_device *cdev;
162 
163 	if (!device)
164 		return -EINVAL;
165 
166 	status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy);
167 	if (ACPI_FAILURE(status))
168 		goto end;
169 
170 	status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy);
171 	if (ACPI_FAILURE(status))
172 		goto end;
173 
174 	cdev = thermal_cooling_device_register("Memory controller", device,
175 					       &memory_cooling_ops);
176 	if (IS_ERR(cdev)) {
177 		result = PTR_ERR(cdev);
178 		goto end;
179 	}
180 
181 	device->driver_data = cdev;
182 	result = sysfs_create_link(&device->dev.kobj,
183 				&cdev->device.kobj, "thermal_cooling");
184 	if (result)
185 		goto unregister;
186 
187 	result = sysfs_create_link(&cdev->device.kobj,
188 				&device->dev.kobj, "device");
189 	if (result) {
190 		sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
191 		goto unregister;
192 	}
193 
194  end:
195 	return result;
196 
197  unregister:
198 	thermal_cooling_device_unregister(cdev);
199 	return result;
200 
201 }
202 
intel_menlow_memory_remove(struct acpi_device * device,int type)203 static int intel_menlow_memory_remove(struct acpi_device *device, int type)
204 {
205 	struct thermal_cooling_device *cdev = acpi_driver_data(device);
206 
207 	if (!device || !cdev)
208 		return -EINVAL;
209 
210 	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
211 	sysfs_remove_link(&cdev->device.kobj, "device");
212 	thermal_cooling_device_unregister(cdev);
213 
214 	return 0;
215 }
216 
217 static const struct acpi_device_id intel_menlow_memory_ids[] = {
218 	{"INT0002", 0},
219 	{"", 0},
220 };
221 
222 static struct acpi_driver intel_menlow_memory_driver = {
223 	.name = "intel_menlow_thermal_control",
224 	.ids = intel_menlow_memory_ids,
225 	.ops = {
226 		.add = intel_menlow_memory_add,
227 		.remove = intel_menlow_memory_remove,
228 		},
229 };
230 
231 /*
232  * Sensor control on menlow platform
233  */
234 
235 #define THERMAL_AUX0 0
236 #define THERMAL_AUX1 1
237 #define GET_AUX0 "GAX0"
238 #define GET_AUX1 "GAX1"
239 #define SET_AUX0 "SAX0"
240 #define SET_AUX1 "SAX1"
241 
242 struct intel_menlow_attribute {
243 	struct device_attribute attr;
244 	struct device *device;
245 	acpi_handle handle;
246 	struct list_head node;
247 };
248 
249 static LIST_HEAD(intel_menlow_attr_list);
250 static DEFINE_MUTEX(intel_menlow_attr_lock);
251 
252 /*
253  * sensor_get_auxtrip - get the current auxtrip value from sensor
254  * @name: Thermalzone name
255  * @auxtype : AUX0/AUX1
256  * @buf: syfs buffer
257  */
sensor_get_auxtrip(acpi_handle handle,int index,unsigned long long * value)258 static int sensor_get_auxtrip(acpi_handle handle, int index,
259 							unsigned long long *value)
260 {
261 	acpi_status status;
262 
263 	if ((index != 0 && index != 1) || !value)
264 		return -EINVAL;
265 
266 	status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
267 				       NULL, value);
268 	if (ACPI_FAILURE(status))
269 		return -EIO;
270 
271 	return 0;
272 }
273 
274 /*
275  * sensor_set_auxtrip - set the new auxtrip value to sensor
276  * @name: Thermalzone name
277  * @auxtype : AUX0/AUX1
278  * @buf: syfs buffer
279  */
sensor_set_auxtrip(acpi_handle handle,int index,int value)280 static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
281 {
282 	acpi_status status;
283 	union acpi_object arg = {
284 		ACPI_TYPE_INTEGER
285 	};
286 	struct acpi_object_list args = {
287 		1, &arg
288 	};
289 	unsigned long long temp;
290 
291 	if (index != 0 && index != 1)
292 		return -EINVAL;
293 
294 	status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
295 				       NULL, &temp);
296 	if (ACPI_FAILURE(status))
297 		return -EIO;
298 	if ((index && value < temp) || (!index && value > temp))
299 		return -EINVAL;
300 
301 	arg.integer.value = value;
302 	status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
303 				       &args, &temp);
304 	if (ACPI_FAILURE(status))
305 		return -EIO;
306 
307 	/* do we need to check the return value of SAX0/SAX1 ? */
308 
309 	return 0;
310 }
311 
312 #define to_intel_menlow_attr(_attr)	\
313 	container_of(_attr, struct intel_menlow_attribute, attr)
314 
aux0_show(struct device * dev,struct device_attribute * dev_attr,char * buf)315 static ssize_t aux0_show(struct device *dev,
316 			 struct device_attribute *dev_attr, char *buf)
317 {
318 	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
319 	unsigned long long value;
320 	int result;
321 
322 	result = sensor_get_auxtrip(attr->handle, 0, &value);
323 
324 	return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
325 }
326 
aux1_show(struct device * dev,struct device_attribute * dev_attr,char * buf)327 static ssize_t aux1_show(struct device *dev,
328 			 struct device_attribute *dev_attr, char *buf)
329 {
330 	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
331 	unsigned long long value;
332 	int result;
333 
334 	result = sensor_get_auxtrip(attr->handle, 1, &value);
335 
336 	return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
337 }
338 
aux0_store(struct device * dev,struct device_attribute * dev_attr,const char * buf,size_t count)339 static ssize_t aux0_store(struct device *dev,
340 			  struct device_attribute *dev_attr,
341 			  const char *buf, size_t count)
342 {
343 	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
344 	int value;
345 	int result;
346 
347 	/*Sanity check; should be a positive integer */
348 	if (!sscanf(buf, "%d", &value))
349 		return -EINVAL;
350 
351 	if (value < 0)
352 		return -EINVAL;
353 
354 	result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value));
355 	return result ? result : count;
356 }
357 
aux1_store(struct device * dev,struct device_attribute * dev_attr,const char * buf,size_t count)358 static ssize_t aux1_store(struct device *dev,
359 			  struct device_attribute *dev_attr,
360 			  const char *buf, size_t count)
361 {
362 	struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
363 	int value;
364 	int result;
365 
366 	/*Sanity check; should be a positive integer */
367 	if (!sscanf(buf, "%d", &value))
368 		return -EINVAL;
369 
370 	if (value < 0)
371 		return -EINVAL;
372 
373 	result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value));
374 	return result ? result : count;
375 }
376 
377 /* BIOS can enable/disable the thermal user application in dabney platform */
378 #define BIOS_ENABLED "\\_TZ.GSTS"
bios_enabled_show(struct device * dev,struct device_attribute * attr,char * buf)379 static ssize_t bios_enabled_show(struct device *dev,
380 				 struct device_attribute *attr, char *buf)
381 {
382 	acpi_status status;
383 	unsigned long long bios_enabled;
384 
385 	status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
386 	if (ACPI_FAILURE(status))
387 		return -ENODEV;
388 
389 	return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled");
390 }
391 
intel_menlow_add_one_attribute(char * name,umode_t mode,void * show,void * store,struct device * dev,acpi_handle handle)392 static int intel_menlow_add_one_attribute(char *name, umode_t mode, void *show,
393 					  void *store, struct device *dev,
394 					  acpi_handle handle)
395 {
396 	struct intel_menlow_attribute *attr;
397 	int result;
398 
399 	attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL);
400 	if (!attr)
401 		return -ENOMEM;
402 
403 	sysfs_attr_init(&attr->attr.attr); /* That is consistent naming :D */
404 	attr->attr.attr.name = name;
405 	attr->attr.attr.mode = mode;
406 	attr->attr.show = show;
407 	attr->attr.store = store;
408 	attr->device = dev;
409 	attr->handle = handle;
410 
411 	result = device_create_file(dev, &attr->attr);
412 	if (result) {
413 		kfree(attr);
414 		return result;
415 	}
416 
417 	mutex_lock(&intel_menlow_attr_lock);
418 	list_add_tail(&attr->node, &intel_menlow_attr_list);
419 	mutex_unlock(&intel_menlow_attr_lock);
420 
421 	return 0;
422 }
423 
intel_menlow_register_sensor(acpi_handle handle,u32 lvl,void * context,void ** rv)424 static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
425 						void *context, void **rv)
426 {
427 	acpi_status status;
428 	acpi_handle dummy;
429 	struct thermal_zone_device *thermal;
430 	int result;
431 
432 	result = acpi_bus_get_private_data(handle, (void **)&thermal);
433 	if (result)
434 		return 0;
435 
436 	/* _TZ must have the AUX0/1 methods */
437 	status = acpi_get_handle(handle, GET_AUX0, &dummy);
438 	if (ACPI_FAILURE(status))
439 		return (status == AE_NOT_FOUND) ? AE_OK : status;
440 
441 	status = acpi_get_handle(handle, SET_AUX0, &dummy);
442 	if (ACPI_FAILURE(status))
443 		return (status == AE_NOT_FOUND) ? AE_OK : status;
444 
445 	result = intel_menlow_add_one_attribute("aux0", 0644,
446 						aux0_show, aux0_store,
447 						&thermal->device, handle);
448 	if (result)
449 		return AE_ERROR;
450 
451 	status = acpi_get_handle(handle, GET_AUX1, &dummy);
452 	if (ACPI_FAILURE(status))
453 		goto aux1_not_found;
454 
455 	status = acpi_get_handle(handle, SET_AUX1, &dummy);
456 	if (ACPI_FAILURE(status))
457 		goto aux1_not_found;
458 
459 	result = intel_menlow_add_one_attribute("aux1", 0644,
460 						aux1_show, aux1_store,
461 						&thermal->device, handle);
462 	if (result) {
463 		intel_menlow_unregister_sensor();
464 		return AE_ERROR;
465 	}
466 
467 	/*
468 	 * create the "dabney_enabled" attribute which means the user app
469 	 * should be loaded or not
470 	 */
471 
472 	result = intel_menlow_add_one_attribute("bios_enabled", 0444,
473 						bios_enabled_show, NULL,
474 						&thermal->device, handle);
475 	if (result) {
476 		intel_menlow_unregister_sensor();
477 		return AE_ERROR;
478 	}
479 
480 	return AE_OK;
481 
482  aux1_not_found:
483 	if (status == AE_NOT_FOUND)
484 		return AE_OK;
485 
486 	intel_menlow_unregister_sensor();
487 	return status;
488 }
489 
intel_menlow_unregister_sensor(void)490 static void intel_menlow_unregister_sensor(void)
491 {
492 	struct intel_menlow_attribute *pos, *next;
493 
494 	mutex_lock(&intel_menlow_attr_lock);
495 	list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) {
496 		list_del(&pos->node);
497 		device_remove_file(pos->device, &pos->attr);
498 		kfree(pos);
499 	}
500 	mutex_unlock(&intel_menlow_attr_lock);
501 
502 	return;
503 }
504 
intel_menlow_module_init(void)505 static int __init intel_menlow_module_init(void)
506 {
507 	int result = -ENODEV;
508 	acpi_status status;
509 	unsigned long long enable;
510 
511 	if (acpi_disabled)
512 		return result;
513 
514 	/* Looking for the \_TZ.GSTS method */
515 	status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable);
516 	if (ACPI_FAILURE(status) || !enable)
517 		return -ENODEV;
518 
519 	/* Looking for ACPI device MEM0 with hardware id INT0002 */
520 	result = acpi_bus_register_driver(&intel_menlow_memory_driver);
521 	if (result)
522 		return result;
523 
524 	/* Looking for sensors in each ACPI thermal zone */
525 	status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
526 				     ACPI_UINT32_MAX,
527 				     intel_menlow_register_sensor, NULL, NULL, NULL);
528 	if (ACPI_FAILURE(status)) {
529 		acpi_bus_unregister_driver(&intel_menlow_memory_driver);
530 		return -ENODEV;
531 	}
532 
533 	return 0;
534 }
535 
intel_menlow_module_exit(void)536 static void __exit intel_menlow_module_exit(void)
537 {
538 	acpi_bus_unregister_driver(&intel_menlow_memory_driver);
539 	intel_menlow_unregister_sensor();
540 }
541 
542 module_init(intel_menlow_module_init);
543 module_exit(intel_menlow_module_exit);
544