diff mbox

[v10,8/8] tpm: TPM 2.0 FIFO Interface

Message ID 1418413600-5400-9-git-send-email-jarkko.sakkinen@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jarkko Sakkinen Dec. 12, 2014, 7:46 p.m. UTC
Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for
TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe.
Using STS3 is unreliable because some chips just report 0xff and not
what the spec says.

Before TPM family is detected, timeouts are set to the maximum values
for both TPM 1.x and TPM 2.x. In addition to this, suspend/resume
functionality is implemented for TPM 2.x.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Will Arthur <will.c.arthur@intel.com>
Reviewed-by: Jasob Gunthorpe <jason.gunthorpe@obsidianresearch.com>
Reviewed-by: Stephan Berger <stephan.berger@linux.vnet.ibm.com>
---
 drivers/char/tpm/tpm_tis.c | 112 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 89 insertions(+), 23 deletions(-)

Comments

Stefan Berger Dec. 14, 2014, 2:48 p.m. UTC | #1
On 12/12/2014 02:46 PM, Jarkko Sakkinen wrote:
> Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for
> TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe.
> Using STS3 is unreliable because some chips just report 0xff and not
> what the spec says.

TPM TIS 1.2 can report either 0xff or 0x00 for sts3 since that part of 
register was not defined for this version but only for a later version. 
So, unless the TIS 1.3 for TPM 2.0 is broken, it should report a bit 
_pattern_ (not plain 0x00 or 0xff) that you could apply the suggested 
mask to and check then.

     Stefan


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
Jarkko Sakkinen Dec. 14, 2014, 3:40 p.m. UTC | #2
On Sun, Dec 14, 2014 at 09:48:26AM -0500, Stefan Berger wrote:
> On 12/12/2014 02:46 PM, Jarkko Sakkinen wrote:
> >Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for
> >TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe.
> >Using STS3 is unreliable because some chips just report 0xff and not
> >what the spec says.
> 
> TPM TIS 1.2 can report either 0xff or 0x00 for sts3 since that part of
> register was not defined for this version but only for a later version. So,
> unless the TIS 1.3 for TPM 2.0 is broken, it should report a bit _pattern_
> (not plain 0x00 or 0xff) that you could apply the suggested mask to and
> check then.

I propose this: lets keep the bit ugly but approach for now and when 
there are TPM2 FIFOs available in the market move to your workaround. 
I think that would be the most reasonable middle road here.

>     Stefan

/Jarkko

------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
Stefan Berger Dec. 14, 2014, 4:09 p.m. UTC | #3
On 12/14/2014 10:40 AM, Jarkko Sakkinen wrote:
> On Sun, Dec 14, 2014 at 09:48:26AM -0500, Stefan Berger wrote:
>> On 12/12/2014 02:46 PM, Jarkko Sakkinen wrote:
>>> Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for
>>> TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe.
>>> Using STS3 is unreliable because some chips just report 0xff and not
>>> what the spec says.
>> TPM TIS 1.2 can report either 0xff or 0x00 for sts3 since that part of
>> register was not defined for this version but only for a later version. So,
>> unless the TIS 1.3 for TPM 2.0 is broken, it should report a bit _pattern_
>> (not plain 0x00 or 0xff) that you could apply the suggested mask to and
>> check then.
> I propose this: lets keep the bit ugly but approach for now and when
> there are TPM2 FIFOs available in the market move to your workaround.
> I think that would be the most reasonable middle road here.

You are now calling tpm2_gen_interrupt and are looking at the rc, which 
is the rc from tpm_transmit_cmd, which seems to make sure that the 
sending of the command went alright and the reception of the response. 
Is this good enough to distinguish between a TPM 2 and a TPM 1.2? If you 
send a valid TPM 2 command to a TPM 1.2 this will at least transmit the 
data ok, but the TPM will respond with a TPM 1.2 tag in the response. 
The way I understand the code, the rc does not include whether the 
response packet is a valid TPM 2 response packet and lets you conclude 
to a TPM2. I do something similar in upcoming QEMU patches where I send 
a valid TPM2 command for probing and if the tag(!) in the response is a 
TPM2 tag (0x8001 = TPM_ST_NO_SESSIONS), then it's a TPM 2, otherwise a 
TPM 1.2.

Did you test this with a TPM 1.2 ?

    Stefan

>
>>      Stefan
> /Jarkko
>


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
Scot Doyle Dec. 14, 2014, 6:27 p.m. UTC | #4
On Sun, 14 Dec 2014, Stefan Berger wrote:
> On 12/14/2014 10:40 AM, Jarkko Sakkinen wrote:
> > On Sun, Dec 14, 2014 at 09:48:26AM -0500, Stefan Berger wrote:
> > > On 12/12/2014 02:46 PM, Jarkko Sakkinen wrote:
> > > > Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for
> > > > TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe.
> > > > Using STS3 is unreliable because some chips just report 0xff and not
> > > > what the spec says.
> > > TPM TIS 1.2 can report either 0xff or 0x00 for sts3 since that part of
> > > register was not defined for this version but only for a later version.
> > > So,
> > > unless the TIS 1.3 for TPM 2.0 is broken, it should report a bit _pattern_
> > > (not plain 0x00 or 0xff) that you could apply the suggested mask to and
> > > check then.
> > I propose this: lets keep the bit ugly but approach for now and when
> > there are TPM2 FIFOs available in the market move to your workaround.
> > I think that would be the most reasonable middle road here.
> 
> You are now calling tpm2_gen_interrupt and are looking at the rc, which is the
> rc from tpm_transmit_cmd, which seems to make sure that the sending of the
> command went alright and the reception of the response. Is this good enough to
> distinguish between a TPM 2 and a TPM 1.2? If you send a valid TPM 2 command
> to a TPM 1.2 this will at least transmit the data ok, but the TPM will respond
> with a TPM 1.2 tag in the response. The way I understand the code, the rc does
> not include whether the response packet is a valid TPM 2 response packet and
> lets you conclude to a TPM2. I do something similar in upcoming QEMU patches
> where I send a valid TPM2 command for probing and if the tag(!) in the
> response is a TPM2 tag (0x8001 = TPM_ST_NO_SESSIONS), then it's a TPM 2,
> otherwise a TPM 1.2.
> 
> Did you test this with a TPM 1.2 ?
> 
>    Stefan

One system's output, with a dev_info call to show the value of rc:
[ 0.223837] tpm_tis 00:08: tpm2_gen_interrupt(chip, true) -> 0xa
[ 0.223847] tpm_tis 00:08: 1.2 TPM (device-id 0xB, rev-id 16)
[ 0.280468] tpm_tis 00:08: [Firmware Bug]: TPM interrupt not working, polling instead


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
Stefan Berger Dec. 14, 2014, 8:40 p.m. UTC | #5
On 12/14/2014 01:27 PM, Scot Doyle wrote:
> On Sun, 14 Dec 2014, Stefan Berger wrote:
>> On 12/14/2014 10:40 AM, Jarkko Sakkinen wrote:
>>> On Sun, Dec 14, 2014 at 09:48:26AM -0500, Stefan Berger wrote:
>>>> On 12/12/2014 02:46 PM, Jarkko Sakkinen wrote:
>>>>> Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for
>>>>> TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe.
>>>>> Using STS3 is unreliable because some chips just report 0xff and not
>>>>> what the spec says.
>>>> TPM TIS 1.2 can report either 0xff or 0x00 for sts3 since that part of
>>>> register was not defined for this version but only for a later version.
>>>> So,
>>>> unless the TIS 1.3 for TPM 2.0 is broken, it should report a bit _pattern_
>>>> (not plain 0x00 or 0xff) that you could apply the suggested mask to and
>>>> check then.
>>> I propose this: lets keep the bit ugly but approach for now and when
>>> there are TPM2 FIFOs available in the market move to your workaround.
>>> I think that would be the most reasonable middle road here.
>> You are now calling tpm2_gen_interrupt and are looking at the rc, which is the
>> rc from tpm_transmit_cmd, which seems to make sure that the sending of the
>> command went alright and the reception of the response. Is this good enough to
>> distinguish between a TPM 2 and a TPM 1.2? If you send a valid TPM 2 command
>> to a TPM 1.2 this will at least transmit the data ok, but the TPM will respond
>> with a TPM 1.2 tag in the response. The way I understand the code, the rc does
>> not include whether the response packet is a valid TPM 2 response packet and
>> lets you conclude to a TPM2. I do something similar in upcoming QEMU patches
>> where I send a valid TPM2 command for probing and if the tag(!) in the
>> response is a TPM2 tag (0x8001 = TPM_ST_NO_SESSIONS), then it's a TPM 2,
>> otherwise a TPM 1.2.
>>
>> Did you test this with a TPM 1.2 ?
>>
>>     Stefan
> One system's output, with a dev_info call to show the value of rc:
> [ 0.223837] tpm_tis 00:08: tpm2_gen_interrupt(chip, true) -> 0xa
> [ 0.223847] tpm_tis 00:08: 1.2 TPM (device-id 0xB, rev-id 16)
> [ 0.280468] tpm_tis 00:08: [Firmware Bug]: TPM interrupt not working, polling instead
>

Ok, good.

[We won't be able to use STS3 if the TIS of Jarkko's TPM2 is broken...]

     Stefan



    Stefan


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
Jarkko Sakkinen Dec. 14, 2014, 11:13 p.m. UTC | #6
On Sun, Dec 14, 2014 at 03:40:05PM -0500, Stefan Berger wrote:
> On 12/14/2014 01:27 PM, Scot Doyle wrote:
> >On Sun, 14 Dec 2014, Stefan Berger wrote:
> >>On 12/14/2014 10:40 AM, Jarkko Sakkinen wrote:
> >>>On Sun, Dec 14, 2014 at 09:48:26AM -0500, Stefan Berger wrote:
> >>>>On 12/12/2014 02:46 PM, Jarkko Sakkinen wrote:
> >>>>>Detect TPM 2.0 by sending idempotent TPM 2.x command. Ordinals for
> >>>>>TPM 2.0 are higher than TPM 1.x commands so this should be fail-safe.
> >>>>>Using STS3 is unreliable because some chips just report 0xff and not
> >>>>>what the spec says.
> >>>>TPM TIS 1.2 can report either 0xff or 0x00 for sts3 since that part of
> >>>>register was not defined for this version but only for a later version.
> >>>>So,
> >>>>unless the TIS 1.3 for TPM 2.0 is broken, it should report a bit _pattern_
> >>>>(not plain 0x00 or 0xff) that you could apply the suggested mask to and
> >>>>check then.
> >>>I propose this: lets keep the bit ugly but approach for now and when
> >>>there are TPM2 FIFOs available in the market move to your workaround.
> >>>I think that would be the most reasonable middle road here.
> >>You are now calling tpm2_gen_interrupt and are looking at the rc, which is the
> >>rc from tpm_transmit_cmd, which seems to make sure that the sending of the
> >>command went alright and the reception of the response. Is this good enough to
> >>distinguish between a TPM 2 and a TPM 1.2? If you send a valid TPM 2 command
> >>to a TPM 1.2 this will at least transmit the data ok, but the TPM will respond
> >>with a TPM 1.2 tag in the response. The way I understand the code, the rc does
> >>not include whether the response packet is a valid TPM 2 response packet and
> >>lets you conclude to a TPM2. I do something similar in upcoming QEMU patches
> >>where I send a valid TPM2 command for probing and if the tag(!) in the
> >>response is a TPM2 tag (0x8001 = TPM_ST_NO_SESSIONS), then it's a TPM 2,
> >>otherwise a TPM 1.2.
> >>
> >>Did you test this with a TPM 1.2 ?
> >>
> >>    Stefan
> >One system's output, with a dev_info call to show the value of rc:
> >[ 0.223837] tpm_tis 00:08: tpm2_gen_interrupt(chip, true) -> 0xa
> >[ 0.223847] tpm_tis 00:08: 1.2 TPM (device-id 0xB, rev-id 16)
> >[ 0.280468] tpm_tis 00:08: [Firmware Bug]: TPM interrupt not working, polling instead
> >
> 
> Ok, good.
> 
> [We won't be able to use STS3 if the TIS of Jarkko's TPM2 is broken...]

Yes, the prototype module that I had to use had the same problem as TPM
1.2 chips.

I think your idea of using tag is much cleaner than using the error
code. I'll probably submit a separate patch for that later on but since
this code is now verified to work on two TPM 1.2 chips (my own and
Scots) and one dTPM2 module, lets keep it that way until this patch
set is pulled at least...

/Jarkko

------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
diff mbox

Patch

diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 89e1abb..c8884be 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -1,5 +1,6 @@ 
 /*
  * Copyright (C) 2005, 2006 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
  *
  * Authors:
  * Leendert van Doorn <leendert@watson.ibm.com>
@@ -64,12 +65,22 @@  enum tis_defaults {
 	TIS_LONG_TIMEOUT = 2000,	/* 2 sec */
 };
 
+
+/* Some timeout values are needed before it is known whether the chip is
+ * TPM 1.0 or TPM 2.0.
+ */
+#define TIS_TIMEOUT_A_MAX	max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
+#define TIS_TIMEOUT_B_MAX	max(TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
+#define TIS_TIMEOUT_C_MAX	max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
+#define TIS_TIMEOUT_D_MAX	max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
+
 #define	TPM_ACCESS(l)			(0x0000 | ((l) << 12))
 #define	TPM_INT_ENABLE(l)		(0x0008 | ((l) << 12))
 #define	TPM_INT_VECTOR(l)		(0x000C | ((l) << 12))
 #define	TPM_INT_STATUS(l)		(0x0010 | ((l) << 12))
 #define	TPM_INTF_CAPS(l)		(0x0014 | ((l) << 12))
 #define	TPM_STS(l)			(0x0018 | ((l) << 12))
+#define	TPM_STS3(l)			(0x001b | ((l) << 12))
 #define	TPM_DATA_FIFO(l)		(0x0024 | ((l) << 12))
 
 #define	TPM_DID_VID(l)			(0x0F00 | ((l) << 12))
@@ -363,6 +374,7 @@  static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
 {
 	int rc;
 	u32 ordinal;
+	unsigned long dur;
 
 	rc = tpm_tis_send_data(chip, buf, len);
 	if (rc < 0)
@@ -374,9 +386,14 @@  static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
 
 	if (chip->vendor.irq) {
 		ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+
+		if (chip->flags & TPM_CHIP_FLAG_TPM2)
+			dur = tpm2_calc_ordinal_duration(chip, ordinal);
+		else
+			dur = tpm_calc_ordinal_duration(chip, ordinal);
+
 		if (wait_for_tpm_stat
-		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-		     tpm_calc_ordinal_duration(chip, ordinal),
+		    (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
 		     &chip->vendor.read_queue, false) < 0) {
 			rc = -ETIME;
 			goto out_err;
@@ -598,17 +615,19 @@  static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 		return PTR_ERR(chip);
 
 	chip->vendor.priv = priv;
+#ifdef CONFIG_ACPI
 	chip->acpi_dev_handle = acpi_dev_handle;
+#endif
 
 	chip->vendor.iobase = devm_ioremap(dev, start, len);
 	if (!chip->vendor.iobase)
 		return -EIO;
 
-	/* Default timeouts */
-	chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-	chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
-	chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
-	chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+	/* Maximum timeouts */
+	chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX;
+	chip->vendor.timeout_b = TIS_TIMEOUT_B_MAX;
+	chip->vendor.timeout_c = TIS_TIMEOUT_C_MAX;
+	chip->vendor.timeout_d = TIS_TIMEOUT_D_MAX;
 
 	if (wait_startup(chip, 0) != 0) {
 		rc = -ENODEV;
@@ -620,11 +639,18 @@  static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 		goto out_err;
 	}
 
+	/* Every TPM 2.x command has a higher ordinal than TPM 1.x commands.
+	 * Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x.
+	 */
+	rc = tpm2_gen_interrupt(chip, true);
+	if (rc == 0 || rc == TPM2_RC_INITIALIZE)
+		chip->flags |= TPM_CHIP_FLAG_TPM2;
+
 	vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
 	chip->vendor.manufacturer_id = vendor;
 
-	dev_info(dev,
-		 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
+	dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
+		 (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
 		 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
 	if (!itpm) {
@@ -720,7 +746,10 @@  static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 			chip->vendor.probed_irq = 0;
 
 			/* Generate Interrupts */
-			tpm_gen_interrupt(chip);
+			if (chip->flags & TPM_CHIP_FLAG_TPM2)
+				tpm2_gen_interrupt(chip, false);
+			else
+				tpm_gen_interrupt(chip);
 
 			chip->vendor.irq = chip->vendor.probed_irq;
 
@@ -765,16 +794,44 @@  static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
 		}
 	}
 
-	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) {
+		chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
+		chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
+		chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
+		chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
+		chip->vendor.duration[TPM_SHORT] =
+			msecs_to_jiffies(TPM2_DURATION_SHORT);
+		chip->vendor.duration[TPM_MEDIUM] =
+			msecs_to_jiffies(TPM2_DURATION_MEDIUM);
+		chip->vendor.duration[TPM_LONG] =
+			msecs_to_jiffies(TPM2_DURATION_LONG);
+
+		rc = tpm2_do_selftest(chip);
+		if (rc == TPM2_RC_INITIALIZE) {
+			dev_warn(dev, "Firmware has not started TPM\n");
+			rc  = tpm2_startup(chip, TPM2_SU_CLEAR);
+			if (!rc)
+				rc = tpm2_do_selftest(chip);
+		}
 
-	if (tpm_do_selftest(chip)) {
-		dev_err(dev, "TPM self test failed\n");
-		rc = -ENODEV;
-		goto out_err;
+		if (rc) {
+			dev_err(dev, "TPM self test failed\n");
+			if (rc > 0)
+				rc = -ENODEV;
+			goto out_err;
+		}
+	} else {
+		if (tpm_get_timeouts(chip)) {
+			dev_err(dev, "Could not get TPM timeouts and durations\n");
+			rc = -ENODEV;
+			goto out_err;
+		}
+
+		if (tpm_do_selftest(chip)) {
+			dev_err(dev, "TPM self test failed\n");
+			rc = -ENODEV;
+			goto out_err;
+		}
 	}
 
 	return tpm_chip_register(chip);
@@ -808,14 +865,23 @@  static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
 static int tpm_tis_resume(struct device *dev)
 {
 	struct tpm_chip *chip = dev_get_drvdata(dev);
-	int ret;
+	int ret = 0;
 
 	if (chip->vendor.irq)
 		tpm_tis_reenable_interrupts(chip);
 
-	ret = tpm_pm_resume(dev);
-	if (!ret)
-		tpm_do_selftest(chip);
+	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+		/* NOP if firmware properly does this. */
+		tpm2_startup(chip, TPM2_SU_STATE);
+
+		ret = tpm2_shutdown(chip, TPM2_SU_STATE);
+		if (!ret)
+			ret = tpm2_do_selftest(chip);
+	} else {
+		ret = tpm_pm_resume(dev);
+		if (!ret)
+			tpm_do_selftest(chip);
+	}
 
 	return ret;
 }