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

Commit 4b3f1a15 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 706ffc8c ed807f6a
Loading
Loading
Loading
Loading
+126 −32
Original line number Diff line number Diff line
@@ -369,20 +369,40 @@ static int tpm_validate_command(struct tpm_chip *chip,
	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 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
	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 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
 *     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)
	 */
+21 −11
Original line number Diff line number Diff line
@@ -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
@@ -81,6 +83,9 @@ enum tpm_duration {
enum tpm2_const {
	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,
@@ -88,6 +93,8 @@ enum tpm2_const {
	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);
+21 −41
Original line number Diff line number Diff line
@@ -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,11 +1051,9 @@ 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);
	if (rc)
+78 −35
Original line number Diff line number Diff line
@@ -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,28 +155,15 @@ 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 */

	return 0;
	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;
	}

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;
	return 0;
}

/**
@@ -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,9 +200,9 @@ 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;

@@ -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 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,

	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)
+3 −1
Original line number Diff line number Diff line
@@ -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)
Loading