aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-24 18:51:02 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-24 18:51:02 -0500
commit09da8dfa98682d871987145ed11e3232accac860 (patch)
tree152a9bb1e52f70db6efb66fffbdc4871f749d7df /drivers/char
parent3aacd625f20129f5a41ea3ff3b5353b0e4dabd01 (diff)
parent7744064731a9543105e207504e0262f883bc14c0 (diff)
Merge tag 'pm+acpi-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI and power management updates from Rafael Wysocki: "As far as the number of commits goes, the top spot belongs to ACPI this time with cpufreq in the second position and a handful of PM core, PNP and cpuidle updates. They are fixes and cleanups mostly, as usual, with a couple of new features in the mix. The most visible change is probably that we will create struct acpi_device objects (visible in sysfs) for all devices represented in the ACPI tables regardless of their status and there will be a new sysfs attribute under those objects allowing user space to check that status via _STA. Consequently, ACPI device eject or generally hot-removal will not delete those objects, unless the table containing the corresponding namespace nodes is unloaded, which is extremely rare. Also ACPI container hotplug will be handled quite a bit differently and cpufreq will support CPU boost ("turbo") generically and not only in the acpi-cpufreq driver. Specifics: - ACPI core changes to make it create a struct acpi_device object for every device represented in the ACPI tables during all namespace scans regardless of the current status of that device. In accordance with this, ACPI hotplug operations will not delete those objects, unless the underlying ACPI tables go away. - On top of the above, new sysfs attribute for ACPI device objects allowing user space to check device status by triggering the execution of _STA for its ACPI object. From Srinivas Pandruvada. - ACPI core hotplug changes reducing code duplication, integrating the PCI root hotplug with the core and reworking container hotplug. - ACPI core simplifications making it use ACPI_COMPANION() in the code "glueing" ACPI device objects to "physical" devices. - ACPICA update to upstream version 20131218. This adds support for the DBG2 and PCCT tables to ACPICA, fixes some bugs and improves debug facilities. From Bob Moore, Lv Zheng and Betty Dall. - Init code change to carry out the early ACPI initialization earlier. That should allow us to use ACPI during the timekeeping initialization and possibly to simplify the EFI initialization too. From Chun-Yi Lee. - Clenups of the inclusions of ACPI headers in many places all over from Lv Zheng and Rashika Kheria (work in progress). - New helper for ACPI _DSM execution and rework of the code in drivers that uses _DSM to execute it via the new helper. From Jiang Liu. - New Win8 OSI blacklist entries from Takashi Iwai. - Assorted ACPI fixes and cleanups from Al Stone, Emil Goode, Hanjun Guo, Lan Tianyu, Masanari Iida, Oliver Neukum, Prarit Bhargava, Rashika Kheria, Tang Chen, Zhang Rui. - intel_pstate driver updates, including proper Baytrail support, from Dirk Brandewie and intel_pstate documentation from Ramkumar Ramachandra. - Generic CPU boost ("turbo") support for cpufreq from Lukasz Majewski. - powernow-k6 cpufreq driver fixes from Mikulas Patocka. - cpufreq core fixes and cleanups from Viresh Kumar, Jane Li, Mark Brown. - Assorted cpufreq drivers fixes and cleanups from Anson Huang, John Tobias, Paul Bolle, Paul Walmsley, Sachin Kamat, Shawn Guo, Viresh Kumar. - cpuidle cleanups from Bartlomiej Zolnierkiewicz. - Support for hibernation APM events from Bin Shi. - Hibernation fix to avoid bringing up nonboot CPUs with ACPI EC disabled during thaw transitions from Bjørn Mork. - PM core fixes and cleanups from Ben Dooks, Leonardo Potenza, Ulf Hansson. - PNP subsystem fixes and cleanups from Dmitry Torokhov, Levente Kurusa, Rashika Kheria. - New tool for profiling system suspend from Todd E Brandt and a cpupower tool cleanup from One Thousand Gnomes" * tag 'pm+acpi-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (153 commits) thermal: exynos: boost: Automatic enable/disable of BOOST feature (at Exynos4412) cpufreq: exynos4x12: Change L0 driver data to CPUFREQ_BOOST_FREQ Documentation: cpufreq / boost: Update BOOST documentation cpufreq: exynos: Extend Exynos cpufreq driver to support boost cpufreq / boost: Kconfig: Support for software-managed BOOST acpi-cpufreq: Adjust the code to use the common boost attribute cpufreq: Add boost frequency support in core intel_pstate: Add trace point to report internal state. cpufreq: introduce cpufreq_generic_get() routine ARM: SA1100: Create dummy clk_get_rate() to avoid build failures cpufreq: stats: create sysfs entries when cpufreq_stats is a module cpufreq: stats: free table and remove sysfs entry in a single routine cpufreq: stats: remove hotplug notifiers cpufreq: stats: handle cpufreq_unregister_driver() and suspend/resume properly cpufreq: speedstep: remove unused speedstep_get_state platform: introduce OF style 'modalias' support for platform bus PM / tools: new tool for suspend/resume performance optimization ACPI: fix module autoloading for ACPI enumerated devices ACPI: add module autoloading support for ACPI enumerated devices ACPI: fix create_modalias() return value handling ...
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/apm-emulation.c11
-rw-r--r--drivers/char/hpet.c7
-rw-r--r--drivers/char/tpm/tpm_acpi.c2
-rw-r--r--drivers/char/tpm/tpm_ppi.c406
4 files changed, 154 insertions, 272 deletions
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 46118f845948..dd9dfa15e9d1 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -531,6 +531,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,
531{ 531{
532 struct apm_user *as; 532 struct apm_user *as;
533 int err; 533 int err;
534 unsigned long apm_event;
534 535
535 /* short-cut emergency suspends */ 536 /* short-cut emergency suspends */
536 if (atomic_read(&userspace_notification_inhibit)) 537 if (atomic_read(&userspace_notification_inhibit))
@@ -538,6 +539,9 @@ static int apm_suspend_notifier(struct notifier_block *nb,
538 539
539 switch (event) { 540 switch (event) {
540 case PM_SUSPEND_PREPARE: 541 case PM_SUSPEND_PREPARE:
542 case PM_HIBERNATION_PREPARE:
543 apm_event = (event == PM_SUSPEND_PREPARE) ?
544 APM_USER_SUSPEND : APM_USER_HIBERNATION;
541 /* 545 /*
542 * Queue an event to all "writer" users that we want 546 * Queue an event to all "writer" users that we want
543 * to suspend and need their ack. 547 * to suspend and need their ack.
@@ -550,7 +554,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,
550 as->writer && as->suser) { 554 as->writer && as->suser) {
551 as->suspend_state = SUSPEND_PENDING; 555 as->suspend_state = SUSPEND_PENDING;
552 atomic_inc(&suspend_acks_pending); 556 atomic_inc(&suspend_acks_pending);
553 queue_add_event(&as->queue, APM_USER_SUSPEND); 557 queue_add_event(&as->queue, apm_event);
554 } 558 }
555 } 559 }
556 560
@@ -601,11 +605,14 @@ static int apm_suspend_notifier(struct notifier_block *nb,
601 return notifier_from_errno(err); 605 return notifier_from_errno(err);
602 606
603 case PM_POST_SUSPEND: 607 case PM_POST_SUSPEND:
608 case PM_POST_HIBERNATION:
609 apm_event = (event == PM_POST_SUSPEND) ?
610 APM_NORMAL_RESUME : APM_HIBERNATION_RESUME;
604 /* 611 /*
605 * Anyone on the APM queues will think we're still suspended. 612 * Anyone on the APM queues will think we're still suspended.
606 * Send a message so everyone knows we're now awake again. 613 * Send a message so everyone knows we're now awake again.
607 */ 614 */
608 queue_event(APM_NORMAL_RESUME); 615 queue_event(apm_event);
609 616
610 /* 617 /*
611 * Finally, wake up anyone who is sleeping on the suspend. 618 * Finally, wake up anyone who is sleeping on the suspend.
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 5d9c31dfc905..d5d4cd82b9f7 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -34,15 +34,12 @@
34#include <linux/uaccess.h> 34#include <linux/uaccess.h>
35#include <linux/slab.h> 35#include <linux/slab.h>
36#include <linux/io.h> 36#include <linux/io.h>
37 37#include <linux/acpi.h>
38#include <linux/hpet.h>
38#include <asm/current.h> 39#include <asm/current.h>
39#include <asm/irq.h> 40#include <asm/irq.h>
40#include <asm/div64.h> 41#include <asm/div64.h>
41 42
42#include <linux/acpi.h>
43#include <acpi/acpi_bus.h>
44#include <linux/hpet.h>
45
46/* 43/*
47 * The High Precision Event Timer driver. 44 * The High Precision Event Timer driver.
48 * This driver is closely modelled after the rtc.c driver. 45 * This driver is closely modelled after the rtc.c driver.
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c
index 64420b3396a2..b9a57fa4b710 100644
--- a/drivers/char/tpm/tpm_acpi.c
+++ b/drivers/char/tpm/tpm_acpi.c
@@ -23,7 +23,7 @@
23#include <linux/security.h> 23#include <linux/security.h>
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <acpi/acpi.h> 26#include <linux/acpi.h>
27 27
28#include "tpm.h" 28#include "tpm.h"
29#include "tpm_eventlog.h" 29#include "tpm_eventlog.h"
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 2db4419831be..b3ea223585bd 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -1,16 +1,6 @@
1#include <linux/acpi.h> 1#include <linux/acpi.h>
2#include <acpi/acpi_drivers.h>
3#include "tpm.h" 2#include "tpm.h"
4 3
5static const u8 tpm_ppi_uuid[] = {
6 0xA6, 0xFA, 0xDD, 0x3D,
7 0x1B, 0x36,
8 0xB4, 0x4E,
9 0xA4, 0x24,
10 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
11};
12static char *tpm_device_name = "TPM";
13
14#define TPM_PPI_REVISION_ID 1 4#define TPM_PPI_REVISION_ID 1
15#define TPM_PPI_FN_VERSION 1 5#define TPM_PPI_FN_VERSION 1
16#define TPM_PPI_FN_SUBREQ 2 6#define TPM_PPI_FN_SUBREQ 2
@@ -24,250 +14,178 @@ static char *tpm_device_name = "TPM";
24#define PPI_VS_REQ_END 255 14#define PPI_VS_REQ_END 255
25#define PPI_VERSION_LEN 3 15#define PPI_VERSION_LEN 3
26 16
17static const u8 tpm_ppi_uuid[] = {
18 0xA6, 0xFA, 0xDD, 0x3D,
19 0x1B, 0x36,
20 0xB4, 0x4E,
21 0xA4, 0x24,
22 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
23};
24
25static char tpm_ppi_version[PPI_VERSION_LEN + 1];
26static acpi_handle tpm_ppi_handle;
27
27static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, 28static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
28 void **return_value) 29 void **return_value)
29{ 30{
30 acpi_status status = AE_OK; 31 union acpi_object *obj;
31 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
32 32
33 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) { 33 if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
34 if (strstr(buffer.pointer, context) != NULL) { 34 1 << TPM_PPI_FN_VERSION))
35 *return_value = handle; 35 return AE_OK;
36 status = AE_CTRL_TERMINATE; 36
37 } 37 /* Cache version string */
38 kfree(buffer.pointer); 38 obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
39 TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
40 NULL, ACPI_TYPE_STRING);
41 if (obj) {
42 strlcpy(tpm_ppi_version, obj->string.pointer,
43 PPI_VERSION_LEN + 1);
44 ACPI_FREE(obj);
39 } 45 }
40 46
41 return status; 47 *return_value = handle;
48
49 return AE_CTRL_TERMINATE;
42} 50}
43 51
44static inline void ppi_assign_params(union acpi_object params[4], 52static inline union acpi_object *
45 u64 function_num) 53tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
46{ 54{
47 params[0].type = ACPI_TYPE_BUFFER; 55 BUG_ON(!tpm_ppi_handle);
48 params[0].buffer.length = sizeof(tpm_ppi_uuid); 56 return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid,
49 params[0].buffer.pointer = (char *)tpm_ppi_uuid; 57 TPM_PPI_REVISION_ID, func, argv4, type);
50 params[1].type = ACPI_TYPE_INTEGER;
51 params[1].integer.value = TPM_PPI_REVISION_ID;
52 params[2].type = ACPI_TYPE_INTEGER;
53 params[2].integer.value = function_num;
54 params[3].type = ACPI_TYPE_PACKAGE;
55 params[3].package.count = 0;
56 params[3].package.elements = NULL;
57} 58}
58 59
59static ssize_t tpm_show_ppi_version(struct device *dev, 60static ssize_t tpm_show_ppi_version(struct device *dev,
60 struct device_attribute *attr, char *buf) 61 struct device_attribute *attr, char *buf)
61{ 62{
62 acpi_handle handle; 63 return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);
63 acpi_status status;
64 struct acpi_object_list input;
65 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
66 union acpi_object params[4];
67 union acpi_object *obj;
68
69 input.count = 4;
70 ppi_assign_params(params, TPM_PPI_FN_VERSION);
71 input.pointer = params;
72 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
73 ACPI_UINT32_MAX, ppi_callback, NULL,
74 tpm_device_name, &handle);
75 if (ACPI_FAILURE(status))
76 return -ENXIO;
77
78 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
79 ACPI_TYPE_STRING);
80 if (ACPI_FAILURE(status))
81 return -ENOMEM;
82 obj = (union acpi_object *)output.pointer;
83 status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer);
84 kfree(output.pointer);
85 return status;
86} 64}
87 65
88static ssize_t tpm_show_ppi_request(struct device *dev, 66static ssize_t tpm_show_ppi_request(struct device *dev,
89 struct device_attribute *attr, char *buf) 67 struct device_attribute *attr, char *buf)
90{ 68{
91 acpi_handle handle; 69 ssize_t size = -EINVAL;
92 acpi_status status; 70 union acpi_object *obj;
93 struct acpi_object_list input; 71
94 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 72 obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
95 union acpi_object params[4]; 73 if (!obj)
96 union acpi_object *ret_obj;
97
98 input.count = 4;
99 ppi_assign_params(params, TPM_PPI_FN_GETREQ);
100 input.pointer = params;
101 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
102 ACPI_UINT32_MAX, ppi_callback, NULL,
103 tpm_device_name, &handle);
104 if (ACPI_FAILURE(status))
105 return -ENXIO; 74 return -ENXIO;
106 75
107 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
108 ACPI_TYPE_PACKAGE);
109 if (ACPI_FAILURE(status))
110 return -ENOMEM;
111 /* 76 /*
112 * output.pointer should be of package type, including two integers. 77 * output.pointer should be of package type, including two integers.
113 * The first is function return code, 0 means success and 1 means 78 * The first is function return code, 0 means success and 1 means
114 * error. The second is pending TPM operation requested by the OS, 0 79 * error. The second is pending TPM operation requested by the OS, 0
115 * means none and >0 means operation value. 80 * means none and >0 means operation value.
116 */ 81 */
117 ret_obj = ((union acpi_object *)output.pointer)->package.elements; 82 if (obj->package.count == 2 &&
118 if (ret_obj->type == ACPI_TYPE_INTEGER) { 83 obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
119 if (ret_obj->integer.value) { 84 obj->package.elements[1].type == ACPI_TYPE_INTEGER) {
120 status = -EFAULT; 85 if (obj->package.elements[0].integer.value)
121 goto cleanup; 86 size = -EFAULT;
122 }
123 ret_obj++;
124 if (ret_obj->type == ACPI_TYPE_INTEGER)
125 status = scnprintf(buf, PAGE_SIZE, "%llu\n",
126 ret_obj->integer.value);
127 else 87 else
128 status = -EINVAL; 88 size = scnprintf(buf, PAGE_SIZE, "%llu\n",
129 } else { 89 obj->package.elements[1].integer.value);
130 status = -EINVAL;
131 } 90 }
132cleanup: 91
133 kfree(output.pointer); 92 ACPI_FREE(obj);
134 return status; 93
94 return size;
135} 95}
136 96
137static ssize_t tpm_store_ppi_request(struct device *dev, 97static ssize_t tpm_store_ppi_request(struct device *dev,
138 struct device_attribute *attr, 98 struct device_attribute *attr,
139 const char *buf, size_t count) 99 const char *buf, size_t count)
140{ 100{
141 char version[PPI_VERSION_LEN + 1];
142 acpi_handle handle;
143 acpi_status status;
144 struct acpi_object_list input;
145 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
146 union acpi_object params[4];
147 union acpi_object obj;
148 u32 req; 101 u32 req;
149 u64 ret; 102 u64 ret;
103 int func = TPM_PPI_FN_SUBREQ;
104 union acpi_object *obj, tmp;
105 union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
150 106
151 input.count = 4;
152 ppi_assign_params(params, TPM_PPI_FN_VERSION);
153 input.pointer = params;
154 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
155 ACPI_UINT32_MAX, ppi_callback, NULL,
156 tpm_device_name, &handle);
157 if (ACPI_FAILURE(status))
158 return -ENXIO;
159
160 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
161 ACPI_TYPE_STRING);
162 if (ACPI_FAILURE(status))
163 return -ENOMEM;
164 strlcpy(version,
165 ((union acpi_object *)output.pointer)->string.pointer,
166 PPI_VERSION_LEN + 1);
167 kfree(output.pointer);
168 output.length = ACPI_ALLOCATE_BUFFER;
169 output.pointer = NULL;
170 /* 107 /*
171 * the function to submit TPM operation request to pre-os environment 108 * the function to submit TPM operation request to pre-os environment
172 * is updated with function index from SUBREQ to SUBREQ2 since PPI 109 * is updated with function index from SUBREQ to SUBREQ2 since PPI
173 * version 1.1 110 * version 1.1
174 */ 111 */
175 if (strcmp(version, "1.1") < 0) 112 if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
176 params[2].integer.value = TPM_PPI_FN_SUBREQ; 113 1 << TPM_PPI_FN_SUBREQ2))
177 else 114 func = TPM_PPI_FN_SUBREQ2;
178 params[2].integer.value = TPM_PPI_FN_SUBREQ2; 115
179 /* 116 /*
180 * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 117 * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS
181 * accept buffer/string/integer type, but some BIOS accept buffer/ 118 * accept buffer/string/integer type, but some BIOS accept buffer/
182 * string/package type. For PPI version 1.0 and 1.1, use buffer type 119 * string/package type. For PPI version 1.0 and 1.1, use buffer type
183 * for compatibility, and use package type since 1.2 according to spec. 120 * for compatibility, and use package type since 1.2 according to spec.
184 */ 121 */
185 if (strcmp(version, "1.2") < 0) { 122 if (strcmp(tpm_ppi_version, "1.2") < 0) {
186 params[3].type = ACPI_TYPE_BUFFER; 123 if (sscanf(buf, "%d", &req) != 1)
187 params[3].buffer.length = sizeof(req); 124 return -EINVAL;
188 sscanf(buf, "%d", &req); 125 argv4.type = ACPI_TYPE_BUFFER;
189 params[3].buffer.pointer = (char *)&req; 126 argv4.buffer.length = sizeof(req);
127 argv4.buffer.pointer = (u8 *)&req;
128 } else {
129 tmp.type = ACPI_TYPE_INTEGER;
130 if (sscanf(buf, "%llu", &tmp.integer.value) != 1)
131 return -EINVAL;
132 }
133
134 obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
135 if (!obj) {
136 return -ENXIO;
190 } else { 137 } else {
191 params[3].package.count = 1; 138 ret = obj->integer.value;
192 obj.type = ACPI_TYPE_INTEGER; 139 ACPI_FREE(obj);
193 sscanf(buf, "%llu", &obj.integer.value);
194 params[3].package.elements = &obj;
195 } 140 }
196 141
197 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
198 ACPI_TYPE_INTEGER);
199 if (ACPI_FAILURE(status))
200 return -ENOMEM;
201 ret = ((union acpi_object *)output.pointer)->integer.value;
202 if (ret == 0) 142 if (ret == 0)
203 status = (acpi_status)count; 143 return (acpi_status)count;
204 else if (ret == 1) 144
205 status = -EPERM; 145 return (ret == 1) ? -EPERM : -EFAULT;
206 else
207 status = -EFAULT;
208 kfree(output.pointer);
209 return status;
210} 146}
211 147
212static ssize_t tpm_show_ppi_transition_action(struct device *dev, 148static ssize_t tpm_show_ppi_transition_action(struct device *dev,
213 struct device_attribute *attr, 149 struct device_attribute *attr,
214 char *buf) 150 char *buf)
215{ 151{
216 char version[PPI_VERSION_LEN + 1];
217 acpi_handle handle;
218 acpi_status status;
219 struct acpi_object_list input;
220 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
221 union acpi_object params[4];
222 u32 ret; 152 u32 ret;
223 char *info[] = { 153 acpi_status status;
154 union acpi_object *obj = NULL;
155 union acpi_object tmp = {
156 .buffer.type = ACPI_TYPE_BUFFER,
157 .buffer.length = 0,
158 .buffer.pointer = NULL
159 };
160
161 static char *info[] = {
224 "None", 162 "None",
225 "Shutdown", 163 "Shutdown",
226 "Reboot", 164 "Reboot",
227 "OS Vendor-specific", 165 "OS Vendor-specific",
228 "Error", 166 "Error",
229 }; 167 };
230 input.count = 4;
231 ppi_assign_params(params, TPM_PPI_FN_VERSION);
232 input.pointer = params;
233 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
234 ACPI_UINT32_MAX, ppi_callback, NULL,
235 tpm_device_name, &handle);
236 if (ACPI_FAILURE(status))
237 return -ENXIO;
238 168
239 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
240 ACPI_TYPE_STRING);
241 if (ACPI_FAILURE(status))
242 return -ENOMEM;
243 strlcpy(version,
244 ((union acpi_object *)output.pointer)->string.pointer,
245 PPI_VERSION_LEN + 1);
246 /* 169 /*
247 * PPI spec defines params[3].type as empty package, but some platforms 170 * PPI spec defines params[3].type as empty package, but some platforms
248 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for 171 * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
249 * compatibility, define params[3].type as buffer, if PPI version < 1.2 172 * compatibility, define params[3].type as buffer, if PPI version < 1.2
250 */ 173 */
251 if (strcmp(version, "1.2") < 0) { 174 if (strcmp(tpm_ppi_version, "1.2") < 0)
252 params[3].type = ACPI_TYPE_BUFFER; 175 obj = &tmp;
253 params[3].buffer.length = 0; 176 obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
254 params[3].buffer.pointer = NULL; 177 if (!obj) {
178 return -ENXIO;
179 } else {
180 ret = obj->integer.value;
181 ACPI_FREE(obj);
255 } 182 }
256 params[2].integer.value = TPM_PPI_FN_GETACT; 183
257 kfree(output.pointer);
258 output.length = ACPI_ALLOCATE_BUFFER;
259 output.pointer = NULL;
260 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
261 ACPI_TYPE_INTEGER);
262 if (ACPI_FAILURE(status))
263 return -ENOMEM;
264 ret = ((union acpi_object *)output.pointer)->integer.value;
265 if (ret < ARRAY_SIZE(info) - 1) 184 if (ret < ARRAY_SIZE(info) - 1)
266 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 185 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]);
267 else 186 else
268 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 187 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret,
269 info[ARRAY_SIZE(info)-1]); 188 info[ARRAY_SIZE(info)-1]);
270 kfree(output.pointer);
271 return status; 189 return status;
272} 190}
273 191
@@ -275,27 +193,14 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
275 struct device_attribute *attr, 193 struct device_attribute *attr,
276 char *buf) 194 char *buf)
277{ 195{
278 acpi_handle handle; 196 acpi_status status = -EINVAL;
279 acpi_status status; 197 union acpi_object *obj, *ret_obj;
280 struct acpi_object_list input; 198 u64 req, res;
281 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 199
282 union acpi_object params[4]; 200 obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
283 union acpi_object *ret_obj; 201 if (!obj)
284 u64 req;
285
286 input.count = 4;
287 ppi_assign_params(params, TPM_PPI_FN_GETRSP);
288 input.pointer = params;
289 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
290 ACPI_UINT32_MAX, ppi_callback, NULL,
291 tpm_device_name, &handle);
292 if (ACPI_FAILURE(status))
293 return -ENXIO; 202 return -ENXIO;
294 203
295 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
296 ACPI_TYPE_PACKAGE);
297 if (ACPI_FAILURE(status))
298 return -ENOMEM;
299 /* 204 /*
300 * parameter output.pointer should be of package type, including 205 * parameter output.pointer should be of package type, including
301 * 3 integers. The first means function return code, the second means 206 * 3 integers. The first means function return code, the second means
@@ -303,115 +208,82 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
303 * the most recent TPM operation request. Only if the first is 0, and 208 * the most recent TPM operation request. Only if the first is 0, and
304 * the second integer is not 0, the response makes sense. 209 * the second integer is not 0, the response makes sense.
305 */ 210 */
306 ret_obj = ((union acpi_object *)output.pointer)->package.elements; 211 ret_obj = obj->package.elements;
307 if (ret_obj->type != ACPI_TYPE_INTEGER) { 212 if (obj->package.count < 3 ||
308 status = -EINVAL; 213 ret_obj[0].type != ACPI_TYPE_INTEGER ||
214 ret_obj[1].type != ACPI_TYPE_INTEGER ||
215 ret_obj[2].type != ACPI_TYPE_INTEGER)
309 goto cleanup; 216 goto cleanup;
310 } 217
311 if (ret_obj->integer.value) { 218 if (ret_obj[0].integer.value) {
312 status = -EFAULT; 219 status = -EFAULT;
313 goto cleanup; 220 goto cleanup;
314 } 221 }
315 ret_obj++; 222
316 if (ret_obj->type != ACPI_TYPE_INTEGER) { 223 req = ret_obj[1].integer.value;
317 status = -EINVAL; 224 res = ret_obj[2].integer.value;
318 goto cleanup; 225 if (req) {
319 } 226 if (res == 0)
320 if (ret_obj->integer.value) {
321 req = ret_obj->integer.value;
322 ret_obj++;
323 if (ret_obj->type != ACPI_TYPE_INTEGER) {
324 status = -EINVAL;
325 goto cleanup;
326 }
327 if (ret_obj->integer.value == 0)
328 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 227 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
329 "0: Success"); 228 "0: Success");
330 else if (ret_obj->integer.value == 0xFFFFFFF0) 229 else if (res == 0xFFFFFFF0)
331 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 230 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
332 "0xFFFFFFF0: User Abort"); 231 "0xFFFFFFF0: User Abort");
333 else if (ret_obj->integer.value == 0xFFFFFFF1) 232 else if (res == 0xFFFFFFF1)
334 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 233 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
335 "0xFFFFFFF1: BIOS Failure"); 234 "0xFFFFFFF1: BIOS Failure");
336 else if (ret_obj->integer.value >= 1 && 235 else if (res >= 1 && res <= 0x00000FFF)
337 ret_obj->integer.value <= 0x00000FFF)
338 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 236 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
339 req, ret_obj->integer.value, 237 req, res, "Corresponding TPM error");
340 "Corresponding TPM error");
341 else 238 else
342 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 239 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
343 req, ret_obj->integer.value, 240 req, res, "Error");
344 "Error");
345 } else { 241 } else {
346 status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 242 status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n",
347 ret_obj->integer.value, "No Recent Request"); 243 req, "No Recent Request");
348 } 244 }
245
349cleanup: 246cleanup:
350 kfree(output.pointer); 247 ACPI_FREE(obj);
351 return status; 248 return status;
352} 249}
353 250
354static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) 251static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
355{ 252{
356 char *str = buf;
357 char version[PPI_VERSION_LEN + 1];
358 acpi_handle handle;
359 acpi_status status;
360 struct acpi_object_list input;
361 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
362 union acpi_object params[4];
363 union acpi_object obj;
364 int i; 253 int i;
365 u32 ret; 254 u32 ret;
366 char *info[] = { 255 char *str = buf;
256 union acpi_object *obj, tmp;
257 union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
258
259 static char *info[] = {
367 "Not implemented", 260 "Not implemented",
368 "BIOS only", 261 "BIOS only",
369 "Blocked for OS by BIOS", 262 "Blocked for OS by BIOS",
370 "User required", 263 "User required",
371 "User not required", 264 "User not required",
372 }; 265 };
373 input.count = 4;
374 ppi_assign_params(params, TPM_PPI_FN_VERSION);
375 input.pointer = params;
376 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
377 ACPI_UINT32_MAX, ppi_callback, NULL,
378 tpm_device_name, &handle);
379 if (ACPI_FAILURE(status))
380 return -ENXIO;
381 266
382 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 267 if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
383 ACPI_TYPE_STRING); 268 1 << TPM_PPI_FN_GETOPR))
384 if (ACPI_FAILURE(status))
385 return -ENOMEM;
386
387 strlcpy(version,
388 ((union acpi_object *)output.pointer)->string.pointer,
389 PPI_VERSION_LEN + 1);
390 kfree(output.pointer);
391 output.length = ACPI_ALLOCATE_BUFFER;
392 output.pointer = NULL;
393 if (strcmp(version, "1.2") < 0)
394 return -EPERM; 269 return -EPERM;
395 270
396 params[2].integer.value = TPM_PPI_FN_GETOPR; 271 tmp.integer.type = ACPI_TYPE_INTEGER;
397 params[3].package.count = 1;
398 obj.type = ACPI_TYPE_INTEGER;
399 params[3].package.elements = &obj;
400 for (i = start; i <= end; i++) { 272 for (i = start; i <= end; i++) {
401 obj.integer.value = i; 273 tmp.integer.value = i;
402 status = acpi_evaluate_object_typed(handle, "_DSM", 274 obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
403 &input, &output, ACPI_TYPE_INTEGER); 275 if (!obj) {
404 if (ACPI_FAILURE(status))
405 return -ENOMEM; 276 return -ENOMEM;
277 } else {
278 ret = obj->integer.value;
279 ACPI_FREE(obj);
280 }
406 281
407 ret = ((union acpi_object *)output.pointer)->integer.value;
408 if (ret > 0 && ret < ARRAY_SIZE(info)) 282 if (ret > 0 && ret < ARRAY_SIZE(info))
409 str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", 283 str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n",
410 i, ret, info[ret]); 284 i, ret, info[ret]);
411 kfree(output.pointer);
412 output.length = ACPI_ALLOCATE_BUFFER;
413 output.pointer = NULL;
414 } 285 }
286
415 return str - buf; 287 return str - buf;
416} 288}
417 289
@@ -453,6 +325,12 @@ static struct attribute_group ppi_attr_grp = {
453 325
454int tpm_add_ppi(struct kobject *parent) 326int tpm_add_ppi(struct kobject *parent)
455{ 327{
328 /* Cache TPM ACPI handle and version string */
329 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
330 ppi_callback, NULL, NULL, &tpm_ppi_handle);
331 if (tpm_ppi_handle == NULL)
332 return -ENODEV;
333
456 return sysfs_create_group(parent, &ppi_attr_grp); 334 return sysfs_create_group(parent, &ppi_attr_grp);
457} 335}
458 336