diff options
author | Marcel Selhorst <selhorst@crypto.rub.de> | 2005-08-05 14:59:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-05 15:22:37 -0400 |
commit | f9abb020405c94edb0717315f1510086b1574a22 (patch) | |
tree | 768cf082ab003287cdf24a5c09143cac96ebcd51 /drivers/char/tpm | |
parent | 30e835e36648b15fb80797ace0a0e2afcf97618d (diff) |
[PATCH] tpm_infineon: Support for new TPM 1.2 and PNPACPI
This patch includes support for the new Infineon Trusted Platform Module
SLB 9635 TT 1.2 and does further include ACPI-support for both chip
versions (SLD 9630 TT 1.1 and SLB9635 TT 1.2). Since the ioports and
configuration registers are not correctly set on some machines, the
configuration is now done via PNPACPI, which reads out the correct values
out of the DSDT-table. Note that you have to have CONFIG_PNP,
CONFIG_ACPI_BUS and CONFIG_PNPACPI enabled to run this driver (assuming
that mainboards including a TPM do have the need for ACPI anyway).
Signed-off-by: Marcel Selhorst <selhorst@crypto.rub.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/Kconfig | 11 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_infineon.c | 146 |
2 files changed, 113 insertions, 44 deletions
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 94a3b3e20bf9..79e9832ef1f3 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig | |||
@@ -17,6 +17,8 @@ config TCG_TPM | |||
17 | obtained at: <http://sourceforge.net/projects/trousers>. To | 17 | obtained at: <http://sourceforge.net/projects/trousers>. To |
18 | compile this driver as a module, choose M here; the module | 18 | compile this driver as a module, choose M here; the module |
19 | will be called tpm. If unsure, say N. | 19 | will be called tpm. If unsure, say N. |
20 | Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI_BUS | ||
21 | and CONFIG_PNPACPI. | ||
20 | 22 | ||
21 | config TCG_NSC | 23 | config TCG_NSC |
22 | tristate "National Semiconductor TPM Interface" | 24 | tristate "National Semiconductor TPM Interface" |
@@ -36,12 +38,13 @@ config TCG_ATMEL | |||
36 | as a module, choose M here; the module will be called tpm_atmel. | 38 | as a module, choose M here; the module will be called tpm_atmel. |
37 | 39 | ||
38 | config TCG_INFINEON | 40 | config TCG_INFINEON |
39 | tristate "Infineon Technologies SLD 9630 TPM Interface" | 41 | tristate "Infineon Technologies TPM Interface" |
40 | depends on TCG_TPM | 42 | depends on TCG_TPM && PNPACPI |
41 | ---help--- | 43 | ---help--- |
42 | If you have a TPM security chip from Infineon Technologies | 44 | If you have a TPM security chip from Infineon Technologies |
43 | say Yes and it will be accessible from within Linux. To | 45 | (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it |
44 | compile this driver as a module, choose M here; the module | 46 | will be accessible from within Linux. |
47 | To compile this driver as a module, choose M here; the module | ||
45 | will be called tpm_infineon. | 48 | will be called tpm_infineon. |
46 | Further information on this driver and the supported hardware | 49 | Further information on this driver and the supported hardware |
47 | can be found at http://www.prosec.rub.de/tpm | 50 | can be found at http://www.prosec.rub.de/tpm |
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 0e3241645c19..dc8c540391fd 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Description: | 2 | * Description: |
3 | * Device Driver for the Infineon Technologies | 3 | * Device Driver for the Infineon Technologies |
4 | * SLD 9630 TT Trusted Platform Module | 4 | * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module |
5 | * Specifications at www.trustedcomputinggroup.org | 5 | * Specifications at www.trustedcomputinggroup.org |
6 | * | 6 | * |
7 | * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de> | 7 | * Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de> |
@@ -12,9 +12,10 @@ | |||
12 | * modify it under the terms of the GNU General Public License as | 12 | * modify it under the terms of the GNU General Public License as |
13 | * published by the Free Software Foundation, version 2 of the | 13 | * published by the Free Software Foundation, version 2 of the |
14 | * License. | 14 | * License. |
15 | * | ||
16 | */ | 15 | */ |
17 | 16 | ||
17 | #include <acpi/acpi_bus.h> | ||
18 | #include <linux/pnp.h> | ||
18 | #include "tpm.h" | 19 | #include "tpm.h" |
19 | 20 | ||
20 | /* Infineon specific definitions */ | 21 | /* Infineon specific definitions */ |
@@ -26,8 +27,11 @@ | |||
26 | #define TPM_MSLEEP_TIME 3 | 27 | #define TPM_MSLEEP_TIME 3 |
27 | /* gives number of max. msleep()-calls before throwing timeout */ | 28 | /* gives number of max. msleep()-calls before throwing timeout */ |
28 | #define TPM_MAX_TRIES 5000 | 29 | #define TPM_MAX_TRIES 5000 |
29 | #define TCPA_INFINEON_DEV_VEN_VALUE 0x15D1 | 30 | #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 |
30 | #define TPM_DATA (TPM_ADDR + 1) & 0xff | 31 | |
32 | /* These values will be filled after ACPI-call */ | ||
33 | static int TPM_INF_DATA = 0; | ||
34 | static int TPM_INF_ADDR = 0; | ||
31 | 35 | ||
32 | /* TPM header definitions */ | 36 | /* TPM header definitions */ |
33 | enum infineon_tpm_header { | 37 | enum infineon_tpm_header { |
@@ -305,9 +309,10 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) | |||
305 | 309 | ||
306 | static void tpm_inf_cancel(struct tpm_chip *chip) | 310 | static void tpm_inf_cancel(struct tpm_chip *chip) |
307 | { | 311 | { |
308 | /* Nothing yet! | 312 | /* |
309 | This has something to do with the internal functions | 313 | Since we are using the legacy mode to communicate |
310 | of the TPM. Abort isn't really necessary... | 314 | with the TPM, we have no cancel functions, but have |
315 | a workaround for interrupting the TPM through WTX. | ||
311 | */ | 316 | */ |
312 | } | 317 | } |
313 | 318 | ||
@@ -345,6 +350,32 @@ static struct tpm_vendor_specific tpm_inf = { | |||
345 | .miscdev = {.fops = &inf_ops,}, | 350 | .miscdev = {.fops = &inf_ops,}, |
346 | }; | 351 | }; |
347 | 352 | ||
353 | static const struct pnp_device_id tpm_pnp_tbl[] = { | ||
354 | /* Infineon TPMs */ | ||
355 | {"IFX0101", 0}, | ||
356 | {"IFX0102", 0}, | ||
357 | {"", 0} | ||
358 | }; | ||
359 | |||
360 | static int __devinit tpm_inf_acpi_probe(struct pnp_dev *dev, | ||
361 | const struct pnp_device_id *dev_id) | ||
362 | { | ||
363 | TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); | ||
364 | TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); | ||
365 | tpm_inf.base = pnp_port_start(dev, 1); | ||
366 | dev_info(&dev->dev, "Found %s with ID %s\n", | ||
367 | dev->name, dev_id->id); | ||
368 | if (!((tpm_inf.base >> 8) & 0xff)) | ||
369 | tpm_inf.base = 0; | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static struct pnp_driver tpm_inf_pnp = { | ||
374 | .name = "tpm_inf_pnp", | ||
375 | .id_table = tpm_pnp_tbl, | ||
376 | .probe = tpm_inf_acpi_probe, | ||
377 | }; | ||
378 | |||
348 | static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | 379 | static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, |
349 | const struct pci_device_id *pci_id) | 380 | const struct pci_device_id *pci_id) |
350 | { | 381 | { |
@@ -353,64 +384,99 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | |||
353 | int vendorid[2]; | 384 | int vendorid[2]; |
354 | int version[2]; | 385 | int version[2]; |
355 | int productid[2]; | 386 | int productid[2]; |
387 | char chipname[20]; | ||
356 | 388 | ||
357 | if (pci_enable_device(pci_dev)) | 389 | if (pci_enable_device(pci_dev)) |
358 | return -EIO; | 390 | return -EIO; |
359 | 391 | ||
360 | dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); | 392 | dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); |
361 | 393 | ||
394 | /* read IO-ports from ACPI */ | ||
395 | pnp_register_driver(&tpm_inf_pnp); | ||
396 | pnp_unregister_driver(&tpm_inf_pnp); | ||
397 | |||
398 | /* Make sure, we have received valid config ports */ | ||
399 | if (!TPM_INF_ADDR) { | ||
400 | pci_disable_device(pci_dev); | ||
401 | return -EIO; | ||
402 | } | ||
403 | |||
362 | /* query chip for its vendor, its version number a.s.o. */ | 404 | /* query chip for its vendor, its version number a.s.o. */ |
363 | outb(ENABLE_REGISTER_PAIR, TPM_ADDR); | 405 | outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR); |
364 | outb(IDVENL, TPM_ADDR); | 406 | outb(IDVENL, TPM_INF_ADDR); |
365 | vendorid[1] = inb(TPM_DATA); | 407 | vendorid[1] = inb(TPM_INF_DATA); |
366 | outb(IDVENH, TPM_ADDR); | 408 | outb(IDVENH, TPM_INF_ADDR); |
367 | vendorid[0] = inb(TPM_DATA); | 409 | vendorid[0] = inb(TPM_INF_DATA); |
368 | outb(IDPDL, TPM_ADDR); | 410 | outb(IDPDL, TPM_INF_ADDR); |
369 | productid[1] = inb(TPM_DATA); | 411 | productid[1] = inb(TPM_INF_DATA); |
370 | outb(IDPDH, TPM_ADDR); | 412 | outb(IDPDH, TPM_INF_ADDR); |
371 | productid[0] = inb(TPM_DATA); | 413 | productid[0] = inb(TPM_INF_DATA); |
372 | outb(CHIP_ID1, TPM_ADDR); | 414 | outb(CHIP_ID1, TPM_INF_ADDR); |
373 | version[1] = inb(TPM_DATA); | 415 | version[1] = inb(TPM_INF_DATA); |
374 | outb(CHIP_ID2, TPM_ADDR); | 416 | outb(CHIP_ID2, TPM_INF_ADDR); |
375 | version[0] = inb(TPM_DATA); | 417 | version[0] = inb(TPM_INF_DATA); |
376 | 418 | ||
377 | if ((vendorid[0] << 8 | vendorid[1]) == (TCPA_INFINEON_DEV_VEN_VALUE)) { | 419 | switch ((productid[0] << 8) | productid[1]) { |
378 | 420 | case 6: | |
379 | /* read IO-ports from TPM */ | 421 | sprintf(chipname, " (SLD 9630 TT 1.1)"); |
380 | outb(IOLIMH, TPM_ADDR); | 422 | break; |
381 | ioh = inb(TPM_DATA); | 423 | case 11: |
382 | outb(IOLIML, TPM_ADDR); | 424 | sprintf(chipname, " (SLB 9635 TT 1.2)"); |
383 | iol = inb(TPM_DATA); | 425 | break; |
384 | tpm_inf.base = (ioh << 8) | iol; | 426 | default: |
427 | sprintf(chipname, " (unknown chip)"); | ||
428 | break; | ||
429 | } | ||
430 | chipname[19] = 0; | ||
431 | |||
432 | if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { | ||
385 | 433 | ||
386 | if (tpm_inf.base == 0) { | 434 | if (tpm_inf.base == 0) { |
387 | dev_err(&pci_dev->dev, "No IO-ports set!\n"); | 435 | dev_err(&pci_dev->dev, "No IO-ports found!\n"); |
388 | pci_disable_device(pci_dev); | 436 | pci_disable_device(pci_dev); |
389 | return -ENODEV; | 437 | return -EIO; |
438 | } | ||
439 | /* configure TPM with IO-ports */ | ||
440 | outb(IOLIMH, TPM_INF_ADDR); | ||
441 | outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); | ||
442 | outb(IOLIML, TPM_INF_ADDR); | ||
443 | outb((tpm_inf.base & 0xff), TPM_INF_DATA); | ||
444 | |||
445 | /* control if IO-ports are set correctly */ | ||
446 | outb(IOLIMH, TPM_INF_ADDR); | ||
447 | ioh = inb(TPM_INF_DATA); | ||
448 | outb(IOLIML, TPM_INF_ADDR); | ||
449 | iol = inb(TPM_INF_DATA); | ||
450 | |||
451 | if ((ioh << 8 | iol) != tpm_inf.base) { | ||
452 | dev_err(&pci_dev->dev, | ||
453 | "Could not set IO-ports to %04x\n", | ||
454 | tpm_inf.base); | ||
455 | pci_disable_device(pci_dev); | ||
456 | return -EIO; | ||
390 | } | 457 | } |
391 | 458 | ||
392 | /* activate register */ | 459 | /* activate register */ |
393 | outb(TPM_DAR, TPM_ADDR); | 460 | outb(TPM_DAR, TPM_INF_ADDR); |
394 | outb(0x01, TPM_DATA); | 461 | outb(0x01, TPM_INF_DATA); |
395 | outb(DISABLE_REGISTER_PAIR, TPM_ADDR); | 462 | outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); |
396 | 463 | ||
397 | /* disable RESET, LP and IRQC */ | 464 | /* disable RESET, LP and IRQC */ |
398 | outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); | 465 | outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); |
399 | 466 | ||
400 | /* Finally, we're done, print some infos */ | 467 | /* Finally, we're done, print some infos */ |
401 | dev_info(&pci_dev->dev, "TPM found: " | 468 | dev_info(&pci_dev->dev, "TPM found: " |
469 | "config base 0x%x, " | ||
402 | "io base 0x%x, " | 470 | "io base 0x%x, " |
403 | "chip version %02x%02x, " | 471 | "chip version %02x%02x, " |
404 | "vendor id %x%x (Infineon), " | 472 | "vendor id %x%x (Infineon), " |
405 | "product id %02x%02x" | 473 | "product id %02x%02x" |
406 | "%s\n", | 474 | "%s\n", |
475 | TPM_INF_ADDR, | ||
407 | tpm_inf.base, | 476 | tpm_inf.base, |
408 | version[0], version[1], | 477 | version[0], version[1], |
409 | vendorid[0], vendorid[1], | 478 | vendorid[0], vendorid[1], |
410 | productid[0], productid[1], ((productid[0] == 0) | 479 | productid[0], productid[1], chipname); |
411 | && (productid[1] == | ||
412 | 6)) ? | ||
413 | " (SLD 9630 TT 1.1)" : ""); | ||
414 | 480 | ||
415 | rc = tpm_register_hardware(pci_dev, &tpm_inf); | 481 | rc = tpm_register_hardware(pci_dev, &tpm_inf); |
416 | if (rc < 0) { | 482 | if (rc < 0) { |
@@ -462,6 +528,6 @@ module_init(init_inf); | |||
462 | module_exit(cleanup_inf); | 528 | module_exit(cleanup_inf); |
463 | 529 | ||
464 | MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); | 530 | MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); |
465 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT"); | 531 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); |
466 | MODULE_VERSION("1.4"); | 532 | MODULE_VERSION("1.5"); |
467 | MODULE_LICENSE("GPL"); | 533 | MODULE_LICENSE("GPL"); |