aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2013-12-19 07:38:17 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-05 10:07:14 -0500
commit84b1667dea233d2af29b5138bfd2d70417cfa720 (patch)
tree123a113cca77549852d92832a85a68f6f7f0957f /drivers/char
parent529139c9736ac71040e589c32ba87d35cc8cbf8f (diff)
ACPI / TPM: replace open-coded _DSM code with helper functions
Use helper functions to simplify _DSM related code in TPM driver. This patch also help to get rid of following warning messages: [ 163.509575] ACPI Error: Incorrect return type [Buffer] requested [Package] (20130517/nsxfeval-135) But there is still an warning left. [ 181.637366] ACPI Warning: \_SB_.IIO0.LPC0.TPM_._DSM: Argument #4 type mismatch - Found [Buffer], ACPI requires [Package] (20130517/nsarguments-95) Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/tpm/tpm_ppi.c404
1 files changed, 145 insertions, 259 deletions
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 1e9cc11ac76a..d542ac6d0ae0 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -2,15 +2,6 @@
2#include <acpi/acpi_drivers.h> 2#include <acpi/acpi_drivers.h>
3#include "tpm.h" 3#include "tpm.h"
4 4
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 5#define TPM_PPI_REVISION_ID 1
15#define TPM_PPI_FN_VERSION 1 6#define TPM_PPI_FN_VERSION 1
16#define TPM_PPI_FN_SUBREQ 2 7#define TPM_PPI_FN_SUBREQ 2
@@ -24,250 +15,185 @@ static char *tpm_device_name = "TPM";
24#define PPI_VS_REQ_END 255 15#define PPI_VS_REQ_END 255
25#define PPI_VERSION_LEN 3 16#define PPI_VERSION_LEN 3
26 17
18static const u8 tpm_ppi_uuid[] = {
19 0xA6, 0xFA, 0xDD, 0x3D,
20 0x1B, 0x36,
21 0xB4, 0x4E,
22 0xA4, 0x24,
23 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
24};
25
26static char *tpm_device_name = "TPM";
27static char tpm_ppi_version[PPI_VERSION_LEN + 1];
28static acpi_handle tpm_ppi_handle;
29
27static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, 30static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
28 void **return_value) 31 void **return_value)
29{ 32{
30 acpi_status status = AE_OK; 33 acpi_status status = AE_OK;
31 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 34 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
32 35
33 if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer))) { 36 status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
34 if (strstr(buffer.pointer, context) != NULL) { 37 if (ACPI_FAILURE(status))
35 *return_value = handle; 38 return AE_OK;
36 status = AE_CTRL_TERMINATE; 39
40 if (strstr(buffer.pointer, context) != NULL) {
41 union acpi_object *obj;
42
43 /* Cache version string */
44 obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
45 TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
46 NULL, ACPI_TYPE_STRING);
47 if (obj) {
48 strlcpy(tpm_ppi_version, obj->string.pointer,
49 PPI_VERSION_LEN + 1);
50 ACPI_FREE(obj);
37 } 51 }
38 kfree(buffer.pointer); 52
53 *return_value = handle;
54 status = AE_CTRL_TERMINATE;
39 } 55 }
56 kfree(buffer.pointer);
40 57
41 return status; 58 return status;
42} 59}
43 60
44static inline void ppi_assign_params(union acpi_object params[4], 61static inline union acpi_object *
45 u64 function_num) 62tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
46{ 63{
47 params[0].type = ACPI_TYPE_BUFFER; 64 BUG_ON(!tpm_ppi_handle);
48 params[0].buffer.length = sizeof(tpm_ppi_uuid); 65 return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid,
49 params[0].buffer.pointer = (char *)tpm_ppi_uuid; 66 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} 67}
58 68
59static ssize_t tpm_show_ppi_version(struct device *dev, 69static ssize_t tpm_show_ppi_version(struct device *dev,
60 struct device_attribute *attr, char *buf) 70 struct device_attribute *attr, char *buf)
61{ 71{
62 acpi_handle handle; 72 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} 73}
87 74
88static ssize_t tpm_show_ppi_request(struct device *dev, 75static ssize_t tpm_show_ppi_request(struct device *dev,
89 struct device_attribute *attr, char *buf) 76 struct device_attribute *attr, char *buf)
90{ 77{
91 acpi_handle handle; 78 ssize_t size = -EINVAL;
92 acpi_status status; 79 union acpi_object *obj;
93 struct acpi_object_list input; 80
94 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 81 obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
95 union acpi_object params[4]; 82 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; 83 return -ENXIO;
106 84
107 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
108 ACPI_TYPE_PACKAGE);
109 if (ACPI_FAILURE(status))
110 return -ENOMEM;
111 /* 85 /*
112 * output.pointer should be of package type, including two integers. 86 * output.pointer should be of package type, including two integers.
113 * The first is function return code, 0 means success and 1 means 87 * 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 88 * error. The second is pending TPM operation requested by the OS, 0
115 * means none and >0 means operation value. 89 * means none and >0 means operation value.
116 */ 90 */
117 ret_obj = ((union acpi_object *)output.pointer)->package.elements; 91 if (obj->package.count == 2 &&
118 if (ret_obj->type == ACPI_TYPE_INTEGER) { 92 obj->package.elements[0].type == ACPI_TYPE_INTEGER &&
119 if (ret_obj->integer.value) { 93 obj->package.elements[1].type == ACPI_TYPE_INTEGER) {
120 status = -EFAULT; 94 if (obj->package.elements[0].integer.value)
121 goto cleanup; 95 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 96 else
128 status = -EINVAL; 97 size = scnprintf(buf, PAGE_SIZE, "%llu\n",
129 } else { 98 obj->package.elements[1].integer.value);
130 status = -EINVAL;
131 } 99 }
132cleanup: 100
133 kfree(output.pointer); 101 ACPI_FREE(obj);
134 return status; 102
103 return size;
135} 104}
136 105
137static ssize_t tpm_store_ppi_request(struct device *dev, 106static ssize_t tpm_store_ppi_request(struct device *dev,
138 struct device_attribute *attr, 107 struct device_attribute *attr,
139 const char *buf, size_t count) 108 const char *buf, size_t count)
140{ 109{
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; 110 u32 req;
149 u64 ret; 111 u64 ret;
112 int func = TPM_PPI_FN_SUBREQ;
113 union acpi_object *obj, tmp;
114 union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
150 115
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 /* 116 /*
171 * the function to submit TPM operation request to pre-os environment 117 * the function to submit TPM operation request to pre-os environment
172 * is updated with function index from SUBREQ to SUBREQ2 since PPI 118 * is updated with function index from SUBREQ to SUBREQ2 since PPI
173 * version 1.1 119 * version 1.1
174 */ 120 */
175 if (strcmp(version, "1.1") == -1) 121 if (strcmp(tpm_ppi_version, "1.1") >= 0)
176 params[2].integer.value = TPM_PPI_FN_SUBREQ; 122 func = TPM_PPI_FN_SUBREQ2;
177 else 123
178 params[2].integer.value = TPM_PPI_FN_SUBREQ2;
179 /* 124 /*
180 * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS 125 * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS
181 * accept buffer/string/integer type, but some BIOS accept buffer/ 126 * 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 127 * 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. 128 * for compatibility, and use package type since 1.2 according to spec.
184 */ 129 */
185 if (strcmp(version, "1.2") == -1) { 130 if (strcmp(tpm_ppi_version, "1.2") < 0) {
186 params[3].type = ACPI_TYPE_BUFFER; 131 if (sscanf(buf, "%d", &req) != 1)
187 params[3].buffer.length = sizeof(req); 132 return -EINVAL;
188 sscanf(buf, "%d", &req); 133 argv4.type = ACPI_TYPE_BUFFER;
189 params[3].buffer.pointer = (char *)&req; 134 argv4.buffer.length = sizeof(req);
135 argv4.buffer.pointer = (u8 *)&req;
190 } else { 136 } else {
191 params[3].package.count = 1; 137 tmp.type = ACPI_TYPE_INTEGER;
192 obj.type = ACPI_TYPE_INTEGER; 138 if (sscanf(buf, "%llu", &tmp.integer.value) != 1)
193 sscanf(buf, "%llu", &obj.integer.value); 139 return -EINVAL;
194 params[3].package.elements = &obj; 140 }
141
142 obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
143 if (!obj) {
144 return -ENXIO;
145 } else {
146 ret = obj->integer.value;
147 ACPI_FREE(obj);
195 } 148 }
196 149
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) 150 if (ret == 0)
203 status = (acpi_status)count; 151 return (acpi_status)count;
204 else if (ret == 1) 152
205 status = -EPERM; 153 return (ret == 1) ? -EPERM : -EFAULT;
206 else
207 status = -EFAULT;
208 kfree(output.pointer);
209 return status;
210} 154}
211 155
212static ssize_t tpm_show_ppi_transition_action(struct device *dev, 156static ssize_t tpm_show_ppi_transition_action(struct device *dev,
213 struct device_attribute *attr, 157 struct device_attribute *attr,
214 char *buf) 158 char *buf)
215{ 159{
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; 160 u32 ret;
223 char *info[] = { 161 acpi_status status;
162 union acpi_object *obj = NULL;
163 union acpi_object tmp = {
164 .buffer.type = ACPI_TYPE_BUFFER,
165 .buffer.length = 0,
166 .buffer.pointer = NULL
167 };
168
169 static char *info[] = {
224 "None", 170 "None",
225 "Shutdown", 171 "Shutdown",
226 "Reboot", 172 "Reboot",
227 "OS Vendor-specific", 173 "OS Vendor-specific",
228 "Error", 174 "Error",
229 }; 175 };
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 176
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 /* 177 /*
247 * PPI spec defines params[3].type as empty package, but some platforms 178 * 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 179 * (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 180 * compatibility, define params[3].type as buffer, if PPI version < 1.2
250 */ 181 */
251 if (strcmp(version, "1.2") == -1) { 182 if (strcmp(tpm_ppi_version, "1.2") < 0)
252 params[3].type = ACPI_TYPE_BUFFER; 183 obj = &tmp;
253 params[3].buffer.length = 0; 184 obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
254 params[3].buffer.pointer = NULL; 185 if (!obj) {
186 return -ENXIO;
187 } else {
188 ret = obj->integer.value;
189 ACPI_FREE(obj);
255 } 190 }
256 params[2].integer.value = TPM_PPI_FN_GETACT; 191
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) 192 if (ret < ARRAY_SIZE(info) - 1)
266 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); 193 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]);
267 else 194 else
268 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, 195 status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret,
269 info[ARRAY_SIZE(info)-1]); 196 info[ARRAY_SIZE(info)-1]);
270 kfree(output.pointer);
271 return status; 197 return status;
272} 198}
273 199
@@ -275,27 +201,14 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
275 struct device_attribute *attr, 201 struct device_attribute *attr,
276 char *buf) 202 char *buf)
277{ 203{
278 acpi_handle handle; 204 acpi_status status = -EINVAL;
279 acpi_status status; 205 union acpi_object *obj, *ret_obj;
280 struct acpi_object_list input; 206 u64 req, res;
281 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 207
282 union acpi_object params[4]; 208 obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
283 union acpi_object *ret_obj; 209 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; 210 return -ENXIO;
294 211
295 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output,
296 ACPI_TYPE_PACKAGE);
297 if (ACPI_FAILURE(status))
298 return -ENOMEM;
299 /* 212 /*
300 * parameter output.pointer should be of package type, including 213 * parameter output.pointer should be of package type, including
301 * 3 integers. The first means function return code, the second means 214 * 3 integers. The first means function return code, the second means
@@ -303,115 +216,81 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
303 * the most recent TPM operation request. Only if the first is 0, and 216 * the most recent TPM operation request. Only if the first is 0, and
304 * the second integer is not 0, the response makes sense. 217 * the second integer is not 0, the response makes sense.
305 */ 218 */
306 ret_obj = ((union acpi_object *)output.pointer)->package.elements; 219 ret_obj = obj->package.elements;
307 if (ret_obj->type != ACPI_TYPE_INTEGER) { 220 if (obj->package.count < 3 ||
308 status = -EINVAL; 221 ret_obj[0].type != ACPI_TYPE_INTEGER ||
222 ret_obj[1].type != ACPI_TYPE_INTEGER ||
223 ret_obj[2].type != ACPI_TYPE_INTEGER)
309 goto cleanup; 224 goto cleanup;
310 } 225
311 if (ret_obj->integer.value) { 226 if (ret_obj[0].integer.value) {
312 status = -EFAULT; 227 status = -EFAULT;
313 goto cleanup; 228 goto cleanup;
314 } 229 }
315 ret_obj++; 230
316 if (ret_obj->type != ACPI_TYPE_INTEGER) { 231 req = ret_obj[1].integer.value;
317 status = -EINVAL; 232 res = ret_obj[2].integer.value;
318 goto cleanup; 233 if (req) {
319 } 234 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, 235 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
329 "0: Success"); 236 "0: Success");
330 else if (ret_obj->integer.value == 0xFFFFFFF0) 237 else if (res == 0xFFFFFFF0)
331 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 238 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
332 "0xFFFFFFF0: User Abort"); 239 "0xFFFFFFF0: User Abort");
333 else if (ret_obj->integer.value == 0xFFFFFFF1) 240 else if (res == 0xFFFFFFF1)
334 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, 241 status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req,
335 "0xFFFFFFF1: BIOS Failure"); 242 "0xFFFFFFF1: BIOS Failure");
336 else if (ret_obj->integer.value >= 1 && 243 else if (res >= 1 && res <= 0x00000FFF)
337 ret_obj->integer.value <= 0x00000FFF)
338 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 244 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
339 req, ret_obj->integer.value, 245 req, res, "Corresponding TPM error");
340 "Corresponding TPM error");
341 else 246 else
342 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", 247 status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n",
343 req, ret_obj->integer.value, 248 req, res, "Error");
344 "Error");
345 } else { 249 } else {
346 status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", 250 status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n",
347 ret_obj->integer.value, "No Recent Request"); 251 req, "No Recent Request");
348 } 252 }
253
349cleanup: 254cleanup:
350 kfree(output.pointer); 255 ACPI_FREE(obj);
351 return status; 256 return status;
352} 257}
353 258
354static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) 259static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
355{ 260{
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; 261 int i;
365 u32 ret; 262 u32 ret;
366 char *info[] = { 263 char *str = buf;
264 union acpi_object *obj, tmp;
265 union acpi_object argv = ACPI_INIT_DSM_ARGV4(1, &tmp);
266
267 static char *info[] = {
367 "Not implemented", 268 "Not implemented",
368 "BIOS only", 269 "BIOS only",
369 "Blocked for OS by BIOS", 270 "Blocked for OS by BIOS",
370 "User required", 271 "User required",
371 "User not required", 272 "User not required",
372 }; 273 };
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 274
382 status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, 275 if (strcmp(tpm_ppi_version, "1.2") < 0)
383 ACPI_TYPE_STRING);
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") == -1)
394 return -EPERM; 276 return -EPERM;
395 277
396 params[2].integer.value = TPM_PPI_FN_GETOPR; 278 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++) { 279 for (i = start; i <= end; i++) {
401 obj.integer.value = i; 280 tmp.integer.value = i;
402 status = acpi_evaluate_object_typed(handle, "_DSM", 281 obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
403 &input, &output, ACPI_TYPE_INTEGER); 282 if (!obj) {
404 if (ACPI_FAILURE(status))
405 return -ENOMEM; 283 return -ENOMEM;
284 } else {
285 ret = obj->integer.value;
286 ACPI_FREE(obj);
287 }
406 288
407 ret = ((union acpi_object *)output.pointer)->integer.value;
408 if (ret > 0 && ret < ARRAY_SIZE(info)) 289 if (ret > 0 && ret < ARRAY_SIZE(info))
409 str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", 290 str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n",
410 i, ret, info[ret]); 291 i, ret, info[ret]);
411 kfree(output.pointer);
412 output.length = ACPI_ALLOCATE_BUFFER;
413 output.pointer = NULL;
414 } 292 }
293
415 return str - buf; 294 return str - buf;
416} 295}
417 296
@@ -453,6 +332,13 @@ static struct attribute_group ppi_attr_grp = {
453 332
454int tpm_add_ppi(struct kobject *parent) 333int tpm_add_ppi(struct kobject *parent)
455{ 334{
335 /* Cache TPM ACPI handle and version string */
336 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
337 ppi_callback, NULL,
338 tpm_device_name, &tpm_ppi_handle);
339 if (tpm_ppi_handle == NULL)
340 return -ENODEV;
341
456 return sysfs_create_group(parent, &ppi_attr_grp); 342 return sysfs_create_group(parent, &ppi_attr_grp);
457} 343}
458 344