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