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