diff options
| -rw-r--r-- | drivers/char/tpm/tpm_tis.c | 76 |
1 files changed, 62 insertions, 14 deletions
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 6f1985496112..ccb140d60532 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
| @@ -75,6 +75,10 @@ enum tis_defaults { | |||
| 75 | #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) | 75 | #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) |
| 76 | #define TPM_RID(l) (0x0F04 | ((l) << 12)) | 76 | #define TPM_RID(l) (0x0F04 | ((l) << 12)) |
| 77 | 77 | ||
| 78 | struct priv_data { | ||
| 79 | bool irq_tested; | ||
| 80 | }; | ||
| 81 | |||
| 78 | static LIST_HEAD(tis_chips); | 82 | static LIST_HEAD(tis_chips); |
| 79 | static DEFINE_MUTEX(tis_lock); | 83 | static DEFINE_MUTEX(tis_lock); |
| 80 | 84 | ||
| @@ -338,12 +342,27 @@ out_err: | |||
| 338 | return rc; | 342 | return rc; |
| 339 | } | 343 | } |
| 340 | 344 | ||
| 345 | static void disable_interrupts(struct tpm_chip *chip) | ||
| 346 | { | ||
| 347 | u32 intmask; | ||
| 348 | |||
| 349 | intmask = | ||
| 350 | ioread32(chip->vendor.iobase + | ||
| 351 | TPM_INT_ENABLE(chip->vendor.locality)); | ||
| 352 | intmask &= ~TPM_GLOBAL_INT_ENABLE; | ||
| 353 | iowrite32(intmask, | ||
| 354 | chip->vendor.iobase + | ||
| 355 | TPM_INT_ENABLE(chip->vendor.locality)); | ||
| 356 | free_irq(chip->vendor.irq, chip); | ||
| 357 | chip->vendor.irq = 0; | ||
| 358 | } | ||
| 359 | |||
| 341 | /* | 360 | /* |
| 342 | * If interrupts are used (signaled by an irq set in the vendor structure) | 361 | * If interrupts are used (signaled by an irq set in the vendor structure) |
| 343 | * tpm.c can skip polling for the data to be available as the interrupt is | 362 | * tpm.c can skip polling for the data to be available as the interrupt is |
| 344 | * waited for here | 363 | * waited for here |
| 345 | */ | 364 | */ |
| 346 | static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) | 365 | static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) |
| 347 | { | 366 | { |
| 348 | int rc; | 367 | int rc; |
| 349 | u32 ordinal; | 368 | u32 ordinal; |
| @@ -373,6 +392,30 @@ out_err: | |||
| 373 | return rc; | 392 | return rc; |
| 374 | } | 393 | } |
| 375 | 394 | ||
| 395 | static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) | ||
| 396 | { | ||
| 397 | int rc, irq; | ||
| 398 | struct priv_data *priv = chip->vendor.priv; | ||
| 399 | |||
| 400 | if (!chip->vendor.irq || priv->irq_tested) | ||
| 401 | return tpm_tis_send_main(chip, buf, len); | ||
| 402 | |||
| 403 | /* Verify receipt of the expected IRQ */ | ||
| 404 | irq = chip->vendor.irq; | ||
| 405 | chip->vendor.irq = 0; | ||
| 406 | rc = tpm_tis_send_main(chip, buf, len); | ||
| 407 | chip->vendor.irq = irq; | ||
| 408 | if (!priv->irq_tested) | ||
| 409 | msleep(1); | ||
| 410 | if (!priv->irq_tested) { | ||
| 411 | disable_interrupts(chip); | ||
| 412 | dev_err(chip->dev, | ||
| 413 | FW_BUG "TPM interrupt not working, polling instead\n"); | ||
| 414 | } | ||
| 415 | priv->irq_tested = true; | ||
| 416 | return rc; | ||
| 417 | } | ||
| 418 | |||
| 376 | struct tis_vendor_timeout_override { | 419 | struct tis_vendor_timeout_override { |
| 377 | u32 did_vid; | 420 | u32 did_vid; |
| 378 | unsigned long timeout_us[4]; | 421 | unsigned long timeout_us[4]; |
| @@ -505,6 +548,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) | |||
| 505 | if (interrupt == 0) | 548 | if (interrupt == 0) |
| 506 | return IRQ_NONE; | 549 | return IRQ_NONE; |
| 507 | 550 | ||
| 551 | ((struct priv_data *)chip->vendor.priv)->irq_tested = true; | ||
| 508 | if (interrupt & TPM_INTF_DATA_AVAIL_INT) | 552 | if (interrupt & TPM_INTF_DATA_AVAIL_INT) |
| 509 | wake_up_interruptible(&chip->vendor.read_queue); | 553 | wake_up_interruptible(&chip->vendor.read_queue); |
| 510 | if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) | 554 | if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) |
| @@ -534,9 +578,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
| 534 | u32 vendor, intfcaps, intmask; | 578 | u32 vendor, intfcaps, intmask; |
| 535 | int rc, i, irq_s, irq_e, probe; | 579 | int rc, i, irq_s, irq_e, probe; |
| 536 | struct tpm_chip *chip; | 580 | struct tpm_chip *chip; |
| 581 | struct priv_data *priv; | ||
| 537 | 582 | ||
| 583 | priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL); | ||
| 584 | if (priv == NULL) | ||
| 585 | return -ENOMEM; | ||
| 538 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) | 586 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) |
| 539 | return -ENODEV; | 587 | return -ENODEV; |
| 588 | chip->vendor.priv = priv; | ||
| 540 | 589 | ||
| 541 | chip->vendor.iobase = ioremap(start, len); | 590 | chip->vendor.iobase = ioremap(start, len); |
| 542 | if (!chip->vendor.iobase) { | 591 | if (!chip->vendor.iobase) { |
| @@ -605,19 +654,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
| 605 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) | 654 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) |
| 606 | dev_dbg(dev, "\tData Avail Int Support\n"); | 655 | dev_dbg(dev, "\tData Avail Int Support\n"); |
| 607 | 656 | ||
| 608 | /* get the timeouts before testing for irqs */ | ||
| 609 | if (tpm_get_timeouts(chip)) { | ||
| 610 | dev_err(dev, "Could not get TPM timeouts and durations\n"); | ||
| 611 | rc = -ENODEV; | ||
| 612 | goto out_err; | ||
| 613 | } | ||
| 614 | |||
| 615 | if (tpm_do_selftest(chip)) { | ||
| 616 | dev_err(dev, "TPM self test failed\n"); | ||
| 617 | rc = -ENODEV; | ||
| 618 | goto out_err; | ||
| 619 | } | ||
| 620 | |||
| 621 | /* INTERRUPT Setup */ | 657 | /* INTERRUPT Setup */ |
| 622 | init_waitqueue_head(&chip->vendor.read_queue); | 658 | init_waitqueue_head(&chip->vendor.read_queue); |
| 623 | init_waitqueue_head(&chip->vendor.int_queue); | 659 | init_waitqueue_head(&chip->vendor.int_queue); |
| @@ -719,6 +755,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
| 719 | } | 755 | } |
| 720 | } | 756 | } |
| 721 | 757 | ||
| 758 | if (tpm_get_timeouts(chip)) { | ||
| 759 | dev_err(dev, "Could not get TPM timeouts and durations\n"); | ||
| 760 | rc = -ENODEV; | ||
| 761 | goto out_err; | ||
| 762 | } | ||
| 763 | |||
| 764 | if (tpm_do_selftest(chip)) { | ||
| 765 | dev_err(dev, "TPM self test failed\n"); | ||
| 766 | rc = -ENODEV; | ||
| 767 | goto out_err; | ||
| 768 | } | ||
| 769 | |||
| 722 | INIT_LIST_HEAD(&chip->vendor.list); | 770 | INIT_LIST_HEAD(&chip->vendor.list); |
| 723 | mutex_lock(&tis_lock); | 771 | mutex_lock(&tis_lock); |
| 724 | list_add(&chip->vendor.list, &tis_chips); | 772 | list_add(&chip->vendor.list, &tis_chips); |
