From: Thomas Gleixner <tglx@linutronix.de>
To: Jerry Snitselaar <jsnitsel@redhat.com>, linux-kernel@vger.kernel.org
Cc: linux-integrity@vger.kernel.org, intel-gfx@lists.freedesktop.org,
dri-devel@lists.freedesktop.org,
Jarkko Sakkinen <jarkko@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>, Peter Huewe <peterhuewe@gmx.de>,
James Bottomley <James.Bottomley@HansenPartnership.com>,
Matthew Garrett <mjg59@google.com>,
Hans de Goede <hdegoede@redhat.com>
Subject: Re: [PATCH v3 3/4] tpm_tis: Disable interrupts if interrupt storm detected
Date: Sun, 06 Dec 2020 20:26:16 +0100 [thread overview]
Message-ID: <87tusy7n3b.fsf@nanos.tec.linutronix.de> (raw)
In-Reply-To: <20201205014340.148235-4-jsnitsel@redhat.com>
Jerry,
On Fri, Dec 04 2020 at 18:43, Jerry Snitselaar wrote:
> @@ -715,9 +717,23 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
> {
> struct tpm_chip *chip = dev_id;
> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
> + static bool check_storm = true;
> + static unsigned int check_start;
So this assumes that there can't be two TPMs which is probably true, but
everything else in this driver has stuff in tpm_tis_data per device.
> u32 interrupt;
> int i, rc;
>
> + if (unlikely(check_storm)) {
> + if (!check_start) {
> + check_start = jiffies_to_msecs(jiffies);
Yuck. I had to read that twice to figure out that it's correct vs. the
truncation of the result to unsigned int. You can spare that conversion
by simply doing
unsigned long end_of_check = jiffies + HZ / 2;
and then the check becomes
time_before(jiffies, end_of_check)
> + } else if ((kstat_irqs(priv->irq) > 1000) &&
> + (jiffies_to_msecs(jiffies) - check_start < 500)) {
I assume you can't call disable_irq_nosync() here, but shouldn't this
shut up the interrupt at the TPM level right here?
> + check_storm = false;
> + schedule_work(&priv->storm_work);
> + } else if (jiffies_to_msecs(jiffies) - check_start >= 500) {
> + check_storm = false;
> + }
> + }
So back to kstat_irqs(). As this needs two extra variables anyway:
init()
priv->irq_check = 1;
priv->end_check = 0;
isr()
if (unlikely(priv->irq_check)) {
if (!priv->end_check) {
priv->end_check = jiffies + HZ / 2;
} else if (time_before(jiffies, priv->end_check)) {
if (priv->irq_check++ > 1000)
schedule_work(...);
} else {
priv->irq_check = 0;
}
}
Hmm? I still need to see an argument for an kstat_irqs() export being
superior.
Though I wonder whether such an infrastructure should be provided in the
irq core. Let me think about it.
Just as a side note. I was looking at tpm_tis_probe_irq_single() and
that function is leaking the interrupt request if any of the checks
afterwards fails, except for the final interrupt probe check which does
a cleanup. That means on fail before that the interrupt handler stays
requested up to the point where the module is removed. If that's a
shared interrupt and some other device is active on the same line, then
each interrupt from that device will call into the TPM code. Something
like the below is needed.
Also the X86 autoprobe mechanism is interesting:
if (IS_ENABLED(CONFIG_X86))
for (i = 3; i <= 15; i++)
if (!tpm_tis_probe_irq_single(chip, intmask, 0, i))
return;
The third argument is 'flags' which is handed to request_irq(). So that
won't ever be able to probe a shared interrupt. But if an interrupt
number > 0 is handed to tpm_tis_core_init() the interrupt is requested
with IRQF_SHARED. Same issue when the chip has an interrupt number in
the register. It's also requested exclusive which is pretty likely
to fail on ancient x86 machines.
The vast amount of comments didn't help to figure out what the reasoning
is.
Thanks,
tglx
---
drivers/char/tpm/tpm_tis_core.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -782,26 +782,26 @@ static int tpm_tis_probe_irq_single(stru
rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality),
&original_int_vec);
if (rc < 0)
- return rc;
+ goto fail;
rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), irq);
if (rc < 0)
- return rc;
+ goto fail;
rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &int_status);
if (rc < 0)
- return rc;
+ goto fail;
/* Clear all existing */
rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), int_status);
if (rc < 0)
- return rc;
+ goto fail;
/* Turn on */
rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality),
intmask | TPM_GLOBAL_INT_ENABLE);
if (rc < 0)
- return rc;
+ goto fail;
priv->irq_tested = false;
@@ -825,6 +825,10 @@ static int tpm_tis_probe_irq_single(stru
}
return 0;
+
+fail:
+ disable_interrupts(chip);
+ return rc;
}
/* Try to find the IRQ the TPM is using. This is for legacy x86 systems that
next prev parent reply other threads:[~2020-12-06 19:27 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-12-05 1:43 [PATCH v3 0/4] tpm_tis: Detect interrupt storms Jerry Snitselaar
2020-12-05 1:43 ` [PATCH v3 1/4] irq: export kstat_irqs Jerry Snitselaar
2020-12-05 10:39 ` Jarkko Sakkinen
2020-12-06 16:40 ` Thomas Gleixner
2020-12-06 17:40 ` James Bottomley
2020-12-06 19:29 ` Thomas Gleixner
2020-12-06 17:54 ` Thomas Gleixner
2020-12-06 21:46 ` Jerry Snitselaar
2020-12-05 1:43 ` [PATCH v3 2/4] drm/i915/pmu: Use kstat_irqs to get interrupt count Jerry Snitselaar
2020-12-06 16:38 ` Thomas Gleixner
2020-12-06 21:33 ` Thomas Gleixner
2020-12-08 9:54 ` Jarkko Sakkinen
2020-12-06 21:47 ` Jerry Snitselaar
2020-12-06 23:38 ` Thomas Gleixner
2020-12-10 7:53 ` [Intel-gfx] " Joonas Lahtinen
2020-12-10 10:45 ` Tvrtko Ursulin
2020-12-10 16:35 ` Thomas Gleixner
2020-12-10 17:09 ` Tvrtko Ursulin
2020-12-10 17:44 ` Thomas Gleixner
2020-12-10 17:51 ` Tvrtko Ursulin
2020-12-05 1:43 ` [PATCH v3 3/4] tpm_tis: Disable interrupts if interrupt storm detected Jerry Snitselaar
2020-12-06 19:26 ` Thomas Gleixner [this message]
2020-12-07 19:28 ` Jason Gunthorpe
2020-12-07 19:58 ` James Bottomley
2020-12-08 17:43 ` Jarkko Sakkinen
2020-12-08 17:42 ` Jarkko Sakkinen
2020-12-05 1:43 ` [PATCH v3 4/4] tpm_tis: Disable Interrupts on the ThinkPad L490 Jerry Snitselaar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87tusy7n3b.fsf@nanos.tec.linutronix.de \
--to=tglx@linutronix.de \
--cc=James.Bottomley@HansenPartnership.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=hdegoede@redhat.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=jarkko@kernel.org \
--cc=jgg@ziepe.ca \
--cc=jsnitsel@redhat.com \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mjg59@google.com \
--cc=peterhuewe@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome