diff options
Diffstat (limited to 'drivers/char/tpm/tpm_infineon.c')
-rw-r--r-- | drivers/char/tpm/tpm_infineon.c | 179 |
1 files changed, 77 insertions, 102 deletions
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 939e51e119e6..8198dbb7370f 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c | |||
@@ -5,6 +5,7 @@ | |||
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> |
8 | * Sirrix AG - security technologies, http://www.sirrix.com and | ||
8 | * Applied Data Security Group, Ruhr-University Bochum, Germany | 9 | * Applied Data Security Group, Ruhr-University Bochum, Germany |
9 | * Project-Homepage: http://www.prosec.rub.de/tpm | 10 | * Project-Homepage: http://www.prosec.rub.de/tpm |
10 | * | 11 | * |
@@ -29,9 +30,10 @@ | |||
29 | #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 | 30 | #define TPM_INFINEON_DEV_VEN_VALUE 0x15D1 |
30 | 31 | ||
31 | /* These values will be filled after PnP-call */ | 32 | /* These values will be filled after PnP-call */ |
32 | static int TPM_INF_DATA = 0; | 33 | static int TPM_INF_DATA; |
33 | static int TPM_INF_ADDR = 0; | 34 | static int TPM_INF_ADDR; |
34 | static int pnp_registered = 0; | 35 | static int TPM_INF_BASE; |
36 | static int TPM_INF_PORT_LEN; | ||
35 | 37 | ||
36 | /* TPM header definitions */ | 38 | /* TPM header definitions */ |
37 | enum infineon_tpm_header { | 39 | enum infineon_tpm_header { |
@@ -143,11 +145,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) | |||
143 | } | 145 | } |
144 | if (i == TPM_MAX_TRIES) { /* timeout occurs */ | 146 | if (i == TPM_MAX_TRIES) { /* timeout occurs */ |
145 | if (wait_for_bit == STAT_XFE) | 147 | if (wait_for_bit == STAT_XFE) |
146 | dev_err(&chip->pci_dev->dev, | 148 | dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n"); |
147 | "Timeout in wait(STAT_XFE)\n"); | ||
148 | if (wait_for_bit == STAT_RDA) | 149 | if (wait_for_bit == STAT_RDA) |
149 | dev_err(&chip->pci_dev->dev, | 150 | dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n"); |
150 | "Timeout in wait(STAT_RDA)\n"); | ||
151 | return -EIO; | 151 | return -EIO; |
152 | } | 152 | } |
153 | return 0; | 153 | return 0; |
@@ -170,7 +170,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) | |||
170 | static void tpm_wtx(struct tpm_chip *chip) | 170 | static void tpm_wtx(struct tpm_chip *chip) |
171 | { | 171 | { |
172 | number_of_wtx++; | 172 | number_of_wtx++; |
173 | dev_info(&chip->pci_dev->dev, "Granting WTX (%02d / %02d)\n", | 173 | dev_info(chip->dev, "Granting WTX (%02d / %02d)\n", |
174 | number_of_wtx, TPM_MAX_WTX_PACKAGES); | 174 | number_of_wtx, TPM_MAX_WTX_PACKAGES); |
175 | wait_and_send(chip, TPM_VL_VER); | 175 | wait_and_send(chip, TPM_VL_VER); |
176 | wait_and_send(chip, TPM_CTRL_WTX); | 176 | wait_and_send(chip, TPM_CTRL_WTX); |
@@ -181,7 +181,7 @@ static void tpm_wtx(struct tpm_chip *chip) | |||
181 | 181 | ||
182 | static void tpm_wtx_abort(struct tpm_chip *chip) | 182 | static void tpm_wtx_abort(struct tpm_chip *chip) |
183 | { | 183 | { |
184 | dev_info(&chip->pci_dev->dev, "Aborting WTX\n"); | 184 | dev_info(chip->dev, "Aborting WTX\n"); |
185 | wait_and_send(chip, TPM_VL_VER); | 185 | wait_and_send(chip, TPM_VL_VER); |
186 | wait_and_send(chip, TPM_CTRL_WTX_ABORT); | 186 | wait_and_send(chip, TPM_CTRL_WTX_ABORT); |
187 | wait_and_send(chip, 0x00); | 187 | wait_and_send(chip, 0x00); |
@@ -206,7 +206,7 @@ recv_begin: | |||
206 | } | 206 | } |
207 | 207 | ||
208 | if (buf[0] != TPM_VL_VER) { | 208 | if (buf[0] != TPM_VL_VER) { |
209 | dev_err(&chip->pci_dev->dev, | 209 | dev_err(chip->dev, |
210 | "Wrong transport protocol implementation!\n"); | 210 | "Wrong transport protocol implementation!\n"); |
211 | return -EIO; | 211 | return -EIO; |
212 | } | 212 | } |
@@ -221,8 +221,7 @@ recv_begin: | |||
221 | } | 221 | } |
222 | 222 | ||
223 | if ((size == 0x6D00) && (buf[1] == 0x80)) { | 223 | if ((size == 0x6D00) && (buf[1] == 0x80)) { |
224 | dev_err(&chip->pci_dev->dev, | 224 | dev_err(chip->dev, "Error handling on vendor layer!\n"); |
225 | "Error handling on vendor layer!\n"); | ||
226 | return -EIO; | 225 | return -EIO; |
227 | } | 226 | } |
228 | 227 | ||
@@ -234,7 +233,7 @@ recv_begin: | |||
234 | } | 233 | } |
235 | 234 | ||
236 | if (buf[1] == TPM_CTRL_WTX) { | 235 | if (buf[1] == TPM_CTRL_WTX) { |
237 | dev_info(&chip->pci_dev->dev, "WTX-package received\n"); | 236 | dev_info(chip->dev, "WTX-package received\n"); |
238 | if (number_of_wtx < TPM_MAX_WTX_PACKAGES) { | 237 | if (number_of_wtx < TPM_MAX_WTX_PACKAGES) { |
239 | tpm_wtx(chip); | 238 | tpm_wtx(chip); |
240 | goto recv_begin; | 239 | goto recv_begin; |
@@ -245,14 +244,14 @@ recv_begin: | |||
245 | } | 244 | } |
246 | 245 | ||
247 | if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) { | 246 | if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) { |
248 | dev_info(&chip->pci_dev->dev, "WTX-abort acknowledged\n"); | 247 | dev_info(chip->dev, "WTX-abort acknowledged\n"); |
249 | return size; | 248 | return size; |
250 | } | 249 | } |
251 | 250 | ||
252 | if (buf[1] == TPM_CTRL_ERROR) { | 251 | if (buf[1] == TPM_CTRL_ERROR) { |
253 | dev_err(&chip->pci_dev->dev, "ERROR-package received:\n"); | 252 | dev_err(chip->dev, "ERROR-package received:\n"); |
254 | if (buf[4] == TPM_INF_NAK) | 253 | if (buf[4] == TPM_INF_NAK) |
255 | dev_err(&chip->pci_dev->dev, | 254 | dev_err(chip->dev, |
256 | "-> Negative acknowledgement" | 255 | "-> Negative acknowledgement" |
257 | " - retransmit command!\n"); | 256 | " - retransmit command!\n"); |
258 | return -EIO; | 257 | return -EIO; |
@@ -271,7 +270,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count) | |||
271 | 270 | ||
272 | ret = empty_fifo(chip, 1); | 271 | ret = empty_fifo(chip, 1); |
273 | if (ret) { | 272 | if (ret) { |
274 | dev_err(&chip->pci_dev->dev, "Timeout while clearing FIFO\n"); | 273 | dev_err(chip->dev, "Timeout while clearing FIFO\n"); |
275 | return -EIO; | 274 | return -EIO; |
276 | } | 275 | } |
277 | 276 | ||
@@ -316,6 +315,11 @@ static void tpm_inf_cancel(struct tpm_chip *chip) | |||
316 | */ | 315 | */ |
317 | } | 316 | } |
318 | 317 | ||
318 | static u8 tpm_inf_status(struct tpm_chip *chip) | ||
319 | { | ||
320 | return inb(chip->vendor->base + STAT); | ||
321 | } | ||
322 | |||
319 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | 323 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); |
320 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | 324 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); |
321 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); | 325 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); |
@@ -344,6 +348,7 @@ static struct tpm_vendor_specific tpm_inf = { | |||
344 | .recv = tpm_inf_recv, | 348 | .recv = tpm_inf_recv, |
345 | .send = tpm_inf_send, | 349 | .send = tpm_inf_send, |
346 | .cancel = tpm_inf_cancel, | 350 | .cancel = tpm_inf_cancel, |
351 | .status = tpm_inf_status, | ||
347 | .req_complete_mask = 0, | 352 | .req_complete_mask = 0, |
348 | .req_complete_val = 0, | 353 | .req_complete_val = 0, |
349 | .attr_group = &inf_attr_grp, | 354 | .attr_group = &inf_attr_grp, |
@@ -356,30 +361,11 @@ static const struct pnp_device_id tpm_pnp_tbl[] = { | |||
356 | {"IFX0102", 0}, | 361 | {"IFX0102", 0}, |
357 | {"", 0} | 362 | {"", 0} |
358 | }; | 363 | }; |
364 | |||
359 | MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); | 365 | MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); |
360 | 366 | ||
361 | static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, | 367 | static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, |
362 | const struct pnp_device_id *dev_id) | 368 | const struct pnp_device_id *dev_id) |
363 | { | ||
364 | if (pnp_port_valid(dev, 0)) { | ||
365 | TPM_INF_ADDR = (pnp_port_start(dev, 0) & 0xff); | ||
366 | TPM_INF_DATA = ((TPM_INF_ADDR + 1) & 0xff); | ||
367 | tpm_inf.base = pnp_port_start(dev, 1); | ||
368 | dev_info(&dev->dev, "Found %s with ID %s\n", | ||
369 | dev->name, dev_id->id); | ||
370 | return 0; | ||
371 | } | ||
372 | return -ENODEV; | ||
373 | } | ||
374 | |||
375 | static struct pnp_driver tpm_inf_pnp = { | ||
376 | .name = "tpm_inf_pnp", | ||
377 | .id_table = tpm_pnp_tbl, | ||
378 | .probe = tpm_inf_pnp_probe, | ||
379 | }; | ||
380 | |||
381 | static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | ||
382 | const struct pci_device_id *pci_id) | ||
383 | { | 369 | { |
384 | int rc = 0; | 370 | int rc = 0; |
385 | u8 iol, ioh; | 371 | u8 iol, ioh; |
@@ -388,30 +374,28 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | |||
388 | int productid[2]; | 374 | int productid[2]; |
389 | char chipname[20]; | 375 | char chipname[20]; |
390 | 376 | ||
391 | rc = pci_enable_device(pci_dev); | 377 | /* read IO-ports through PnP */ |
392 | if (rc) | 378 | if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && |
393 | return rc; | 379 | !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { |
394 | 380 | TPM_INF_ADDR = pnp_port_start(dev, 0); | |
395 | dev_info(&pci_dev->dev, "LPC-bus found at 0x%x\n", pci_id->device); | 381 | TPM_INF_DATA = (TPM_INF_ADDR + 1); |
396 | 382 | TPM_INF_BASE = pnp_port_start(dev, 1); | |
397 | /* read IO-ports from PnP */ | 383 | TPM_INF_PORT_LEN = pnp_port_len(dev, 1); |
398 | rc = pnp_register_driver(&tpm_inf_pnp); | 384 | if (!TPM_INF_PORT_LEN) |
399 | if (rc < 0) { | 385 | return -EINVAL; |
400 | dev_err(&pci_dev->dev, | 386 | dev_info(&dev->dev, "Found %s with ID %s\n", |
401 | "Error %x from pnp_register_driver!\n",rc); | 387 | dev->name, dev_id->id); |
402 | goto error2; | 388 | if (!((TPM_INF_BASE >> 8) & 0xff)) |
403 | } | 389 | return -EINVAL; |
404 | if (!rc) { | 390 | /* publish my base address and request region */ |
405 | dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); | 391 | tpm_inf.base = TPM_INF_BASE; |
406 | goto error; | 392 | if (request_region |
393 | (tpm_inf.base, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { | ||
394 | release_region(tpm_inf.base, TPM_INF_PORT_LEN); | ||
395 | return -EINVAL; | ||
396 | } | ||
407 | } else { | 397 | } else { |
408 | pnp_registered = 1; | 398 | return -EINVAL; |
409 | } | ||
410 | |||
411 | /* Make sure, we have received valid config ports */ | ||
412 | if (!TPM_INF_ADDR) { | ||
413 | dev_err(&pci_dev->dev, "No valid IO-ports received!\n"); | ||
414 | goto error; | ||
415 | } | 399 | } |
416 | 400 | ||
417 | /* query chip for its vendor, its version number a.s.o. */ | 401 | /* query chip for its vendor, its version number a.s.o. */ |
@@ -443,10 +427,6 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | |||
443 | 427 | ||
444 | if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { | 428 | if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) { |
445 | 429 | ||
446 | if (tpm_inf.base == 0) { | ||
447 | dev_err(&pci_dev->dev, "No IO-ports found!\n"); | ||
448 | goto error; | ||
449 | } | ||
450 | /* configure TPM with IO-ports */ | 430 | /* configure TPM with IO-ports */ |
451 | outb(IOLIMH, TPM_INF_ADDR); | 431 | outb(IOLIMH, TPM_INF_ADDR); |
452 | outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); | 432 | outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); |
@@ -460,10 +440,11 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | |||
460 | iol = inb(TPM_INF_DATA); | 440 | iol = inb(TPM_INF_DATA); |
461 | 441 | ||
462 | if ((ioh << 8 | iol) != tpm_inf.base) { | 442 | if ((ioh << 8 | iol) != tpm_inf.base) { |
463 | dev_err(&pci_dev->dev, | 443 | dev_err(&dev->dev, |
464 | "Could not set IO-ports to %04x\n", | 444 | "Could not set IO-ports to %04x\n", |
465 | tpm_inf.base); | 445 | tpm_inf.base); |
466 | goto error; | 446 | release_region(tpm_inf.base, TPM_INF_PORT_LEN); |
447 | return -EIO; | ||
467 | } | 448 | } |
468 | 449 | ||
469 | /* activate register */ | 450 | /* activate register */ |
@@ -475,7 +456,7 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | |||
475 | outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); | 456 | outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); |
476 | 457 | ||
477 | /* Finally, we're done, print some infos */ | 458 | /* Finally, we're done, print some infos */ |
478 | dev_info(&pci_dev->dev, "TPM found: " | 459 | dev_info(&dev->dev, "TPM found: " |
479 | "config base 0x%x, " | 460 | "config base 0x%x, " |
480 | "io base 0x%x, " | 461 | "io base 0x%x, " |
481 | "chip version %02x%02x, " | 462 | "chip version %02x%02x, " |
@@ -483,59 +464,53 @@ static int __devinit tpm_inf_probe(struct pci_dev *pci_dev, | |||
483 | "product id %02x%02x" | 464 | "product id %02x%02x" |
484 | "%s\n", | 465 | "%s\n", |
485 | TPM_INF_ADDR, | 466 | TPM_INF_ADDR, |
486 | tpm_inf.base, | 467 | TPM_INF_BASE, |
487 | version[0], version[1], | 468 | version[0], version[1], |
488 | vendorid[0], vendorid[1], | 469 | vendorid[0], vendorid[1], |
489 | productid[0], productid[1], chipname); | 470 | productid[0], productid[1], chipname); |
490 | 471 | ||
491 | rc = tpm_register_hardware(pci_dev, &tpm_inf); | 472 | rc = tpm_register_hardware(&dev->dev, &tpm_inf); |
492 | if (rc < 0) | 473 | if (rc < 0) { |
493 | goto error; | 474 | release_region(tpm_inf.base, TPM_INF_PORT_LEN); |
475 | return -ENODEV; | ||
476 | } | ||
494 | return 0; | 477 | return 0; |
495 | } else { | 478 | } else { |
496 | dev_info(&pci_dev->dev, "No Infineon TPM found!\n"); | 479 | dev_info(&dev->dev, "No Infineon TPM found!\n"); |
497 | error: | ||
498 | pnp_unregister_driver(&tpm_inf_pnp); | ||
499 | error2: | ||
500 | pci_disable_device(pci_dev); | ||
501 | pnp_registered = 0; | ||
502 | return -ENODEV; | 480 | return -ENODEV; |
503 | } | 481 | } |
504 | } | 482 | } |
505 | 483 | ||
506 | static struct pci_device_id tpm_pci_tbl[] __devinitdata = { | 484 | static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) |
507 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, | 485 | { |
508 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, | 486 | struct tpm_chip *chip = pnp_get_drvdata(dev); |
509 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, | ||
510 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, | ||
511 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, | ||
512 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, | ||
513 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, | ||
514 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2)}, | ||
515 | {0,} | ||
516 | }; | ||
517 | 487 | ||
518 | MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); | 488 | if (chip) { |
489 | release_region(chip->vendor->base, TPM_INF_PORT_LEN); | ||
490 | tpm_remove_hardware(chip->dev); | ||
491 | } | ||
492 | } | ||
519 | 493 | ||
520 | static struct pci_driver inf_pci_driver = { | 494 | static struct pnp_driver tpm_inf_pnp = { |
521 | .name = "tpm_inf", | 495 | .name = "tpm_inf_pnp", |
522 | .id_table = tpm_pci_tbl, | 496 | .driver = { |
523 | .probe = tpm_inf_probe, | 497 | .owner = THIS_MODULE, |
524 | .remove = __devexit_p(tpm_remove), | 498 | .suspend = tpm_pm_suspend, |
525 | .suspend = tpm_pm_suspend, | 499 | .resume = tpm_pm_resume, |
526 | .resume = tpm_pm_resume, | 500 | }, |
501 | .id_table = tpm_pnp_tbl, | ||
502 | .probe = tpm_inf_pnp_probe, | ||
503 | .remove = tpm_inf_pnp_remove, | ||
527 | }; | 504 | }; |
528 | 505 | ||
529 | static int __init init_inf(void) | 506 | static int __init init_inf(void) |
530 | { | 507 | { |
531 | return pci_register_driver(&inf_pci_driver); | 508 | return pnp_register_driver(&tpm_inf_pnp); |
532 | } | 509 | } |
533 | 510 | ||
534 | static void __exit cleanup_inf(void) | 511 | static void __exit cleanup_inf(void) |
535 | { | 512 | { |
536 | if (pnp_registered) | 513 | pnp_unregister_driver(&tpm_inf_pnp); |
537 | pnp_unregister_driver(&tpm_inf_pnp); | ||
538 | pci_unregister_driver(&inf_pci_driver); | ||
539 | } | 514 | } |
540 | 515 | ||
541 | module_init(init_inf); | 516 | module_init(init_inf); |
@@ -543,5 +518,5 @@ module_exit(cleanup_inf); | |||
543 | 518 | ||
544 | MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); | 519 | MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>"); |
545 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); | 520 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); |
546 | MODULE_VERSION("1.5"); | 521 | MODULE_VERSION("1.6"); |
547 | MODULE_LICENSE("GPL"); | 522 | MODULE_LICENSE("GPL"); |