diff options
author | Linus Torvalds | 2018-04-07 16:46:56 -0700 |
---|---|---|
committer | Linus Torvalds | 2018-04-07 16:46:56 -0700 |
commit | 4b3f1a151571985f7c9964260db1c31e056a67e4 (patch) | |
tree | 34f4dcdd36dbeb8bf3c6919f9740dc65273ddd2e /drivers/char/tpm | |
parent | 706ffc8c26432432fcd6d8a02708b40852bd0bd2 (diff) | |
parent | ed807f6aaf787b83885a571268c5d803068f60a6 (diff) |
Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull TPM updates from James Morris:
"This release contains only bug fixes. There are no new major features
added"
* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
tpm: fix intermittent failure with self tests
tpm: add retry logic
tpm: self test failure should not cause suspend to fail
tpm2: add longer timeouts for creation commands.
tpm_crb: use __le64 annotated variable for response buffer address
tpm: fix buffer type in tpm_transmit_cmd
tpm: tpm-interface: fix tpm_transmit/_cmd kdoc
tpm: cmd_ready command can be issued only after granting locality
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 158 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 32 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 62 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_crb.c | 113 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.c | 4 |
5 files changed, 249 insertions, 120 deletions
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 9e80a953d693..c43a9e28995e 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -369,20 +369,40 @@ err_len: return -EINVAL; } -/** - * tmp_transmit - Internal kernel interface to transmit TPM commands. - * - * @chip: TPM chip to use - * @buf: TPM command buffer - * @bufsiz: length of the TPM command buffer - * @flags: tpm transmit flags - bitmap - * - * Return: - * 0 when the operation is successful. - * A negative number for system errors (errno). - */ -ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, - u8 *buf, size_t bufsiz, unsigned int flags) +static int tpm_request_locality(struct tpm_chip *chip) +{ + int rc; + + if (!chip->ops->request_locality) + return 0; + + rc = chip->ops->request_locality(chip, 0); + if (rc < 0) + return rc; + + chip->locality = rc; + + return 0; +} + +static void tpm_relinquish_locality(struct tpm_chip *chip) +{ + int rc; + + if (!chip->ops->relinquish_locality) + return; + + rc = chip->ops->relinquish_locality(chip, chip->locality); + if (rc) + dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); + + chip->locality = -1; +} + +static ssize_t tpm_try_transmit(struct tpm_chip *chip, + struct tpm_space *space, + u8 *buf, size_t bufsiz, + unsigned int flags) { struct tpm_output_header *header = (void *)buf; int rc; @@ -422,8 +442,6 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); - if (chip->dev.parent) - pm_runtime_get_sync(chip->dev.parent); if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, true); @@ -431,19 +449,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; - if (!(flags & TPM_TRANSMIT_RAW) && - need_locality && chip->ops->request_locality) { - rc = chip->ops->request_locality(chip, 0); + if (!(flags & TPM_TRANSMIT_RAW) && need_locality) { + rc = tpm_request_locality(chip); if (rc < 0) goto out_no_locality; - chip->locality = rc; } + if (chip->dev.parent) + pm_runtime_get_sync(chip->dev.parent); + rc = tpm2_prepare_space(chip, space, ordinal, buf); if (rc) goto out; - rc = chip->ops->send(chip, (u8 *) buf, count); + rc = chip->ops->send(chip, buf, count); if (rc < 0) { if (rc != -EPIPE) dev_err(&chip->dev, @@ -480,7 +499,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, goto out; out_recv: - len = chip->ops->recv(chip, (u8 *) buf, bufsiz); + len = chip->ops->recv(chip, buf, bufsiz); if (len < 0) { rc = len; dev_err(&chip->dev, @@ -499,27 +518,95 @@ out_recv: rc = tpm2_commit_space(chip, space, ordinal, buf, &len); out: - if (need_locality && chip->ops->relinquish_locality) { - chip->ops->relinquish_locality(chip, chip->locality); - chip->locality = -1; - } + if (chip->dev.parent) + pm_runtime_put_sync(chip->dev.parent); + + if (need_locality) + tpm_relinquish_locality(chip); + out_no_locality: if (chip->ops->clk_enable != NULL) chip->ops->clk_enable(chip, false); - if (chip->dev.parent) - pm_runtime_put_sync(chip->dev.parent); - if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); return rc ? rc : len; } /** - * tmp_transmit_cmd - send a tpm command to the device + * tpm_transmit - Internal kernel interface to transmit TPM commands. + * + * @chip: TPM chip to use + * @space: tpm space + * @buf: TPM command buffer + * @bufsiz: length of the TPM command buffer + * @flags: tpm transmit flags - bitmap + * + * A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY + * returns from the TPM and retransmits the command after a delay up + * to a maximum wait of TPM2_DURATION_LONG. + * + * Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2 + * only + * + * Return: + * the length of the return when the operation is successful. + * A negative number for system errors (errno). + */ +ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, + u8 *buf, size_t bufsiz, unsigned int flags) +{ + struct tpm_output_header *header = (struct tpm_output_header *)buf; + /* space for header and handles */ + u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)]; + unsigned int delay_msec = TPM2_DURATION_SHORT; + u32 rc = 0; + 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 + * transformed, so when we restore the header we also have to + * restore the handles. + */ + memcpy(save, buf, save_size); + + for (;;) { + ret = tpm_try_transmit(chip, space, buf, bufsiz, flags); + if (ret < 0) + break; + rc = be32_to_cpu(header->return_code); + 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) { + 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); + memcpy(buf, save, save_size); + } + return ret; +} +/** + * tpm_transmit_cmd - send a tpm command to the device * The function extracts tpm out header return code * * @chip: TPM chip to use + * @space: tpm space * @buf: TPM command buffer * @bufsiz: length of the buffer * @min_rsp_body_length: minimum expected length of response body @@ -532,7 +619,7 @@ out_no_locality: * A positive number for a TPM error. */ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, - const void *buf, size_t bufsiz, + void *buf, size_t bufsiz, size_t min_rsp_body_length, unsigned int flags, const char *desc) { @@ -540,7 +627,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, int err; ssize_t len; - len = tpm_transmit(chip, space, (u8 *)buf, bufsiz, flags); + len = tpm_transmit(chip, space, buf, bufsiz, flags); if (len < 0) return len; @@ -666,6 +753,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) msecs_to_jiffies(TPM2_DURATION_MEDIUM); chip->duration[TPM_LONG] = msecs_to_jiffies(TPM2_DURATION_LONG); + chip->duration[TPM_LONG_LONG] = + msecs_to_jiffies(TPM2_DURATION_LONG_LONG); chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS; return 0; @@ -754,6 +843,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); chip->duration[TPM_LONG] = usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long)); + chip->duration[TPM_LONG_LONG] = 0; /* not used under 1.2 */ /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above * value wrong and apparently reports msecs rather than usecs. So we @@ -969,6 +1059,10 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); + if (rc == TPM_ERR_INVALID_POSTINIT) { + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + dev_info(&chip->dev, "TPM not ready (%d)\n", rc); + } /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index f895fba4e20d..7f2d0f489e9c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -67,7 +67,9 @@ enum tpm_duration { TPM_SHORT = 0, TPM_MEDIUM = 1, TPM_LONG = 2, + TPM_LONG_LONG = 3, TPM_UNDEFINED, + TPM_NUM_DURATIONS = TPM_UNDEFINED, }; #define TPM_WARN_RETRY 0x800 @@ -79,15 +81,20 @@ enum tpm_duration { #define TPM_HEADER_SIZE 10 enum tpm2_const { - TPM2_PLATFORM_PCR = 24, - TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8), - TPM2_TIMEOUT_A = 750, - TPM2_TIMEOUT_B = 2000, - TPM2_TIMEOUT_C = 200, - TPM2_TIMEOUT_D = 30, - TPM2_DURATION_SHORT = 20, - TPM2_DURATION_MEDIUM = 750, - TPM2_DURATION_LONG = 2000, + TPM2_PLATFORM_PCR = 24, + TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8), +}; + +enum tpm2_timeouts { + TPM2_TIMEOUT_A = 750, + TPM2_TIMEOUT_B = 2000, + TPM2_TIMEOUT_C = 200, + TPM2_TIMEOUT_D = 30, + TPM2_DURATION_SHORT = 20, + TPM2_DURATION_MEDIUM = 750, + TPM2_DURATION_LONG = 2000, + TPM2_DURATION_LONG_LONG = 300000, + TPM2_DURATION_DEFAULT = 120000, }; enum tpm2_structures { @@ -104,10 +111,12 @@ enum tpm2_return_codes { TPM2_RC_HASH = 0x0083, /* RC_FMT1 */ TPM2_RC_HANDLE = 0x008B, TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */ + TPM2_RC_FAILURE = 0x0101, TPM2_RC_DISABLED = 0x0120, TPM2_RC_COMMAND_CODE = 0x0143, TPM2_RC_TESTING = 0x090A, /* RC_WARN */ TPM2_RC_REFERENCE_H0 = 0x0910, + TPM2_RC_RETRY = 0x0922, }; enum tpm2_algorithms { @@ -123,6 +132,7 @@ enum tpm2_algorithms { enum tpm2_command_codes { TPM2_CC_FIRST = 0x011F, + TPM2_CC_CREATE_PRIMARY = 0x0131, TPM2_CC_SELF_TEST = 0x0143, TPM2_CC_STARTUP = 0x0144, TPM2_CC_SHUTDOWN = 0x0145, @@ -227,7 +237,7 @@ struct tpm_chip { unsigned long timeout_c; /* jiffies */ unsigned long timeout_d; /* jiffies */ bool timeout_adjusted; - unsigned long duration[3]; /* jiffies */ + unsigned long duration[TPM_NUM_DURATIONS]; /* jiffies */ bool duration_adjusted; struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES]; @@ -506,7 +516,7 @@ enum tpm_transmit_flags { ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, u8 *buf, size_t bufsiz, unsigned int flags); ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space, - const void *buf, size_t bufsiz, + void *buf, size_t bufsiz, size_t min_rsp_body_length, unsigned int flags, const char *desc); int tpm_startup(struct tpm_chip *chip); diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index a700f8f9ead7..96c77c8e7f40 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -31,10 +31,6 @@ struct tpm2_startup_in { __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; @@ -60,7 +56,6 @@ struct tpm2_get_random_out { 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; @@ -90,6 +85,8 @@ static struct tpm2_hash tpm2_hash_map[] = { * of time the chip could take to return the result. The values * of the SHORT, MEDIUM, and LONG durations are taken from the * PC Client Profile (PTP) specification. + * LONG_LONG is for commands that generates keys which empirically + * takes longer time on some systems. */ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { TPM_UNDEFINED, /* 11F */ @@ -110,7 +107,7 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { TPM_UNDEFINED, /* 12e */ TPM_UNDEFINED, /* 12f */ TPM_UNDEFINED, /* 130 */ - TPM_UNDEFINED, /* 131 */ + TPM_LONG_LONG, /* 131 */ TPM_UNDEFINED, /* 132 */ TPM_UNDEFINED, /* 133 */ TPM_UNDEFINED, /* 134 */ @@ -144,7 +141,7 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { TPM_UNDEFINED, /* 150 */ TPM_UNDEFINED, /* 151 */ TPM_UNDEFINED, /* 152 */ - TPM_UNDEFINED, /* 153 */ + TPM_LONG_LONG, /* 153 */ TPM_UNDEFINED, /* 154 */ TPM_UNDEFINED, /* 155 */ TPM_UNDEFINED, /* 156 */ @@ -821,22 +818,12 @@ unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) duration = chip->duration[index]; if (duration <= 0) - duration = 2 * 60 * HZ; + duration = msecs_to_jiffies(TPM2_DURATION_DEFAULT); return duration; } 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 * @@ -852,27 +839,24 @@ static const struct tpm_input_header tpm2_selftest_header = { */ 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; @@ -1058,10 +1042,8 @@ int tpm2_auto_startup(struct tpm_chip *chip) 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); @@ -1069,10 +1051,8 @@ int tpm2_auto_startup(struct tpm_chip *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); diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 7b3c2a8aa9de..7f78482cd157 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -112,6 +112,25 @@ struct tpm2_crb_smc { u32 smc_func_id; }; +static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, + unsigned long timeout) +{ + ktime_t start; + ktime_t stop; + + start = ktime_get(); + stop = ktime_add(start, ms_to_ktime(timeout)); + + do { + if ((ioread32(reg) & mask) == value) + return true; + + usleep_range(50, 100); + } while (ktime_before(ktime_get(), stop)); + + return ((ioread32(reg) & mask) == value); +} + /** * crb_go_idle - request tpm crb device to go the idle state * @@ -128,7 +147,7 @@ struct tpm2_crb_smc { * * Return: 0 always */ -static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) +static int crb_go_idle(struct device *dev, struct crb_priv *priv) { if ((priv->sm == ACPI_TPM2_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || @@ -136,30 +155,17 @@ static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) return 0; iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->regs_t->ctrl_req); - /* we don't really care when this settles */ + if (!crb_wait_for_reg_32(&priv->regs_t->ctrl_req, + CRB_CTRL_REQ_GO_IDLE/* mask */, + 0, /* value */ + TPM2_TIMEOUT_C)) { + dev_warn(dev, "goIdle timed out\n"); + return -ETIME; + } return 0; } -static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, - unsigned long timeout) -{ - ktime_t start; - ktime_t stop; - - start = ktime_get(); - stop = ktime_add(start, ms_to_ktime(timeout)); - - do { - if ((ioread32(reg) & mask) == value) - return true; - - usleep_range(50, 100); - } while (ktime_before(ktime_get(), stop)); - - return false; -} - /** * crb_cmd_ready - request tpm crb device to enter ready state * @@ -175,8 +181,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, * * Return: 0 on success -ETIME on timeout; */ -static int __maybe_unused crb_cmd_ready(struct device *dev, - struct crb_priv *priv) +static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) { if ((priv->sm == ACPI_TPM2_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || @@ -195,11 +200,11 @@ static int __maybe_unused crb_cmd_ready(struct device *dev, return 0; } -static int crb_request_locality(struct tpm_chip *chip, int loc) +static int __crb_request_locality(struct device *dev, + struct crb_priv *priv, int loc) { - struct crb_priv *priv = dev_get_drvdata(&chip->dev); u32 value = CRB_LOC_STATE_LOC_ASSIGNED | - CRB_LOC_STATE_TPM_REG_VALID_STS; + CRB_LOC_STATE_TPM_REG_VALID_STS; if (!priv->regs_h) return 0; @@ -207,21 +212,45 @@ static int crb_request_locality(struct tpm_chip *chip, int loc) iowrite32(CRB_LOC_CTRL_REQUEST_ACCESS, &priv->regs_h->loc_ctrl); if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, value, value, TPM2_TIMEOUT_C)) { - dev_warn(&chip->dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); + dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); return -ETIME; } return 0; } -static void crb_relinquish_locality(struct tpm_chip *chip, int loc) +static int crb_request_locality(struct tpm_chip *chip, int loc) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); + return __crb_request_locality(&chip->dev, priv, loc); +} + +static int __crb_relinquish_locality(struct device *dev, + struct crb_priv *priv, int loc) +{ + u32 mask = CRB_LOC_STATE_LOC_ASSIGNED | + CRB_LOC_STATE_TPM_REG_VALID_STS; + u32 value = CRB_LOC_STATE_TPM_REG_VALID_STS; + if (!priv->regs_h) - return; + return 0; iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl); + if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, mask, value, + TPM2_TIMEOUT_C)) { + dev_warn(dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); + return -ETIME; + } + + return 0; +} + +static int crb_relinquish_locality(struct tpm_chip *chip, int loc) +{ + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return __crb_relinquish_locality(&chip->dev, priv, loc); } static u8 crb_status(struct tpm_chip *chip) @@ -442,6 +471,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, u32 pa_high, pa_low; u64 cmd_pa; u32 cmd_size; + __le64 __rsp_pa; u64 rsp_pa; u32 rsp_size; int ret; @@ -475,6 +505,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, dev_warn(dev, FW_BUG "Bad ACPI memory layout"); } + ret = __crb_request_locality(dev, priv, 0); + if (ret) + return ret; + priv->regs_t = crb_map_res(dev, priv, &io_res, buf->control_address, sizeof(struct crb_regs_tail)); if (IS_ERR(priv->regs_t)) @@ -503,8 +537,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, goto out; } - memcpy_fromio(&rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); - rsp_pa = le64_to_cpu(rsp_pa); + memcpy_fromio(&__rsp_pa, &priv->regs_t->ctrl_rsp_pa, 8); + rsp_pa = le64_to_cpu(__rsp_pa); rsp_size = crb_fixup_cmd_size(dev, &io_res, rsp_pa, ioread32(&priv->regs_t->ctrl_rsp_size)); @@ -531,6 +565,8 @@ out: crb_go_idle(dev, priv); + __crb_relinquish_locality(dev, priv, 0); + return ret; } @@ -588,10 +624,14 @@ static int crb_acpi_add(struct acpi_device *device) chip->acpi_dev_handle = device->handle; chip->flags = TPM_CHIP_FLAG_TPM2; - rc = crb_cmd_ready(dev, priv); + rc = __crb_request_locality(dev, priv, 0); if (rc) return rc; + rc = crb_cmd_ready(dev, priv); + if (rc) + goto out; + pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -601,12 +641,15 @@ static int crb_acpi_add(struct acpi_device *device) crb_go_idle(dev, priv); pm_runtime_put_noidle(dev); pm_runtime_disable(dev); - return rc; + goto out; } - pm_runtime_put(dev); + pm_runtime_put_sync(dev); - return 0; +out: + __crb_relinquish_locality(dev, priv, 0); + + return rc; } static int crb_acpi_remove(struct acpi_device *device) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index da074e3db19b..5a1f47b43947 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -143,11 +143,13 @@ static bool check_locality(struct tpm_chip *chip, int l) return false; } -static void release_locality(struct tpm_chip *chip, int l) +static int release_locality(struct tpm_chip *chip, int l) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); + + return 0; } static int request_locality(struct tpm_chip *chip, int l) |