Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3837e74 authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Jarkko Sakkinen
Browse files

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: default avatarJason Gunthorpe <jgunthorpe@obsidianresearch.com>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: default avatarMartin Wilck <Martin.Wilck@ts.fujitsu.com>
Tested-by: default avatarScot Doyle <lkml14@scotdoyle.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Acked-by: default avatarPeter Huewe <peterhuewe@gmx.de>
parent 7ab4032f
Loading
Loading
Loading
Loading
+84 −100
Original line number Diff line number Diff line
@@ -99,7 +99,6 @@ static struct tpm_info tis_default_info = {
#define	TPM_RID(l)			(0x0F04 | ((l) << 12))

struct priv_data {
	bool irq_probing;
	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;
	if (!priv->irq_tested)
		msleep(1);
	if (!priv->irq_tested) {
	if (!priv->irq_tested)
		disable_interrupts(chip);
		if (!priv->irq_probing)
			dev_err(chip->pdev, FW_BUG
				"TPM interrupt not working, polling instead\n");
	}
	priv->irq_tested = true;
	return rc;
}
@@ -604,6 +599,80 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
	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;
module_param(interrupts, bool, 0444);
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)
{
	u32 vendor, intfcaps, intmask;
	int rc, i, irq_s, irq_e, probe;
	int irq_r = -1;
	int rc, probe;
	struct tpm_chip *chip;
	struct priv_data *priv;

@@ -735,98 +803,14 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
	/* INTERRUPT Setup */
	init_waitqueue_head(&chip->vendor.read_queue);
	init_waitqueue_head(&chip->vendor.int_queue);

	if (interrupts)
		chip->vendor.irq = 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 (interrupts) {
		if (tpm_info->irq) {
			tpm_tis_probe_irq_single(chip, intmask, tpm_info->irq);
			if (!chip->vendor.irq)
			iowrite8(irq_r, chip->vendor.iobase +
				 TPM_INT_VECTOR(chip->vendor.locality));
	}
	if (chip->vendor.irq && !priv->irq_tested) {
		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;
				dev_err(chip->pdev, FW_BUG
					"TPM interrupt not working, polling instead\n");
		} else
			tpm_tis_probe_irq(chip, intmask);
	}

	if (chip->flags & TPM_CHIP_FLAG_TPM2) {