Commit 1436ab06 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull TPM updates from James Morris:
 "Here are the TPM updates from Jarkko for v4.14, which I've placed in
  their own branch (next-tpm). I ended up cherry-picking them as other
  changes had been made in Jarkko's branch after he sent me his original
  pull request.

  I plan on maintaining a separate branch for TPM (and other security
  subsystems) from now on.

  From Jarkko: 'Not much this time except a few fixes'"

* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  tpm: ibmvtpm: simplify crq initialization and document crq format
  tpm: replace msleep() with  usleep_range() in TPM 1.2/2.0 generic drivers
  Documentation: tpm: add powered-while-suspended binding documentation
  tpm: tpm_crb: constify acpi_device_id.
  tpm: vtpm: constify vio_device_id
parents cd4175b1 fb154e0e
...@@ -8,6 +8,12 @@ Required properties: ...@@ -8,6 +8,12 @@ Required properties:
the firmware event log the firmware event log
- linux,sml-size : size of the memory allocated for the firmware event log - linux,sml-size : size of the memory allocated for the firmware event log
Optional properties:
- powered-while-suspended: present when the TPM is left powered on between
suspend and resume (makes the suspend/resume
callbacks do nothing).
Example (for OpenPower Systems with Nuvoton TPM 2.0 on I2C) Example (for OpenPower Systems with Nuvoton TPM 2.0 on I2C)
---------------------------------------------------------- ----------------------------------------------------------
......
...@@ -455,7 +455,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, ...@@ -455,7 +455,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
goto out; goto out;
} }
msleep(TPM_TIMEOUT); /* CHECK */ tpm_msleep(TPM_TIMEOUT);
rmb(); rmb();
} while (time_before(jiffies, stop)); } while (time_before(jiffies, stop));
...@@ -970,7 +970,7 @@ int tpm_do_selftest(struct tpm_chip *chip) ...@@ -970,7 +970,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
dev_info( dev_info(
&chip->dev, HW_ERR &chip->dev, HW_ERR
"TPM command timed out during continue self test"); "TPM command timed out during continue self test");
msleep(delay_msec); tpm_msleep(delay_msec);
continue; continue;
} }
...@@ -985,7 +985,7 @@ int tpm_do_selftest(struct tpm_chip *chip) ...@@ -985,7 +985,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
} }
if (rc != TPM_WARN_DOING_SELFTEST) if (rc != TPM_WARN_DOING_SELFTEST)
return rc; return rc;
msleep(delay_msec); tpm_msleep(delay_msec);
} while (--loops > 0); } while (--loops > 0);
return rc; return rc;
...@@ -1085,7 +1085,7 @@ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, ...@@ -1085,7 +1085,7 @@ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
} }
} else { } else {
do { do {
msleep(TPM_TIMEOUT); tpm_msleep(TPM_TIMEOUT);
status = chip->ops->status(chip); status = chip->ops->status(chip);
if ((status & mask) == mask) if ((status & mask) == mask)
return 0; return 0;
...@@ -1150,7 +1150,7 @@ int tpm_pm_suspend(struct device *dev) ...@@ -1150,7 +1150,7 @@ int tpm_pm_suspend(struct device *dev)
*/ */
if (rc != TPM_WARN_RETRY) if (rc != TPM_WARN_RETRY)
break; break;
msleep(TPM_TIMEOUT_RETRY); tpm_msleep(TPM_TIMEOUT_RETRY);
} }
if (rc) if (rc)
......
...@@ -50,7 +50,8 @@ enum tpm_const { ...@@ -50,7 +50,8 @@ enum tpm_const {
enum tpm_timeout { enum tpm_timeout {
TPM_TIMEOUT = 5, /* msecs */ TPM_TIMEOUT = 5, /* msecs */
TPM_TIMEOUT_RETRY = 100 /* msecs */ TPM_TIMEOUT_RETRY = 100, /* msecs */
TPM_TIMEOUT_RANGE_US = 300 /* usecs */
}; };
/* TPM addresses */ /* TPM addresses */
...@@ -527,6 +528,12 @@ int tpm_pm_resume(struct device *dev); ...@@ -527,6 +528,12 @@ int tpm_pm_resume(struct device *dev);
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
wait_queue_head_t *queue, bool check_cancel); wait_queue_head_t *queue, bool check_cancel);
static inline void tpm_msleep(unsigned int delay_msec)
{
usleep_range(delay_msec * 1000,
(delay_msec * 1000) + TPM_TIMEOUT_RANGE_US);
};
struct tpm_chip *tpm_chip_find_get(int chip_num); struct tpm_chip *tpm_chip_find_get(int chip_num);
__must_check int tpm_try_get_ops(struct tpm_chip *chip); __must_check int tpm_try_get_ops(struct tpm_chip *chip);
void tpm_put_ops(struct tpm_chip *chip); void tpm_put_ops(struct tpm_chip *chip);
......
...@@ -899,7 +899,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip) ...@@ -899,7 +899,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
if (rc != TPM2_RC_TESTING) if (rc != TPM2_RC_TESTING)
break; break;
msleep(delay_msec); tpm_msleep(delay_msec);
} }
return rc; return rc;
......
...@@ -665,7 +665,7 @@ static const struct dev_pm_ops crb_pm = { ...@@ -665,7 +665,7 @@ static const struct dev_pm_ops crb_pm = {
SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL)
}; };
static struct acpi_device_id crb_device_ids[] = { static const struct acpi_device_id crb_device_ids[] = {
{"MSFT0101", 0}, {"MSFT0101", 0},
{"", 0}, {"", 0},
}; };
......
...@@ -32,26 +32,70 @@ ...@@ -32,26 +32,70 @@
static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm";
static struct vio_device_id tpm_ibmvtpm_device_table[] = { static const struct vio_device_id tpm_ibmvtpm_device_table[] = {
{ "IBM,vtpm", "IBM,vtpm"}, { "IBM,vtpm", "IBM,vtpm"},
{ "", "" } { "", "" }
}; };
MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
/** /**
*
* ibmvtpm_send_crq_word - Send a CRQ request
* @vdev: vio device struct
* @w1: pre-constructed first word of tpm crq (second word is reserved)
*
* Return:
* 0 - Success
* Non-zero - Failure
*/
static int ibmvtpm_send_crq_word(struct vio_dev *vdev, u64 w1)
{
return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, 0);
}
/**
*
* ibmvtpm_send_crq - Send a CRQ request * ibmvtpm_send_crq - Send a CRQ request
* *
* @vdev: vio device struct * @vdev: vio device struct
* @w1: first word * @valid: Valid field
* @w2: second word * @msg: Type field
* @len: Length field
* @data: Data field
*
* The ibmvtpm crq is defined as follows:
*
* Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
* -----------------------------------------------------------------------
* Word0 | Valid | Type | Length | Data
* -----------------------------------------------------------------------
* Word1 | Reserved
* -----------------------------------------------------------------------
*
* Which matches the following structure (on bigendian host):
*
* struct ibmvtpm_crq {
* u8 valid;
* u8 msg;
* __be16 len;
* __be32 data;
* __be64 reserved;
* } __attribute__((packed, aligned(8)));
*
* However, the value is passed in a register so just compute the numeric value
* to load into the register avoiding byteswap altogether. Endian only affects
* memory loads and stores - registers are internally represented the same.
* *
* Return: * Return:
* 0 -Sucess * 0 (H_SUCCESS) - Success
* Non-zero - Failure * Non-zero - Failure
*/ */
static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2) static int ibmvtpm_send_crq(struct vio_dev *vdev,
u8 valid, u8 msg, u16 len, u32 data)
{ {
return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2); u64 w1 = ((u64)valid << 56) | ((u64)msg << 48) | ((u64)len << 32) |
(u64)data;
return ibmvtpm_send_crq_word(vdev, w1);
} }
/** /**
...@@ -109,8 +153,6 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -109,8 +153,6 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
{ {
struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
struct ibmvtpm_crq crq;
__be64 *word = (__be64 *)&crq;
int rc, sig; int rc, sig;
if (!ibmvtpm->rtce_buf) { if (!ibmvtpm->rtce_buf) {
...@@ -137,10 +179,6 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -137,10 +179,6 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
spin_lock(&ibmvtpm->rtce_lock); spin_lock(&ibmvtpm->rtce_lock);
ibmvtpm->res_len = 0; ibmvtpm->res_len = 0;
memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_TPM_COMMAND;
crq.len = cpu_to_be16(count);
crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
/* /*
* set the processing flag before the Hcall, since we may get the * set the processing flag before the Hcall, since we may get the
...@@ -148,8 +186,9 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -148,8 +186,9 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
*/ */
ibmvtpm->tpm_processing_cmd = true; ibmvtpm->tpm_processing_cmd = true;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), rc = ibmvtpm_send_crq(ibmvtpm->vdev,
be64_to_cpu(word[1])); IBMVTPM_VALID_CMD, VTPM_TPM_COMMAND,
count, ibmvtpm->rtce_dma_handle);
if (rc != H_SUCCESS) { if (rc != H_SUCCESS) {
dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
rc = 0; rc = 0;
...@@ -182,15 +221,10 @@ static u8 tpm_ibmvtpm_status(struct tpm_chip *chip) ...@@ -182,15 +221,10 @@ static u8 tpm_ibmvtpm_status(struct tpm_chip *chip)
*/ */
static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
{ {
struct ibmvtpm_crq crq;
u64 *buf = (u64 *) &crq;
int rc; int rc;
crq.valid = (u8)IBMVTPM_VALID_CMD; rc = ibmvtpm_send_crq(ibmvtpm->vdev,
crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE; IBMVTPM_VALID_CMD, VTPM_GET_RTCE_BUFFER_SIZE, 0, 0);
rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
cpu_to_be64(buf[1]));
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc); "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
...@@ -210,15 +244,10 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) ...@@ -210,15 +244,10 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
*/ */
static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
{ {
struct ibmvtpm_crq crq;
u64 *buf = (u64 *) &crq;
int rc; int rc;
crq.valid = (u8)IBMVTPM_VALID_CMD; rc = ibmvtpm_send_crq(ibmvtpm->vdev,
crq.msg = (u8)VTPM_GET_VERSION; IBMVTPM_VALID_CMD, VTPM_GET_VERSION, 0, 0);
rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
cpu_to_be64(buf[1]));
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"ibmvtpm_crq_get_version failed rc=%d\n", rc); "ibmvtpm_crq_get_version failed rc=%d\n", rc);
...@@ -238,7 +267,7 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) ...@@ -238,7 +267,7 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
{ {
int rc; int rc;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0); rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_COMP_CMD);
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"ibmvtpm_crq_send_init_complete failed rc=%d\n", rc); "ibmvtpm_crq_send_init_complete failed rc=%d\n", rc);
...@@ -258,7 +287,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) ...@@ -258,7 +287,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
{ {
int rc; int rc;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0); rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_CMD);
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"ibmvtpm_crq_send_init failed rc=%d\n", rc); "ibmvtpm_crq_send_init failed rc=%d\n", rc);
...@@ -340,15 +369,10 @@ static int tpm_ibmvtpm_suspend(struct device *dev) ...@@ -340,15 +369,10 @@ static int tpm_ibmvtpm_suspend(struct device *dev)
{ {
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
struct ibmvtpm_crq crq;
u64 *buf = (u64 *) &crq;
int rc = 0; int rc = 0;
crq.valid = (u8)IBMVTPM_VALID_CMD; rc = ibmvtpm_send_crq(ibmvtpm->vdev,
crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND; IBMVTPM_VALID_CMD, VTPM_PREPARE_TO_SUSPEND, 0, 0);
rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
cpu_to_be64(buf[1]));
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"tpm_ibmvtpm_suspend failed rc=%d\n", rc); "tpm_ibmvtpm_suspend failed rc=%d\n", rc);
......
...@@ -191,7 +191,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit) ...@@ -191,7 +191,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
/* check the status-register if wait_for_bit is set */ /* check the status-register if wait_for_bit is set */
if (status & 1 << wait_for_bit) if (status & 1 << wait_for_bit)
break; break;
msleep(TPM_MSLEEP_TIME); tpm_msleep(TPM_MSLEEP_TIME);
} }
if (i == TPM_MAX_TRIES) { /* timeout occurs */ if (i == TPM_MAX_TRIES) { /* timeout occurs */
if (wait_for_bit == STAT_XFE) if (wait_for_bit == STAT_XFE)
...@@ -226,7 +226,7 @@ static void tpm_wtx(struct tpm_chip *chip) ...@@ -226,7 +226,7 @@ static void tpm_wtx(struct tpm_chip *chip)
wait_and_send(chip, TPM_CTRL_WTX); wait_and_send(chip, TPM_CTRL_WTX);
wait_and_send(chip, 0x00); wait_and_send(chip, 0x00);
wait_and_send(chip, 0x00); wait_and_send(chip, 0x00);
msleep(TPM_WTX_MSLEEP_TIME); tpm_msleep(TPM_WTX_MSLEEP_TIME);
} }
static void tpm_wtx_abort(struct tpm_chip *chip) static void tpm_wtx_abort(struct tpm_chip *chip)
...@@ -237,7 +237,7 @@ static void tpm_wtx_abort(struct tpm_chip *chip) ...@@ -237,7 +237,7 @@ static void tpm_wtx_abort(struct tpm_chip *chip)
wait_and_send(chip, 0x00); wait_and_send(chip, 0x00);
wait_and_send(chip, 0x00); wait_and_send(chip, 0x00);
number_of_wtx = 0; number_of_wtx = 0;
msleep(TPM_WTX_MSLEEP_TIME); tpm_msleep(TPM_WTX_MSLEEP_TIME);
} }
static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count) static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
......
...@@ -51,7 +51,7 @@ static int wait_startup(struct tpm_chip *chip, int l) ...@@ -51,7 +51,7 @@ static int wait_startup(struct tpm_chip *chip, int l)
if (access & TPM_ACCESS_VALID) if (access & TPM_ACCESS_VALID)
return 0; return 0;
msleep(TPM_TIMEOUT); tpm_msleep(TPM_TIMEOUT);
} while (time_before(jiffies, stop)); } while (time_before(jiffies, stop));
return -1; return -1;
} }
...@@ -117,7 +117,7 @@ static int request_locality(struct tpm_chip *chip, int l) ...@@ -117,7 +117,7 @@ static int request_locality(struct tpm_chip *chip, int l)
do { do {
if (check_locality(chip, l)) if (check_locality(chip, l))
return l; return l;
msleep(TPM_TIMEOUT); tpm_msleep(TPM_TIMEOUT);
} while (time_before(jiffies, stop)); } while (time_before(jiffies, stop));
} }
return -1; return -1;
...@@ -164,7 +164,7 @@ static int get_burstcount(struct tpm_chip *chip) ...@@ -164,7 +164,7 @@ static int get_burstcount(struct tpm_chip *chip)
burstcnt = (value >> 8) & 0xFFFF; burstcnt = (value >> 8) & 0xFFFF;
if (burstcnt) if (burstcnt)
return burstcnt; return burstcnt;
msleep(TPM_TIMEOUT); tpm_msleep(TPM_TIMEOUT);
} while (time_before(jiffies, stop)); } while (time_before(jiffies, stop));
return -EBUSY; return -EBUSY;
} }
...@@ -396,7 +396,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -396,7 +396,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
priv->irq = irq; priv->irq = irq;
chip->flags |= TPM_CHIP_FLAG_IRQ; chip->flags |= TPM_CHIP_FLAG_IRQ;
if (!priv->irq_tested) if (!priv->irq_tested)
msleep(1); tpm_msleep(1);
if (!priv->irq_tested) if (!priv->irq_tested)
disable_interrupts(chip); disable_interrupts(chip);
priv->irq_tested = true; priv->irq_tested = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment