tpm_tis: Refactor the interrupt setup
Now that the probe and run cases are merged together we can use a much simpler setup flow where probe and normal setup are done with exactly the same code. Since the new flow always calls tpm_gen_interrupt to confirm the IRQ there is also no longer any need to call tpm_get_timeouts twice. Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com> Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Martin Wilck <Martin.Wilck@ts.fujitsu.com> Tested-by: Scot Doyle <lkml14@scotdoyle.com> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Acked-by: Peter Huewe <peterhuewe@gmx.de>
This commit is contained in:
parent
7ab4032fa5
commit
e3837e74a0
|
@ -99,7 +99,6 @@ static struct tpm_info tis_default_info = {
|
||||||
#define TPM_RID(l) (0x0F04 | ((l) << 12))
|
#define TPM_RID(l) (0x0F04 | ((l) << 12))
|
||||||
|
|
||||||
struct priv_data {
|
struct priv_data {
|
||||||
bool irq_probing;
|
|
||||||
bool irq_tested;
|
bool irq_tested;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -462,12 +461,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||||
chip->vendor.irq = irq;
|
chip->vendor.irq = irq;
|
||||||
if (!priv->irq_tested)
|
if (!priv->irq_tested)
|
||||||
msleep(1);
|
msleep(1);
|
||||||
if (!priv->irq_tested) {
|
if (!priv->irq_tested)
|
||||||
disable_interrupts(chip);
|
disable_interrupts(chip);
|
||||||
if (!priv->irq_probing)
|
|
||||||
dev_err(chip->pdev, FW_BUG
|
|
||||||
"TPM interrupt not working, polling instead\n");
|
|
||||||
}
|
|
||||||
priv->irq_tested = true;
|
priv->irq_tested = true;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -604,6 +599,80 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Register the IRQ and issue a command that will cause an interrupt. If an
|
||||||
|
* irq is seen then leave the chip setup for IRQ operation, otherwise reverse
|
||||||
|
* everything and leave in polling mode. Returns 0 on success.
|
||||||
|
*/
|
||||||
|
static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, int irq)
|
||||||
|
{
|
||||||
|
struct priv_data *priv = chip->vendor.priv;
|
||||||
|
u8 original_int_vec;
|
||||||
|
|
||||||
|
if (devm_request_irq(chip->pdev, irq, tis_int_handler, IRQF_SHARED,
|
||||||
|
chip->devname, chip) != 0) {
|
||||||
|
dev_info(chip->pdev, "Unable to request irq: %d for probe\n",
|
||||||
|
irq);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
chip->vendor.irq = irq;
|
||||||
|
|
||||||
|
original_int_vec = ioread8(chip->vendor.iobase +
|
||||||
|
TPM_INT_VECTOR(chip->vendor.locality));
|
||||||
|
iowrite8(irq,
|
||||||
|
chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality));
|
||||||
|
|
||||||
|
/* Clear all existing */
|
||||||
|
iowrite32(ioread32(chip->vendor.iobase +
|
||||||
|
TPM_INT_STATUS(chip->vendor.locality)),
|
||||||
|
chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
|
||||||
|
|
||||||
|
/* Turn on */
|
||||||
|
iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
|
||||||
|
chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
|
||||||
|
|
||||||
|
priv->irq_tested = false;
|
||||||
|
|
||||||
|
/* Generate an interrupt by having the core call through to
|
||||||
|
* tpm_tis_send
|
||||||
|
*/
|
||||||
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
|
tpm2_gen_interrupt(chip);
|
||||||
|
else
|
||||||
|
tpm_gen_interrupt(chip);
|
||||||
|
|
||||||
|
/* tpm_tis_send will either confirm the interrupt is working or it
|
||||||
|
* will call disable_irq which undoes all of the above.
|
||||||
|
*/
|
||||||
|
if (!chip->vendor.irq) {
|
||||||
|
iowrite8(original_int_vec,
|
||||||
|
chip->vendor.iobase +
|
||||||
|
TPM_INT_VECTOR(chip->vendor.locality));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find the IRQ the TPM is using. This is for legacy x86 systems that
|
||||||
|
* do not have ACPI/etc. We typically expect the interrupt to be declared if
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
static void tpm_tis_probe_irq(struct tpm_chip *chip, u32 intmask)
|
||||||
|
{
|
||||||
|
u8 original_int_vec;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
original_int_vec = ioread8(chip->vendor.iobase +
|
||||||
|
TPM_INT_VECTOR(chip->vendor.locality));
|
||||||
|
|
||||||
|
if (!original_int_vec) {
|
||||||
|
for (i = 3; i <= 15; i++)
|
||||||
|
if (!tpm_tis_probe_irq_single(chip, intmask, i))
|
||||||
|
return;
|
||||||
|
} else if (!tpm_tis_probe_irq_single(chip, intmask, original_int_vec))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
static bool interrupts = true;
|
static bool interrupts = true;
|
||||||
module_param(interrupts, bool, 0444);
|
module_param(interrupts, bool, 0444);
|
||||||
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
||||||
|
@ -626,8 +695,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
|
||||||
acpi_handle acpi_dev_handle)
|
acpi_handle acpi_dev_handle)
|
||||||
{
|
{
|
||||||
u32 vendor, intfcaps, intmask;
|
u32 vendor, intfcaps, intmask;
|
||||||
int rc, i, irq_s, irq_e, probe;
|
int rc, probe;
|
||||||
int irq_r = -1;
|
|
||||||
struct tpm_chip *chip;
|
struct tpm_chip *chip;
|
||||||
struct priv_data *priv;
|
struct priv_data *priv;
|
||||||
|
|
||||||
|
@ -735,98 +803,14 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
|
||||||
/* INTERRUPT Setup */
|
/* INTERRUPT Setup */
|
||||||
init_waitqueue_head(&chip->vendor.read_queue);
|
init_waitqueue_head(&chip->vendor.read_queue);
|
||||||
init_waitqueue_head(&chip->vendor.int_queue);
|
init_waitqueue_head(&chip->vendor.int_queue);
|
||||||
|
if (interrupts) {
|
||||||
if (interrupts)
|
if (tpm_info->irq) {
|
||||||
chip->vendor.irq = tpm_info->irq;
|
tpm_tis_probe_irq_single(chip, intmask, tpm_info->irq);
|
||||||
if (interrupts && !chip->vendor.irq) {
|
|
||||||
irq_s =
|
|
||||||
ioread8(chip->vendor.iobase +
|
|
||||||
TPM_INT_VECTOR(chip->vendor.locality));
|
|
||||||
irq_r = irq_s;
|
|
||||||
if (irq_s) {
|
|
||||||
irq_e = irq_s;
|
|
||||||
} else {
|
|
||||||
irq_s = 3;
|
|
||||||
irq_e = 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
|
|
||||||
iowrite8(i, chip->vendor.iobase +
|
|
||||||
TPM_INT_VECTOR(chip->vendor.locality));
|
|
||||||
if (devm_request_irq
|
|
||||||
(dev, i, tis_int_handler, IRQF_SHARED,
|
|
||||||
chip->devname, chip) != 0) {
|
|
||||||
dev_info(chip->pdev,
|
|
||||||
"Unable to request irq: %d for probe\n",
|
|
||||||
i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
chip->vendor.irq = i;
|
|
||||||
|
|
||||||
/* Clear all existing */
|
|
||||||
iowrite32(ioread32
|
|
||||||
(chip->vendor.iobase +
|
|
||||||
TPM_INT_STATUS(chip->vendor.locality)),
|
|
||||||
chip->vendor.iobase +
|
|
||||||
TPM_INT_STATUS(chip->vendor.locality));
|
|
||||||
|
|
||||||
/* Turn on */
|
|
||||||
iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
|
|
||||||
chip->vendor.iobase +
|
|
||||||
TPM_INT_ENABLE(chip->vendor.locality));
|
|
||||||
|
|
||||||
priv->irq_tested = false;
|
|
||||||
priv->irq_probing = true;
|
|
||||||
|
|
||||||
/* Generate Interrupts */
|
|
||||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
|
||||||
tpm2_gen_interrupt(chip);
|
|
||||||
else
|
|
||||||
tpm_gen_interrupt(chip);
|
|
||||||
|
|
||||||
priv->irq_probing = false;
|
|
||||||
|
|
||||||
/* tpm_tis_send will either confirm the interrupt is
|
|
||||||
* working or it will call disable_irq which undoes
|
|
||||||
* all of the above.
|
|
||||||
*/
|
|
||||||
if (chip->vendor.irq)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!chip->vendor.irq)
|
if (!chip->vendor.irq)
|
||||||
iowrite8(irq_r, chip->vendor.iobase +
|
dev_err(chip->pdev, FW_BUG
|
||||||
TPM_INT_VECTOR(chip->vendor.locality));
|
"TPM interrupt not working, polling instead\n");
|
||||||
}
|
} else
|
||||||
if (chip->vendor.irq && !priv->irq_tested) {
|
tpm_tis_probe_irq(chip, intmask);
|
||||||
iowrite8(chip->vendor.irq,
|
|
||||||
chip->vendor.iobase +
|
|
||||||
TPM_INT_VECTOR(chip->vendor.locality));
|
|
||||||
if (devm_request_irq
|
|
||||||
(dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
|
|
||||||
chip->devname, chip) != 0) {
|
|
||||||
dev_info(chip->pdev,
|
|
||||||
"Unable to request irq: %d for use\n",
|
|
||||||
chip->vendor.irq);
|
|
||||||
chip->vendor.irq = 0;
|
|
||||||
} else {
|
|
||||||
/* Clear all existing */
|
|
||||||
iowrite32(ioread32
|
|
||||||
(chip->vendor.iobase +
|
|
||||||
TPM_INT_STATUS(chip->vendor.locality)),
|
|
||||||
chip->vendor.iobase +
|
|
||||||
TPM_INT_STATUS(chip->vendor.locality));
|
|
||||||
|
|
||||||
/* Turn on */
|
|
||||||
iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
|
|
||||||
chip->vendor.iobase +
|
|
||||||
TPM_INT_ENABLE(chip->vendor.locality));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tpm_get_timeouts(chip)) {
|
|
||||||
dev_err(dev, "Could not get TPM timeouts and durations\n");
|
|
||||||
rc = -ENODEV;
|
|
||||||
goto out_err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||||
|
|
Loading…
Reference in New Issue