ssize_t ret;
        const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE,
                                     bufsiz);
+       /* the command code is where the return code will be */
+       u32 cc = be32_to_cpu(header->return_code);
 
        /*
         * Subtlety here: if we have a space, the handles will be
                if (ret < 0)
                        break;
                rc = be32_to_cpu(header->return_code);
-               if (rc != TPM2_RC_RETRY)
+               if (rc != TPM2_RC_RETRY && rc != TPM2_RC_TESTING)
+                       break;
+               /*
+                * return immediately if self test returns test
+                * still running to shorten boot time.
+                */
+               if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST)
                        break;
                delay_msec *= 2;
                if (delay_msec > TPM2_DURATION_LONG) {
-                       dev_err(&chip->dev, "TPM is in retry loop\n");
+                       if (rc == TPM2_RC_RETRY)
+                               dev_err(&chip->dev, "in retry loop\n");
+                       else
+                               dev_err(&chip->dev,
+                                       "self test is still running\n");
                        break;
                }
                tpm_msleep(delay_msec);
 
        __be16  startup_type;
 } __packed;
 
-struct tpm2_self_test_in {
-       u8      full_test;
-} __packed;
-
 struct tpm2_get_tpm_pt_in {
        __be32  cap_id;
        __be32  property_id;
 
 union tpm2_cmd_params {
        struct  tpm2_startup_in         startup_in;
-       struct  tpm2_self_test_in       selftest_in;
        struct  tpm2_get_tpm_pt_in      get_tpm_pt_in;
        struct  tpm2_get_tpm_pt_out     get_tpm_pt_out;
        struct  tpm2_get_random_in      getrandom_in;
 }
 EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
 
-#define TPM2_SELF_TEST_IN_SIZE \
-       (sizeof(struct tpm_input_header) + \
-        sizeof(struct tpm2_self_test_in))
-
-static const struct tpm_input_header tpm2_selftest_header = {
-       .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
-       .length = cpu_to_be32(TPM2_SELF_TEST_IN_SIZE),
-       .ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
-};
-
 /**
  * tpm2_do_selftest() - ensure that all self tests have passed
  *
  */
 static int tpm2_do_selftest(struct tpm_chip *chip)
 {
+       struct tpm_buf buf;
+       int full;
        int rc;
-       unsigned int delay_msec = 10;
-       long duration;
-       struct tpm2_cmd cmd;
 
-       duration = jiffies_to_msecs(
-               tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
-
-       while (1) {
-               cmd.header.in = tpm2_selftest_header;
-               cmd.params.selftest_in.full_test = 0;
-
-               rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
-                                     0, 0, "continue selftest");
+       for (full = 0; full < 2; full++) {
+               rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST);
+               if (rc)
+                       return rc;
 
-               if (rc != TPM2_RC_TESTING || delay_msec >= duration)
-                       break;
+               tpm_buf_append_u8(&buf, full);
+               rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
+                                     "attempting the self test");
+               tpm_buf_destroy(&buf);
 
-               /* wait longer than before */
-               delay_msec *= 2;
-               tpm_msleep(delay_msec);
+               if (rc == TPM2_RC_TESTING)
+                       rc = TPM2_RC_SUCCESS;
+               if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS)
+                       return rc;
        }
 
        return rc;
                goto out;
 
        rc = tpm2_do_selftest(chip);
-       if (rc != 0 && rc != TPM2_RC_INITIALIZE) {
-               dev_err(&chip->dev, "TPM self test failed\n");
+       if (rc && rc != TPM2_RC_INITIALIZE)
                goto out;
-       }
 
        if (rc == TPM2_RC_INITIALIZE) {
                rc = tpm_startup(chip);
                        goto out;
 
                rc = tpm2_do_selftest(chip);
-               if (rc) {
-                       dev_err(&chip->dev, "TPM self test failed\n");
+               if (rc)
                        goto out;
-               }
        }
 
        rc = tpm2_get_pcr_allocation(chip);