Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(524)

Side by Side Diff: drivers/tpm/slb9635_i2c/tpm.c

Issue 6683023: Add Infineon v05 TPM driver (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/u-boot-next.git@chromeos-v2010.09
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2011 Infineon Technologies
3 *
4 * Authors:
5 *
6 *
7 * Device driver for TCG/TCPA TPM (trusted platform module).
8 * Specifications at www.trustedcomputinggroup.org
9 *
10 * It is based on the Linux kernel driver tpm.c from Leendert van
11 * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation, version 2 of the
16 * License.
17 *
18 */
19
20 #include <malloc.h>
21
22 #include "tpm.h"
23 #include "tpm_tis_i2c.h"
24
25 /* global structure for tpm chip data */
26 struct tpm_chip g_chip;
27
28 enum tpm_duration {
29 TPM_SHORT = 0,
30 TPM_MEDIUM = 1,
31 TPM_LONG = 2,
32 TPM_UNDEFINED,
33 };
34
35 #define TPM_MAX_ORDINAL 243
36 #define TPM_MAX_PROTECTED_ORDINAL 12
37 #define TPM_PROTECTED_ORDINAL_MASK 0xFF
38
39 /*
40 * Array with one entry per ordinal defining the maximum amount
41 * of time the chip could take to return the result. The ordinal
42 * designation of short, medium or long is defined in a table in
43 * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
44 * values of the SHORT, MEDIUM, and LONG durations are retrieved
45 * from the chip during initialization with a call to tpm_get_timeouts.
46 */
47 static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
48 TPM_UNDEFINED, /* 0 */
49 TPM_UNDEFINED,
50 TPM_UNDEFINED,
51 TPM_UNDEFINED,
52 TPM_UNDEFINED,
53 TPM_UNDEFINED, /* 5 */
54 TPM_UNDEFINED,
55 TPM_UNDEFINED,
56 TPM_UNDEFINED,
57 TPM_UNDEFINED,
58 TPM_SHORT, /* 10 */
59 TPM_SHORT,
60 };
61
62 static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
63 TPM_UNDEFINED, /* 0 */
64 TPM_UNDEFINED,
65 TPM_UNDEFINED,
66 TPM_UNDEFINED,
67 TPM_UNDEFINED,
68 TPM_UNDEFINED, /* 5 */
69 TPM_UNDEFINED,
70 TPM_UNDEFINED,
71 TPM_UNDEFINED,
72 TPM_UNDEFINED,
73 TPM_SHORT, /* 10 */
74 TPM_SHORT,
75 TPM_MEDIUM,
76 TPM_LONG,
77 TPM_LONG,
78 TPM_MEDIUM, /* 15 */
79 TPM_SHORT,
80 TPM_SHORT,
81 TPM_MEDIUM,
82 TPM_LONG,
83 TPM_SHORT, /* 20 */
84 TPM_SHORT,
85 TPM_MEDIUM,
86 TPM_MEDIUM,
87 TPM_MEDIUM,
88 TPM_SHORT, /* 25 */
89 TPM_SHORT,
90 TPM_MEDIUM,
91 TPM_SHORT,
92 TPM_SHORT,
93 TPM_MEDIUM, /* 30 */
94 TPM_LONG,
95 TPM_MEDIUM,
96 TPM_SHORT,
97 TPM_SHORT,
98 TPM_SHORT, /* 35 */
99 TPM_MEDIUM,
100 TPM_MEDIUM,
101 TPM_UNDEFINED,
102 TPM_UNDEFINED,
103 TPM_MEDIUM, /* 40 */
104 TPM_LONG,
105 TPM_MEDIUM,
106 TPM_SHORT,
107 TPM_SHORT,
108 TPM_SHORT, /* 45 */
109 TPM_SHORT,
110 TPM_SHORT,
111 TPM_SHORT,
112 TPM_LONG,
113 TPM_MEDIUM, /* 50 */
114 TPM_MEDIUM,
115 TPM_UNDEFINED,
116 TPM_UNDEFINED,
117 TPM_UNDEFINED,
118 TPM_UNDEFINED, /* 55 */
119 TPM_UNDEFINED,
120 TPM_UNDEFINED,
121 TPM_UNDEFINED,
122 TPM_UNDEFINED,
123 TPM_MEDIUM, /* 60 */
124 TPM_MEDIUM,
125 TPM_MEDIUM,
126 TPM_SHORT,
127 TPM_SHORT,
128 TPM_MEDIUM, /* 65 */
129 TPM_UNDEFINED,
130 TPM_UNDEFINED,
131 TPM_UNDEFINED,
132 TPM_UNDEFINED,
133 TPM_SHORT, /* 70 */
134 TPM_SHORT,
135 TPM_UNDEFINED,
136 TPM_UNDEFINED,
137 TPM_UNDEFINED,
138 TPM_UNDEFINED, /* 75 */
139 TPM_UNDEFINED,
140 TPM_UNDEFINED,
141 TPM_UNDEFINED,
142 TPM_UNDEFINED,
143 TPM_LONG, /* 80 */
144 TPM_UNDEFINED,
145 TPM_MEDIUM,
146 TPM_LONG,
147 TPM_SHORT,
148 TPM_UNDEFINED, /* 85 */
149 TPM_UNDEFINED,
150 TPM_UNDEFINED,
151 TPM_UNDEFINED,
152 TPM_UNDEFINED,
153 TPM_SHORT, /* 90 */
154 TPM_SHORT,
155 TPM_SHORT,
156 TPM_SHORT,
157 TPM_SHORT,
158 TPM_UNDEFINED, /* 95 */
159 TPM_UNDEFINED,
160 TPM_UNDEFINED,
161 TPM_UNDEFINED,
162 TPM_UNDEFINED,
163 TPM_MEDIUM, /* 100 */
164 TPM_SHORT,
165 TPM_SHORT,
166 TPM_UNDEFINED,
167 TPM_UNDEFINED,
168 TPM_UNDEFINED, /* 105 */
169 TPM_UNDEFINED,
170 TPM_UNDEFINED,
171 TPM_UNDEFINED,
172 TPM_UNDEFINED,
173 TPM_SHORT, /* 110 */
174 TPM_SHORT,
175 TPM_SHORT,
176 TPM_SHORT,
177 TPM_SHORT,
178 TPM_SHORT, /* 115 */
179 TPM_SHORT,
180 TPM_SHORT,
181 TPM_UNDEFINED,
182 TPM_UNDEFINED,
183 TPM_LONG, /* 120 */
184 TPM_LONG,
185 TPM_MEDIUM,
186 TPM_UNDEFINED,
187 TPM_SHORT,
188 TPM_SHORT, /* 125 */
189 TPM_SHORT,
190 TPM_LONG,
191 TPM_SHORT,
192 TPM_SHORT,
193 TPM_SHORT, /* 130 */
194 TPM_MEDIUM,
195 TPM_UNDEFINED,
196 TPM_SHORT,
197 TPM_MEDIUM,
198 TPM_UNDEFINED, /* 135 */
199 TPM_UNDEFINED,
200 TPM_UNDEFINED,
201 TPM_UNDEFINED,
202 TPM_UNDEFINED,
203 TPM_SHORT, /* 140 */
204 TPM_SHORT,
205 TPM_UNDEFINED,
206 TPM_UNDEFINED,
207 TPM_UNDEFINED,
208 TPM_UNDEFINED, /* 145 */
209 TPM_UNDEFINED,
210 TPM_UNDEFINED,
211 TPM_UNDEFINED,
212 TPM_UNDEFINED,
213 TPM_SHORT, /* 150 */
214 TPM_MEDIUM,
215 TPM_MEDIUM,
216 TPM_SHORT,
217 TPM_SHORT,
218 TPM_UNDEFINED, /* 155 */
219 TPM_UNDEFINED,
220 TPM_UNDEFINED,
221 TPM_UNDEFINED,
222 TPM_UNDEFINED,
223 TPM_SHORT, /* 160 */
224 TPM_SHORT,
225 TPM_SHORT,
226 TPM_SHORT,
227 TPM_UNDEFINED,
228 TPM_UNDEFINED, /* 165 */
229 TPM_UNDEFINED,
230 TPM_UNDEFINED,
231 TPM_UNDEFINED,
232 TPM_UNDEFINED,
233 TPM_LONG, /* 170 */
234 TPM_UNDEFINED,
235 TPM_UNDEFINED,
236 TPM_UNDEFINED,
237 TPM_UNDEFINED,
238 TPM_UNDEFINED, /* 175 */
239 TPM_UNDEFINED,
240 TPM_UNDEFINED,
241 TPM_UNDEFINED,
242 TPM_UNDEFINED,
243 TPM_MEDIUM, /* 180 */
244 TPM_SHORT,
245 TPM_MEDIUM,
246 TPM_MEDIUM,
247 TPM_MEDIUM,
248 TPM_MEDIUM, /* 185 */
249 TPM_SHORT,
250 TPM_UNDEFINED,
251 TPM_UNDEFINED,
252 TPM_UNDEFINED,
253 TPM_UNDEFINED, /* 190 */
254 TPM_UNDEFINED,
255 TPM_UNDEFINED,
256 TPM_UNDEFINED,
257 TPM_UNDEFINED,
258 TPM_UNDEFINED, /* 195 */
259 TPM_UNDEFINED,
260 TPM_UNDEFINED,
261 TPM_UNDEFINED,
262 TPM_UNDEFINED,
263 TPM_SHORT, /* 200 */
264 TPM_UNDEFINED,
265 TPM_UNDEFINED,
266 TPM_UNDEFINED,
267 TPM_SHORT,
268 TPM_SHORT, /* 205 */
269 TPM_SHORT,
270 TPM_SHORT,
271 TPM_SHORT,
272 TPM_SHORT,
273 TPM_MEDIUM, /* 210 */
274 TPM_UNDEFINED,
275 TPM_MEDIUM,
276 TPM_MEDIUM,
277 TPM_MEDIUM,
278 TPM_UNDEFINED, /* 215 */
279 TPM_MEDIUM,
280 TPM_UNDEFINED,
281 TPM_UNDEFINED,
282 TPM_SHORT,
283 TPM_SHORT, /* 220 */
284 TPM_SHORT,
285 TPM_SHORT,
286 TPM_SHORT,
287 TPM_SHORT,
288 TPM_UNDEFINED, /* 225 */
289 TPM_UNDEFINED,
290 TPM_UNDEFINED,
291 TPM_UNDEFINED,
292 TPM_UNDEFINED,
293 TPM_SHORT, /* 230 */
294 TPM_LONG,
295 TPM_MEDIUM,
296 TPM_UNDEFINED,
297 TPM_UNDEFINED,
298 TPM_UNDEFINED, /* 235 */
299 TPM_UNDEFINED,
300 TPM_UNDEFINED,
301 TPM_UNDEFINED,
302 TPM_UNDEFINED,
303 TPM_SHORT, /* 240 */
304 TPM_UNDEFINED,
305 TPM_MEDIUM,
306 };
307
308 /*
309 * Returns max number of jiffies to wait
310 */
311 unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
312 {
313 int duration_idx = TPM_UNDEFINED;
314 int duration = 0;
315
316 if (ordinal < TPM_MAX_ORDINAL)
317 duration_idx = tpm_ordinal_duration[ordinal];
318 else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
319 TPM_MAX_PROTECTED_ORDINAL)
320 duration_idx =
321 tpm_protected_ordinal_duration[ordinal &
322 TPM_PROTECTED_ORDINAL_MASK];
323
324 if (duration_idx != TPM_UNDEFINED)
325 duration = chip->vendor.duration[duration_idx];
326 if (duration <= 0)
327 return 2 * 60 * HZ;
328 else
329 return duration;
330 }
331 EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
332
333 #define TPM_CMD_COUNT_BYTE 2
334 #define TPM_CMD_ORDINAL_BYTE 6
335
336 ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz)
337 {
338 ssize_t rc;
339 u32 count, ordinal;
340 unsigned long stop;
341
342 struct tpm_chip *chip = &g_chip;
343
344 /* switch endianess: big->little */
345 count = switch_endian32(&buf[TPM_CMD_COUNT_BYTE]);
346 ordinal = switch_endian32(&buf[TPM_CMD_ORDINAL_BYTE]);
347
348 if (count == 0) {
349 dev_err(chip->dev, "no data\n");
350 return -ENODATA;
351 }
352 if (count > bufsiz) {
353 dev_err(chip->dev,
354 "invalid count value %x %zx\n", count, bufsiz);
355 return -E2BIG;
356 }
357
358 rc = chip->vendor.send(chip, (u8 *) buf, count);
359 if (rc < 0) {
360 dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc);
361 goto out;
362 }
363
364 if (chip->vendor.irq)
365 goto out_recv;
366
367 jiffies = 0;
368 stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
369 do {
370 dbg_printf("waiting for status...\n");
371 u8 status = chip->vendor.status(chip);
372 if ((status & chip->vendor.req_complete_mask) ==
373 chip->vendor.req_complete_val) {
374 dbg_printf("...got it;\n");
375 goto out_recv;
376 }
377
378 if ((status == chip->vendor.req_canceled)) {
379 dev_err(chip->dev, "Operation Canceled\n");
380 rc = -ECANCELED;
381 goto out;
382 }
383
384 msleep2(TPM_TIMEOUT); /* CHECK */
385 } while (time_before(jiffies, stop));
386
387 chip->vendor.cancel(chip);
388 dev_err(chip->dev, "Operation Timed out\n");
389 rc = -ETIME;
390 goto out;
391
392 out_recv:
393
394 dbg_printf("out_recv: reading response...\n");
395 rc = chip->vendor.recv(chip, (u8 *) buf, bufsiz);
396 if (rc < 0)
397 dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc);
398 out:
399 return rc;
400 }
401
402 #define TPM_ERROR_SIZE 10
403
404 enum tpm_capabilities {
405 TPM_CAP_PROP = cpu_to_be32(5),
406 };
407
408 enum tpm_sub_capabilities {
409 TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115),
410 TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120),
411 };
412
413 static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
414 int len, const char *desc)
415 {
416 int err;
417
418 len = tpm_transmit((u8 *) cmd, len);
419 if (len < 0)
420 return len;
421 if (len == TPM_ERROR_SIZE) {
422 err = be32_to_cpu(cmd->header.out.return_code);
423 dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
424 return err;
425 }
426 return 0;
427 }
428
429 #define TPM_INTERNAL_RESULT_SIZE 200
430 #define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
431 #define TPM_ORD_GET_CAP cpu_to_be32(101)
432
433 static const struct tpm_input_header tpm_getcap_header = {
434 .tag = TPM_TAG_RQU_COMMAND,
435 .length = cpu_to_be32(22),
436 .ordinal = TPM_ORD_GET_CAP
437 };
438
439 void tpm_get_timeouts(struct tpm_chip *chip)
440 {
441 struct tpm_cmd_t tpm_cmd;
442 struct timeout_t *timeout_cap;
443 struct duration_t *duration_cap;
444 ssize_t rc;
445 u32 timeout;
446
447 tpm_cmd.header.in = tpm_getcap_header;
448 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
449 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
450 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
451
452 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
453 "attempting to determine the timeouts");
454 if (rc)
455 goto duration;
456
457 if (be32_to_cpu(tpm_cmd.header.out.length)
458 != 4 * sizeof(u32))
459 goto duration;
460
461 timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
462 /* Don't overwrite default if value is 0 */
463 timeout = be32_to_cpu(timeout_cap->a);
464 if (timeout)
465 chip->vendor.timeout_a = usecs_to_jiffies(timeout);
466 timeout = be32_to_cpu(timeout_cap->b);
467 if (timeout)
468 chip->vendor.timeout_b = usecs_to_jiffies(timeout);
469 timeout = be32_to_cpu(timeout_cap->c);
470 if (timeout)
471 chip->vendor.timeout_c = usecs_to_jiffies(timeout);
472 timeout = be32_to_cpu(timeout_cap->d);
473 if (timeout)
474 chip->vendor.timeout_d = usecs_to_jiffies(timeout);
475
476 duration:
477 tpm_cmd.header.in = tpm_getcap_header;
478 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
479 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
480 tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
481
482 rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
483 "attempting to determine the durations");
484 if (rc)
485 return;
486
487 if (be32_to_cpu(tpm_cmd.header.out.return_code)
488 != 3 * sizeof(u32))
489 return;
490 duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
491 chip->vendor.duration[TPM_SHORT] =
492 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
493 /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
494 * value wrong and apparently reports msecs rather than usecs. So we
495 * fix up the resulting too-small TPM_SHORT value to make things work.
496 */
497 if (chip->vendor.duration[TPM_SHORT] < (HZ / 100))
498 chip->vendor.duration[TPM_SHORT] = HZ;
499
500 chip->vendor.duration[TPM_MEDIUM] =
501 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
502 chip->vendor.duration[TPM_LONG] =
503 usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
504 }
505 EXPORT_SYMBOL_GPL(tpm_get_timeouts);
506
507 void tpm_continue_selftest(struct tpm_chip *chip)
508 {
509 u8 data[] = {
510 0, 193, /* TPM_TAG_RQU_COMMAND */
511 0, 0, 0, 10, /* length */
512 0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */
513 };
514
515 tpm_transmit(data, sizeof(data));
516 }
517 EXPORT_SYMBOL_GPL(tpm_continue_selftest);
518
519 /*
520 void tpm_startup(struct tpm_chip *chip)
521 {
522 u8 data[] = {
523 0, 193, *//* TPM_TAG_RQU_COMMAND *//*
524 0, 0, 0, 12, *//* length *//*
525 0, 0, 0, 153, *//* TPM_ORD_Startup *//*
526 0, 0
527 };
528
529 tpm_transmit(data, sizeof(data));
530 }
531 */
532 EXPORT_SYMBOL_GPL(tpm_startup);
533
534 struct tpm_chip *tpm_register_hardware(struct device *dev,
535 const struct tpm_vendor_specific *entry)
536 {
537 struct tpm_chip *chip;
538
539 /* Driver specific per-device data */
540 chip = &g_chip;
541 memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
542 chip->is_open = 1;
543
544 return chip;
545 }
546 EXPORT_SYMBOL_GPL(tpm_register_hardware);
547
548 int tpm_open(void)
549 {
550 if (g_chip.is_open)
551 return 0;
552 else
553 return tpm_tis_i2c_init(NULL);
554 }
555
556 void tpm_close(void)
557 {
558 if (g_chip.is_open) {
559 tpm_tis_i2c_cleanup(&g_chip);
560 g_chip.is_open = 0;
561 }
562 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698