diff options
author | Stefan Berger <stefanb@linux.vnet.ibm.com> | 2011-03-30 12:13:32 -0400 |
---|---|---|
committer | Rajiv Andrade <srajiv@linux.vnet.ibm.com> | 2011-07-12 17:53:08 -0400 |
commit | a7b66822b20f67f106690d0acee3d0ba667fd9bb (patch) | |
tree | c9b0ae416b45ae1b4c6fc453265e42394d60e352 /drivers/char/tpm/tpm_tis.c | |
parent | 20b87bbfada971ae917cc2ff9dbc9dae05b94d25 (diff) |
tpm_tis: Fix the probing for interrupts
This patch fixes several aspects of the probing for interrupts.
This patch reads the TPM's timeouts before probing for the interrupts. The
tpm_get_timeouts() function is invoked in polling mode and gets the proper
timeouts from the TPM so that we don't need to fall back to 2 minutes timeouts
for short duration commands while the interrupt probing is happening.
This patch introduces a variable probed_irq into the vendor structure that gets
the irq number if an interrupt is received while the the tpm_gen_interrupt()
function is run in polling mode during interrupt probing. Previously some
parts of tpm_gen_interrupt() were run in polling mode, then the irq variable
was set in the interrupt handler when an interrupt was received and execution
of tpm_gen_interrupt() ended up switching over to interrupt mode.
tpm_gen_interrupt() execution ended up on an event queue where it eventually
timed out since the probing handler doesn't wake any queues.
Before calling into free_irq() clear all interrupt flags that may have
been set by the TPM. The reason is that free_irq() will call into the probing
interrupt handler and may otherwise fool us into thinking that a real interrupt
happened (because we see the flags as being set) while the TPM's interrupt line
is not even connected to anything on the motherboard. This solves a problem
on one machine I did testing on (Thinkpad T60).
If a TPM claims to use a specifc interrupt, the probing is done as well
to verify that the interrupt is actually working. If a TPM indicates
that it does not use a specific interrupt (returns '0'), probe all interrupts
from 3 to 15.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/char/tpm/tpm_tis.c')
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index b97ce2b205d7..47517e49d2be 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -438,7 +438,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id) | |||
438 | if (interrupt == 0) | 438 | if (interrupt == 0) |
439 | return IRQ_NONE; | 439 | return IRQ_NONE; |
440 | 440 | ||
441 | chip->vendor.irq = irq; | 441 | chip->vendor.probed_irq = irq; |
442 | 442 | ||
443 | /* Clear interrupts handled with TPM_EOI */ | 443 | /* Clear interrupts handled with TPM_EOI */ |
444 | iowrite32(interrupt, | 444 | iowrite32(interrupt, |
@@ -486,7 +486,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
486 | resource_size_t len, unsigned int irq) | 486 | resource_size_t len, unsigned int irq) |
487 | { | 487 | { |
488 | u32 vendor, intfcaps, intmask; | 488 | u32 vendor, intfcaps, intmask; |
489 | int rc, i; | 489 | int rc, i, irq_s, irq_e; |
490 | struct tpm_chip *chip; | 490 | struct tpm_chip *chip; |
491 | 491 | ||
492 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) | 492 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) |
@@ -544,6 +544,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
544 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) | 544 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) |
545 | dev_dbg(dev, "\tData Avail Int Support\n"); | 545 | dev_dbg(dev, "\tData Avail Int Support\n"); |
546 | 546 | ||
547 | /* get the timeouts before testing for irqs */ | ||
548 | tpm_get_timeouts(chip); | ||
549 | |||
547 | /* INTERRUPT Setup */ | 550 | /* INTERRUPT Setup */ |
548 | init_waitqueue_head(&chip->vendor.read_queue); | 551 | init_waitqueue_head(&chip->vendor.read_queue); |
549 | init_waitqueue_head(&chip->vendor.int_queue); | 552 | init_waitqueue_head(&chip->vendor.int_queue); |
@@ -562,13 +565,19 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
562 | if (interrupts) | 565 | if (interrupts) |
563 | chip->vendor.irq = irq; | 566 | chip->vendor.irq = irq; |
564 | if (interrupts && !chip->vendor.irq) { | 567 | if (interrupts && !chip->vendor.irq) { |
565 | chip->vendor.irq = | 568 | irq_s = |
566 | ioread8(chip->vendor.iobase + | 569 | ioread8(chip->vendor.iobase + |
567 | TPM_INT_VECTOR(chip->vendor.locality)); | 570 | TPM_INT_VECTOR(chip->vendor.locality)); |
571 | if (irq_s) { | ||
572 | irq_e = irq_s; | ||
573 | } else { | ||
574 | irq_s = 3; | ||
575 | irq_e = 15; | ||
576 | } | ||
568 | 577 | ||
569 | for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { | 578 | for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) { |
570 | iowrite8(i, chip->vendor.iobase + | 579 | iowrite8(i, chip->vendor.iobase + |
571 | TPM_INT_VECTOR(chip->vendor.locality)); | 580 | TPM_INT_VECTOR(chip->vendor.locality)); |
572 | if (request_irq | 581 | if (request_irq |
573 | (i, tis_int_probe, IRQF_SHARED, | 582 | (i, tis_int_probe, IRQF_SHARED, |
574 | chip->vendor.miscdev.name, chip) != 0) { | 583 | chip->vendor.miscdev.name, chip) != 0) { |
@@ -590,9 +599,22 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
590 | chip->vendor.iobase + | 599 | chip->vendor.iobase + |
591 | TPM_INT_ENABLE(chip->vendor.locality)); | 600 | TPM_INT_ENABLE(chip->vendor.locality)); |
592 | 601 | ||
602 | chip->vendor.probed_irq = 0; | ||
603 | |||
593 | /* Generate Interrupts */ | 604 | /* Generate Interrupts */ |
594 | tpm_gen_interrupt(chip); | 605 | tpm_gen_interrupt(chip); |
595 | 606 | ||
607 | chip->vendor.irq = chip->vendor.probed_irq; | ||
608 | |||
609 | /* free_irq will call into tis_int_probe; | ||
610 | clear all irqs we haven't seen while doing | ||
611 | tpm_gen_interrupt */ | ||
612 | iowrite32(ioread32 | ||
613 | (chip->vendor.iobase + | ||
614 | TPM_INT_STATUS(chip->vendor.locality)), | ||
615 | chip->vendor.iobase + | ||
616 | TPM_INT_STATUS(chip->vendor.locality)); | ||
617 | |||
596 | /* Turn off */ | 618 | /* Turn off */ |
597 | iowrite32(intmask, | 619 | iowrite32(intmask, |
598 | chip->vendor.iobase + | 620 | chip->vendor.iobase + |
@@ -631,7 +653,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
631 | list_add(&chip->vendor.list, &tis_chips); | 653 | list_add(&chip->vendor.list, &tis_chips); |
632 | spin_unlock(&tis_lock); | 654 | spin_unlock(&tis_lock); |
633 | 655 | ||
634 | tpm_get_timeouts(chip); | ||
635 | tpm_continue_selftest(chip); | 656 | tpm_continue_selftest(chip); |
636 | 657 | ||
637 | return 0; | 658 | return 0; |