diff options
| -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"); |
