summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/hw_random/mtk-rng.c42
-rw-r--r--drivers/char/hw_random/omap3-rom-rng.c11
-rw-r--r--drivers/char/hw_random/timeriomem-rng.c7
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c333
-rw-r--r--drivers/char/pcmcia/synclink_cs.c2
-rw-r--r--drivers/char/tpm/st33zp24/i2c.c3
-rw-r--r--drivers/char/tpm/st33zp24/spi.c3
-rw-r--r--drivers/char/tpm/tpm-chip.c34
-rw-r--r--drivers/char/tpm/tpm-interface.c182
-rw-r--r--drivers/char/tpm/tpm-sysfs.c12
-rw-r--r--drivers/char/tpm/tpm.h33
-rw-r--r--drivers/char/tpm/tpm2-cmd.c123
-rw-r--r--drivers/char/tpm/tpm_atmel.c12
-rw-r--r--drivers/char/tpm/tpm_crb.c9
-rw-r--r--drivers/char/tpm/tpm_i2c_infineon.c76
-rw-r--r--drivers/char/tpm/tpm_infineon.c8
-rw-r--r--drivers/char/tpm/tpm_of.c3
-rw-r--r--drivers/char/tpm/tpm_tis.c288
-rw-r--r--drivers/char/tpm/tpm_vtpm_proxy.c69
-rw-r--r--drivers/char/tpm/tpmrm-dev.c2
21 files changed, 716 insertions, 538 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 2af70014ee5a..ccd239ab879f 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -17,6 +17,8 @@ config DEVMEM
config DEVKMEM
bool "/dev/kmem virtual device support"
+ # On arm64, VMALLOC_START < PAGE_OFFSET, which confuses kmem read/write
+ depends on !ARM64
help
Say Y here if you want to support the /dev/kmem device. The
/dev/kmem device is rarely used, but can be used for certain
diff --git a/drivers/char/hw_random/mtk-rng.c b/drivers/char/hw_random/mtk-rng.c
index df8eb54fd5a3..8da7bcf54105 100644
--- a/drivers/char/hw_random/mtk-rng.c
+++ b/drivers/char/hw_random/mtk-rng.c
@@ -25,6 +25,10 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* Runtime PM autosuspend timeout: */
+#define RNG_AUTOSUSPEND_TIMEOUT 100
#define USEC_POLL 2
#define TIMEOUT_POLL 20
@@ -90,6 +94,8 @@ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
struct mtk_rng *priv = to_mtk_rng(rng);
int retval = 0;
+ pm_runtime_get_sync((struct device *)priv->rng.priv);
+
while (max >= sizeof(u32)) {
if (!mtk_rng_wait_ready(rng, wait))
break;
@@ -100,6 +106,9 @@ static int mtk_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
max -= sizeof(u32);
}
+ pm_runtime_mark_last_busy((struct device *)priv->rng.priv);
+ pm_runtime_put_sync_autosuspend((struct device *)priv->rng.priv);
+
return retval || !wait ? retval : -EIO;
}
@@ -120,9 +129,12 @@ static int mtk_rng_probe(struct platform_device *pdev)
return -ENOMEM;
priv->rng.name = pdev->name;
+#ifndef CONFIG_PM
priv->rng.init = mtk_rng_init;
priv->rng.cleanup = mtk_rng_cleanup;
+#endif
priv->rng.read = mtk_rng_read;
+ priv->rng.priv = (unsigned long)&pdev->dev;
priv->clk = devm_clk_get(&pdev->dev, "rng");
if (IS_ERR(priv->clk)) {
@@ -142,11 +154,40 @@ static int mtk_rng_probe(struct platform_device *pdev)
return ret;
}
+ dev_set_drvdata(&pdev->dev, priv);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, RNG_AUTOSUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
dev_info(&pdev->dev, "registered RNG driver\n");
return 0;
}
+#ifdef CONFIG_PM
+static int mtk_rng_runtime_suspend(struct device *dev)
+{
+ struct mtk_rng *priv = dev_get_drvdata(dev);
+
+ mtk_rng_cleanup(&priv->rng);
+
+ return 0;
+}
+
+static int mtk_rng_runtime_resume(struct device *dev)
+{
+ struct mtk_rng *priv = dev_get_drvdata(dev);
+
+ return mtk_rng_init(&priv->rng);
+}
+
+static UNIVERSAL_DEV_PM_OPS(mtk_rng_pm_ops, mtk_rng_runtime_suspend,
+ mtk_rng_runtime_resume, NULL);
+#define MTK_RNG_PM_OPS (&mtk_rng_pm_ops)
+#else /* CONFIG_PM */
+#define MTK_RNG_PM_OPS NULL
+#endif /* CONFIG_PM */
+
static const struct of_device_id mtk_rng_match[] = {
{ .compatible = "mediatek,mt7623-rng" },
{},
@@ -157,6 +198,7 @@ static struct platform_driver mtk_rng_driver = {
.probe = mtk_rng_probe,
.driver = {
.name = MTK_RNG_DEV,
+ .pm = MTK_RNG_PM_OPS,
.of_match_table = mtk_rng_match,
},
};
diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c
index 37a58d78aab3..38b719017186 100644
--- a/drivers/char/hw_random/omap3-rom-rng.c
+++ b/drivers/char/hw_random/omap3-rom-rng.c
@@ -53,7 +53,10 @@ static int omap3_rom_rng_get_random(void *buf, unsigned int count)
cancel_delayed_work_sync(&idle_work);
if (rng_idle) {
- clk_prepare_enable(rng_clk);
+ r = clk_prepare_enable(rng_clk);
+ if (r)
+ return r;
+
r = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT);
if (r != 0) {
clk_disable_unprepare(rng_clk);
@@ -88,6 +91,8 @@ static struct hwrng omap3_rom_rng_ops = {
static int omap3_rom_rng_probe(struct platform_device *pdev)
{
+ int ret = 0;
+
pr_info("initializing\n");
omap3_rom_rng_call = pdev->dev.platform_data;
@@ -104,7 +109,9 @@ static int omap3_rom_rng_probe(struct platform_device *pdev)
}
/* Leave the RNG in reset state. */
- clk_prepare_enable(rng_clk);
+ ret = clk_prepare_enable(rng_clk);
+ if (ret)
+ return ret;
omap3_rom_rng_idle(0);
return hwrng_register(&omap3_rom_rng_ops);
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
index a0faa5f05deb..03ff5483d865 100644
--- a/drivers/char/hw_random/timeriomem-rng.c
+++ b/drivers/char/hw_random/timeriomem-rng.c
@@ -151,8 +151,15 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "missing period\n");
return -EINVAL;
}
+
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "quality", &i))
+ priv->rng_ops.quality = i;
+ else
+ priv->rng_ops.quality = 0;
} else {
period = pdata->period;
+ priv->rng_ops.quality = pdata->quality;
}
priv->period = ns_to_ktime(period * NSEC_PER_USEC);
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index f45119c5337d..2ffca4232686 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -231,6 +231,102 @@ static int handle_send_req(ipmi_user_t user,
return rv;
}
+static int handle_recv(struct ipmi_file_private *priv,
+ bool trunc, struct ipmi_recv *rsp,
+ int (*copyout)(struct ipmi_recv *, void __user *),
+ void __user *to)
+{
+ int addr_len;
+ struct list_head *entry;
+ struct ipmi_recv_msg *msg;
+ unsigned long flags;
+ int rv = 0;
+
+ /* We claim a mutex because we don't want two
+ users getting something from the queue at a time.
+ Since we have to release the spinlock before we can
+ copy the data to the user, it's possible another
+ user will grab something from the queue, too. Then
+ the messages might get out of order if something
+ fails and the message gets put back onto the
+ queue. This mutex prevents that problem. */
+ mutex_lock(&priv->recv_mutex);
+
+ /* Grab the message off the list. */
+ spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+ if (list_empty(&(priv->recv_msgs))) {
+ spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+ rv = -EAGAIN;
+ goto recv_err;
+ }
+ entry = priv->recv_msgs.next;
+ msg = list_entry(entry, struct ipmi_recv_msg, link);
+ list_del(entry);
+ spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+
+ addr_len = ipmi_addr_length(msg->addr.addr_type);
+ if (rsp->addr_len < addr_len)
+ {
+ rv = -EINVAL;
+ goto recv_putback_on_err;
+ }
+
+ if (copy_to_user(rsp->addr, &(msg->addr), addr_len)) {
+ rv = -EFAULT;
+ goto recv_putback_on_err;
+ }
+ rsp->addr_len = addr_len;
+
+ rsp->recv_type = msg->recv_type;
+ rsp->msgid = msg->msgid;
+ rsp->msg.netfn = msg->msg.netfn;
+ rsp->msg.cmd = msg->msg.cmd;
+
+ if (msg->msg.data_len > 0) {
+ if (rsp->msg.data_len < msg->msg.data_len) {
+ rv = -EMSGSIZE;
+ if (trunc)
+ msg->msg.data_len = rsp->msg.data_len;
+ else
+ goto recv_putback_on_err;
+ }
+
+ if (copy_to_user(rsp->msg.data,
+ msg->msg.data,
+ msg->msg.data_len))
+ {
+ rv = -EFAULT;
+ goto recv_putback_on_err;
+ }
+ rsp->msg.data_len = msg->msg.data_len;
+ } else {
+ rsp->msg.data_len = 0;
+ }
+
+ rv = copyout(rsp, to);
+ if (rv)
+ goto recv_putback_on_err;
+
+ mutex_unlock(&priv->recv_mutex);
+ ipmi_free_recv_msg(msg);
+ return 0;
+
+recv_putback_on_err:
+ /* If we got an error, put the message back onto
+ the head of the queue. */
+ spin_lock_irqsave(&(priv->recv_msg_lock), flags);
+ list_add(entry, &(priv->recv_msgs));
+ spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
+recv_err:
+ mutex_unlock(&priv->recv_mutex);
+ return rv;
+}
+
+static int copyout_recv(struct ipmi_recv *rsp, void __user *to)
+{
+ return copy_to_user(to, rsp, sizeof(struct ipmi_recv)) ? -EFAULT : 0;
+}
+
static int ipmi_ioctl(struct file *file,
unsigned int cmd,
unsigned long data)
@@ -277,100 +373,12 @@ static int ipmi_ioctl(struct file *file,
case IPMICTL_RECEIVE_MSG_TRUNC:
{
struct ipmi_recv rsp;
- int addr_len;
- struct list_head *entry;
- struct ipmi_recv_msg *msg;
- unsigned long flags;
-
-
- rv = 0;
- if (copy_from_user(&rsp, arg, sizeof(rsp))) {
- rv = -EFAULT;
- break;
- }
-
- /* We claim a mutex because we don't want two
- users getting something from the queue at a time.
- Since we have to release the spinlock before we can
- copy the data to the user, it's possible another
- user will grab something from the queue, too. Then
- the messages might get out of order if something
- fails and the message gets put back onto the
- queue. This mutex prevents that problem. */
- mutex_lock(&priv->recv_mutex);
-
- /* Grab the message off the list. */
- spin_lock_irqsave(&(priv->recv_msg_lock), flags);
- if (list_empty(&(priv->recv_msgs))) {
- spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
- rv = -EAGAIN;
- goto recv_err;
- }
- entry = priv->recv_msgs.next;
- msg = list_entry(entry, struct ipmi_recv_msg, link);
- list_del(entry);
- spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
-
- addr_len = ipmi_addr_length(msg->addr.addr_type);
- if (rsp.addr_len < addr_len)
- {
- rv = -EINVAL;
- goto recv_putback_on_err;
- }
- if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
+ if (copy_from_user(&rsp, arg, sizeof(rsp)))
rv = -EFAULT;
- goto recv_putback_on_err;
- }
- rsp.addr_len = addr_len;
-
- rsp.recv_type = msg->recv_type;
- rsp.msgid = msg->msgid;
- rsp.msg.netfn = msg->msg.netfn;
- rsp.msg.cmd = msg->msg.cmd;
-
- if (msg->msg.data_len > 0) {
- if (rsp.msg.data_len < msg->msg.data_len) {
- rv = -EMSGSIZE;
- if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
- msg->msg.data_len = rsp.msg.data_len;
- } else {
- goto recv_putback_on_err;
- }
- }
-
- if (copy_to_user(rsp.msg.data,
- msg->msg.data,
- msg->msg.data_len))
- {
- rv = -EFAULT;
- goto recv_putback_on_err;
- }
- rsp.msg.data_len = msg->msg.data_len;
- } else {
- rsp.msg.data_len = 0;
- }
-
- if (copy_to_user(arg, &rsp, sizeof(rsp))) {
- rv = -EFAULT;
- goto recv_putback_on_err;
- }
-
- mutex_unlock(&priv->recv_mutex);
- ipmi_free_recv_msg(msg);
- break;
-
- recv_putback_on_err:
- /* If we got an error, put the message back onto
- the head of the queue. */
- spin_lock_irqsave(&(priv->recv_msg_lock), flags);
- list_add(entry, &(priv->recv_msgs));
- spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
- mutex_unlock(&priv->recv_mutex);
- break;
-
- recv_err:
- mutex_unlock(&priv->recv_mutex);
+ else
+ rv = handle_recv(priv, cmd == IPMICTL_RECEIVE_MSG_TRUNC,
+ &rsp, copyout_recv, arg);
break;
}
@@ -696,85 +704,56 @@ struct compat_ipmi_req_settime {
/*
* Define some helper functions for copying IPMI data
*/
-static long get_compat_ipmi_msg(struct ipmi_msg *p64,
- struct compat_ipmi_msg __user *p32)
-{
- compat_uptr_t tmp;
-
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- __get_user(p64->netfn, &p32->netfn) ||
- __get_user(p64->cmd, &p32->cmd) ||
- __get_user(p64->data_len, &p32->data_len) ||
- __get_user(tmp, &p32->data))
- return -EFAULT;
- p64->data = compat_ptr(tmp);
- return 0;
-}
-
-static long put_compat_ipmi_msg(struct ipmi_msg *p64,
- struct compat_ipmi_msg __user *p32)
+static void get_compat_ipmi_msg(struct ipmi_msg *p64,
+ struct compat_ipmi_msg *p32)
{
- if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
- __put_user(p64->netfn, &p32->netfn) ||
- __put_user(p64->cmd, &p32->cmd) ||
- __put_user(p64->data_len, &p32->data_len))
- return -EFAULT;
- return 0;
+ p64->netfn = p32->netfn;
+ p64->cmd = p32->cmd;
+ p64->data_len = p32->data_len;
+ p64->data = compat_ptr(p32->data);
}
-static long get_compat_ipmi_req(struct ipmi_req *p64,
- struct compat_ipmi_req __user *p32)
+static void get_compat_ipmi_req(struct ipmi_req *p64,
+ struct compat_ipmi_req *p32)
{
-
- compat_uptr_t tmp;
-
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- __get_user(tmp, &p32->addr) ||
- __get_user(p64->addr_len, &p32->addr_len) ||
- __get_user(p64->msgid, &p32->msgid) ||
- get_compat_ipmi_msg(&p64->msg, &p32->msg))
- return -EFAULT;
- p64->addr = compat_ptr(tmp);
- return 0;
+ p64->addr = compat_ptr(p32->addr);
+ p64->addr_len = p32->addr_len;
+ p64->msgid = p32->msgid;
+ get_compat_ipmi_msg(&p64->msg, &p32->msg);
}
-static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
- struct compat_ipmi_req_settime __user *p32)
+static void get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
+ struct compat_ipmi_req_settime *p32)
{
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- get_compat_ipmi_req(&p64->req, &p32->req) ||
- __get_user(p64->retries, &p32->retries) ||
- __get_user(p64->retry_time_ms, &p32->retry_time_ms))
- return -EFAULT;
- return 0;
+ get_compat_ipmi_req(&p64->req, &p32->req);
+ p64->retries = p32->retries;
+ p64->retry_time_ms = p32->retry_time_ms;
}
-static long get_compat_ipmi_recv(struct ipmi_recv *p64,
- struct compat_ipmi_recv __user *p32)
+static void get_compat_ipmi_recv(struct ipmi_recv *p64,
+ struct compat_ipmi_recv *p32)
{
- compat_uptr_t tmp;
-
- if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
- __get_user(p64->recv_type, &p32->recv_type) ||
- __get_user(tmp, &p32->addr) ||
- __get_user(p64->addr_len, &p32->addr_len) ||
- __get_user(p64->msgid, &p32->msgid) ||
- get_compat_ipmi_msg(&p64->msg, &p32->msg))
- return -EFAULT;
- p64->addr = compat_ptr(tmp);
- return 0;
+ memset(p64, 0, sizeof(struct ipmi_recv));
+ p64->recv_type = p32->recv_type;
+ p64->addr = compat_ptr(p32->addr);
+ p64->addr_len = p32->addr_len;
+ p64->msgid = p32->msgid;
+ get_compat_ipmi_msg(&p64->msg, &p32->msg);
}
-static long put_compat_ipmi_recv(struct ipmi_recv *p64,
- struct compat_ipmi_recv __user *p32)
+static int copyout_recv32(struct ipmi_recv *p64, void __user *to)
{
- if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
- __put_user(p64->recv_type, &p32->recv_type) ||
- __put_user(p64->addr_len, &p32->addr_len) ||
- __put_user(p64->msgid, &p32->msgid) ||
- put_compat_ipmi_msg(&p64->msg, &p32->msg))
- return -EFAULT;
- return 0;
+ struct compat_ipmi_recv v32;
+ memset(&v32, 0, sizeof(struct compat_ipmi_recv));
+ v32.recv_type = p64->recv_type;
+ v32.addr = ptr_to_compat(p64->addr);
+ v32.addr_len = p64->addr_len;
+ v32.msgid = p64->msgid;
+ v32.msg.netfn = p64->msg.netfn;
+ v32.msg.cmd = p64->msg.cmd;
+ v32.msg.data_len = p64->msg.data_len;
+ v32.msg.data = ptr_to_compat(p64->msg.data);
+ return copy_to_user(to, &v32, sizeof(v32)) ? -EFAULT : 0;
}
/*
@@ -783,17 +762,19 @@ static long put_compat_ipmi_recv(struct ipmi_recv *p64,
static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
- int rc;
struct ipmi_file_private *priv = filep->private_data;
switch(cmd) {
case COMPAT_IPMICTL_SEND_COMMAND:
{
struct ipmi_req rp;
+ struct compat_ipmi_req r32;
- if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
+ if (copy_from_user(&r32, compat_ptr(arg), sizeof(r32)))
return -EFAULT;
+ get_compat_ipmi_req(&rp, &r32);
+
return handle_send_req(priv->user, &rp,
priv->default_retries,
priv->default_retry_time_ms);
@@ -801,42 +782,30 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
{
struct ipmi_req_settime sp;
+ struct compat_ipmi_req_settime sp32;
- if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
+ if (copy_from_user(&sp32, compat_ptr(arg), sizeof(sp32)))
return -EFAULT;
+ get_compat_ipmi_req_settime(&sp, &sp32);
+
return handle_send_req(priv->user, &sp.req,
sp.retries, sp.retry_time_ms);
}
case COMPAT_IPMICTL_RECEIVE_MSG:
case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
{
- struct ipmi_recv __user *precv64;
struct ipmi_recv recv64;
+ struct compat_ipmi_recv recv32;
- memset(&recv64, 0, sizeof(recv64));
- if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+ if (copy_from_user(&recv32, compat_ptr(arg), sizeof(recv32)))
return -EFAULT;
- precv64 = compat_alloc_user_space(sizeof(recv64));
- if (copy_to_user(precv64, &recv64, sizeof(recv64)))
- return -EFAULT;
-
- rc = ipmi_ioctl(filep,
- ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
- ? IPMICTL_RECEIVE_MSG
- : IPMICTL_RECEIVE_MSG_TRUNC),
- (unsigned long) precv64);
- if (rc != 0)
- return rc;
-
- if (copy_from_user(&recv64, precv64, sizeof(recv64)))
- return -EFAULT;
-
- if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
- return -EFAULT;
+ get_compat_ipmi_recv(&recv64, &recv32);
- return rc;
+ return handle_recv(priv,
+ cmd == COMPAT_IPMICTL_RECEIVE_MSG_TRUNC,
+ &recv64, copyout_recv32, compat_ptr(arg));
}
default:
return ipmi_ioctl(filep, cmd, arg);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index d136db1a10f0..62be953e5fb0 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -4235,7 +4235,7 @@ static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size)
return;
}
- memcpy(skb_put(skb, size), buf, size);
+ skb_put_data(skb, buf, size);
skb->protocol = hdlc_type_trans(skb, dev);
diff --git a/drivers/char/tpm/st33zp24/i2c.c b/drivers/char/tpm/st33zp24/i2c.c
index 1b10e38f214e..be5d1abd3e8e 100644
--- a/drivers/char/tpm/st33zp24/i2c.c
+++ b/drivers/char/tpm/st33zp24/i2c.c
@@ -127,7 +127,7 @@ static int st33zp24_i2c_acpi_request_resources(struct i2c_client *client)
struct device *dev = &client->dev;
int ret;
- ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_st33zp24_gpios);
+ ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st33zp24_gpios);
if (ret)
return ret;
@@ -285,7 +285,6 @@ static int st33zp24_i2c_remove(struct i2c_client *client)
if (ret)
return ret;
- acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev));
return 0;
}
diff --git a/drivers/char/tpm/st33zp24/spi.c b/drivers/char/tpm/st33zp24/spi.c
index c69d15198f84..0fc4f20b5f83 100644
--- a/drivers/char/tpm/st33zp24/spi.c
+++ b/drivers/char/tpm/st33zp24/spi.c
@@ -246,7 +246,7 @@ static int st33zp24_spi_acpi_request_resources(struct spi_device *spi_dev)
struct device *dev = &spi_dev->dev;
int ret;
- ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), acpi_st33zp24_gpios);
+ ret = devm_acpi_dev_add_driver_gpios(dev, acpi_st33zp24_gpios);
if (ret)
return ret;
@@ -402,7 +402,6 @@ static int st33zp24_spi_remove(struct spi_device *dev)
if (ret)
return ret;
- acpi_dev_remove_driver_gpios(ACPI_COMPANION(&dev->dev));
return 0;
}
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 322b8a51ffc6..67ec9d3d04f5 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -143,6 +143,39 @@ static void tpm_devs_release(struct device *dev)
}
/**
+ * tpm_class_shutdown() - prepare the TPM device for loss of power.
+ * @dev: device to which the chip is associated.
+ *
+ * Issues a TPM2_Shutdown command prior to loss of power, as required by the
+ * TPM 2.0 spec.
+ * Then, calls bus- and device- specific shutdown code.
+ *
+ * XXX: This codepath relies on the fact that sysfs is not enabled for
+ * TPM2: sysfs uses an implicit lock on chip->ops, so this could race if TPM2
+ * has sysfs support enabled before TPM sysfs's implicit locking is fixed.
+ */
+static int tpm_class_shutdown(struct device *dev)
+{
+ struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ down_write(&chip->ops_sem);
+ tpm2_shutdown(chip, TPM2_SU_CLEAR);
+ chip->ops = NULL;
+ up_write(&chip->ops_sem);
+ }
+ /* Allow bus- and device-specific code to run. Note: since chip->ops
+ * is NULL, more-specific shutdown code will not be able to issue TPM
+ * commands.
+ */
+ if (dev->bus && dev->bus->shutdown)
+ dev->bus->shutdown(dev);
+ else if (dev->driver && dev->driver->shutdown)
+ dev->driver->shutdown(dev);
+ return 0;
+}
+
+/**
* tpm_chip_alloc() - allocate a new struct tpm_chip instance
* @pdev: device to which the chip is associated
* At this point pdev mst be initialized, but does not have to
@@ -181,6 +214,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
device_initialize(&chip->devs);
chip->dev.class = tpm_class;
+ chip->dev.class->shutdown = tpm_class_shutdown;
chip->dev.release = tpm_dev_release;
chip->dev.parent = pdev;
chip->dev.groups = chip->groups;
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 158c1db83f05..fe597e6c55c4 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -416,7 +416,8 @@ 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 (need_locality && chip->ops->request_locality) {
+ if (!(flags & TPM_TRANSMIT_RAW) &&
+ need_locality && chip->ops->request_locality) {
rc = chip->ops->request_locality(chip, 0);
if (rc < 0)
goto out_no_locality;
@@ -429,8 +430,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
rc = chip->ops->send(chip, (u8 *) buf, count);
if (rc < 0) {
- dev_err(&chip->dev,
- "tpm_transmit: tpm_send: error %d\n", rc);
+ if (rc != -EPIPE)
+ dev_err(&chip->dev,
+ "%s: tpm_send: error %d\n", __func__, rc);
goto out;
}
@@ -536,72 +538,95 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
return 0;
}
+EXPORT_SYMBOL_GPL(tpm_transmit_cmd);
+
+#define TPM_ORD_STARTUP 153
+#define TPM_ST_CLEAR 1
+
+/**
+ * tpm_startup - turn on the TPM
+ * @chip: TPM chip to use
+ *
+ * Normally the firmware should start the TPM. This function is provided as a
+ * workaround if this does not happen. A legal case for this could be for
+ * example when a TPM emulator is used.
+ *
+ * Return: same as tpm_transmit_cmd()
+ */
+int tpm_startup(struct tpm_chip *chip)
+{
+ struct tpm_buf buf;
+ int rc;
+
+ dev_info(&chip->dev, "starting up the TPM manually\n");
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
+ if (rc < 0)
+ return rc;
+
+ tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
+ } else {
+ rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
+ if (rc < 0)
+ return rc;
+
+ tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
+ }
+
+ rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
+ "attempting to start the TPM");
+
+ tpm_buf_destroy(&buf);
+ return rc;
+}
#define TPM_DIGEST_SIZE 20
#define TPM_RET_CODE_IDX 6
#define TPM_INTERNAL_RESULT_SIZE 200
-#define TPM_ORD_GET_CAP cpu_to_be32(101)
-#define TPM_ORD_GET_RANDOM cpu_to_be32(70)
+#define TPM_ORD_GET_CAP 101
+#define TPM_ORD_GET_RANDOM 70
static const struct tpm_input_header tpm_getcap_header = {
- .tag = TPM_TAG_RQU_COMMAND,
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(22),
- .ordinal = TPM_ORD_GET_CAP
+ .ordinal = cpu_to_be32(TPM_ORD_GET_CAP)
};
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length)
{
- struct tpm_cmd_t tpm_cmd;
+ struct tpm_buf buf;
int rc;
- tpm_cmd.header.in = tpm_getcap_header;
+ rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
+ if (rc)
+ return rc;
+
if (subcap_id == TPM_CAP_VERSION_1_1 ||
subcap_id == TPM_CAP_VERSION_1_2) {
- tpm_cmd.params.getcap_in.cap = cpu_to_be32(subcap_id);
- /*subcap field not necessary */
- tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0);
- tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32));
+ tpm_buf_append_u32(&buf, subcap_id);
+ tpm_buf_append_u32(&buf, 0);
} else {
if (subcap_id == TPM_CAP_FLAG_PERM ||
subcap_id == TPM_CAP_FLAG_VOL)
- tpm_cmd.params.getcap_in.cap =
- cpu_to_be32(TPM_CAP_FLAG);
+ tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
else
- tpm_cmd.params.getcap_in.cap =
- cpu_to_be32(TPM_CAP_PROP);
- tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
- tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id);
+ tpm_buf_append_u32(&buf, TPM_CAP_PROP);
+
+ tpm_buf_append_u32(&buf, 4);
+ tpm_buf_append_u32(&buf, subcap_id);
}
- rc = tpm_transmit_cmd(chip, NULL, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+ rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
min_cap_length, 0, desc);
if (!rc)
- *cap = tpm_cmd.params.getcap_out.cap;
+ *cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
+
+ tpm_buf_destroy(&buf);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_getcap);
-#define TPM_ORD_STARTUP cpu_to_be32(153)
-#define TPM_ST_CLEAR cpu_to_be16(1)
-#define TPM_ST_STATE cpu_to_be16(2)
-#define TPM_ST_DEACTIVATED cpu_to_be16(3)
-static const struct tpm_input_header tpm_startup_header = {
- .tag = TPM_TAG_RQU_COMMAND,
- .length = cpu_to_be32(12),
- .ordinal = TPM_ORD_STARTUP
-};
-
-static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
-{
- struct tpm_cmd_t start_cmd;
- start_cmd.header.in = tpm_startup_header;
-
- start_cmd.params.startup_in.startup_type = startup_type;
- return tpm_transmit_cmd(chip, NULL, &start_cmd,
- TPM_INTERNAL_RESULT_SIZE, 0,
- 0, "attempting to start the TPM");
-}
-
int tpm_get_timeouts(struct tpm_chip *chip)
{
cap_t cap;
@@ -631,10 +656,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL,
sizeof(cap.timeout));
if (rc == TPM_ERR_INVALID_POSTINIT) {
- /* The TPM is not started, we are the first to talk to it.
- Execute a startup command. */
- dev_info(&chip->dev, "Issuing TPM_STARTUP\n");
- if (tpm_startup(chip, TPM_ST_CLEAR))
+ if (tpm_startup(chip))
return rc;
rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
@@ -737,7 +759,7 @@ EXPORT_SYMBOL_GPL(tpm_get_timeouts);
#define CONTINUE_SELFTEST_RESULT_SIZE 10
static const struct tpm_input_header continue_selftest_header = {
- .tag = TPM_TAG_RQU_COMMAND,
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(10),
.ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
};
@@ -760,13 +782,13 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
return rc;
}
-#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
+#define TPM_ORDINAL_PCRREAD 21
#define READ_PCR_RESULT_SIZE 30
#define READ_PCR_RESULT_BODY_SIZE 20
static const struct tpm_input_header pcrread_header = {
- .tag = TPM_TAG_RQU_COMMAND,
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(14),
- .ordinal = TPM_ORDINAL_PCRREAD
+ .ordinal = cpu_to_be32(TPM_ORDINAL_PCRREAD)
};
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
@@ -838,15 +860,34 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
}
EXPORT_SYMBOL_GPL(tpm_pcr_read);
-#define TPM_ORD_PCR_EXTEND cpu_to_be32(20)
+#define TPM_ORD_PCR_EXTEND 20
#define EXTEND_PCR_RESULT_SIZE 34
#define EXTEND_PCR_RESULT_BODY_SIZE 20
static const struct tpm_input_header pcrextend_header = {
- .tag = TPM_TAG_RQU_COMMAND,
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(34),
- .ordinal = TPM_ORD_PCR_EXTEND
+ .ordinal = cpu_to_be32(TPM_ORD_PCR_EXTEND)
};
+static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash,
+ char *log_msg)
+{
+ struct tpm_buf buf;
+ int rc;
+
+ rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
+ if (rc)
+ return rc;
+
+ tpm_buf_append_u32(&buf, pcr_idx);
+ tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
+
+ rc = tpm_transmit_cmd(chip, NULL, buf.data, EXTEND_PCR_RESULT_SIZE,
+ EXTEND_PCR_RESULT_BODY_SIZE, 0, log_msg);
+ tpm_buf_destroy(&buf);
+ return rc;
+}
+
/**
* tpm_pcr_extend - extend pcr value with hash
* @chip_num: tpm idx # or AN&
@@ -859,7 +900,6 @@ static const struct tpm_input_header pcrextend_header = {
*/
int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
{
- struct tpm_cmd_t cmd;
int rc;
struct tpm_chip *chip;
struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
@@ -885,13 +925,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
return rc;
}
- cmd.header.in = pcrextend_header;
- cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
- memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
- rc = tpm_transmit_cmd(chip, NULL, &cmd, EXTEND_PCR_RESULT_SIZE,
- EXTEND_PCR_RESULT_BODY_SIZE, 0,
- "attempting extend a PCR value");
-
+ rc = tpm1_pcr_extend(chip, pcr_idx, hash,
+ "attempting extend a PCR value");
tpm_put_ops(chip);
return rc;
}
@@ -1060,13 +1095,13 @@ again:
}
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
-#define TPM_ORD_SAVESTATE cpu_to_be32(152)
+#define TPM_ORD_SAVESTATE 152
#define SAVESTATE_RESULT_SIZE 10
static const struct tpm_input_header savestate_header = {
- .tag = TPM_TAG_RQU_COMMAND,
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(10),
- .ordinal = TPM_ORD_SAVESTATE
+ .ordinal = cpu_to_be32(TPM_ORD_SAVESTATE)
};
/*
@@ -1084,21 +1119,18 @@ int tpm_pm_suspend(struct device *dev)
if (chip == NULL)
return -ENODEV;
+ if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
+ return 0;
+
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
tpm2_shutdown(chip, TPM2_SU_STATE);
return 0;
}
/* for buggy tpm, flush pcrs with extend to selected dummy */
- if (tpm_suspend_pcr) {
- cmd.header.in = pcrextend_header;
- cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
- memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
- TPM_DIGEST_SIZE);
- rc = tpm_transmit_cmd(chip, NULL, &cmd, EXTEND_PCR_RESULT_SIZE,
- EXTEND_PCR_RESULT_BODY_SIZE, 0,
- "extending dummy pcr before suspend");
- }
+ if (tpm_suspend_pcr)
+ rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
+ "extending dummy pcr before suspend");
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
@@ -1149,9 +1181,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume);
#define TPM_GETRANDOM_RESULT_SIZE 18
static const struct tpm_input_header tpm_getrandom_header = {
- .tag = TPM_TAG_RQU_COMMAND,
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(14),
- .ordinal = TPM_ORD_GET_RANDOM
+ .ordinal = cpu_to_be32(TPM_ORD_GET_RANDOM)
};
/**
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 55405dbe43fa..86f38d239476 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -22,11 +22,11 @@
#define READ_PUBEK_RESULT_SIZE 314
#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256)
-#define TPM_ORD_READPUBEK cpu_to_be32(124)
+#define TPM_ORD_READPUBEK 124
static const struct tpm_input_header tpm_readpubek_header = {
- .tag = TPM_TAG_RQU_COMMAND,
+ .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
.length = cpu_to_be32(30),
- .ordinal = TPM_ORD_READPUBEK
+ .ordinal = cpu_to_be32(TPM_ORD_READPUBEK)
};
static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -36,9 +36,10 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
ssize_t err;
int i, rc;
char *str = buf;
-
struct tpm_chip *chip = to_tpm_chip(dev);
+ memset(&tpm_cmd, 0, sizeof(tpm_cmd));
+
tpm_cmd.header.in = tpm_readpubek_header;
err = tpm_transmit_cmd(chip, NULL, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
READ_PUBEK_RESULT_MIN_BODY_SIZE, 0,
@@ -294,6 +295,9 @@ static const struct attribute_group tpm_dev_group = {
void tpm_sysfs_add_device(struct tpm_chip *chip)
{
+ /* XXX: If you wish to remove this restriction, you must first update
+ * tpm_sysfs to explicitly lock chip->ops.
+ */
if (chip->flags & TPM_CHIP_FLAG_TPM2)
return;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 4b4c8dee3096..04fbff2edbf3 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -36,6 +36,10 @@
#include <linux/highmem.h>
#include <crypto/hash_info.h>
+#ifdef CONFIG_X86
+#include <asm/intel-family.h>
+#endif
+
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_BUFSIZE = 4096,
@@ -170,6 +174,7 @@ enum tpm_chip_flags {
TPM_CHIP_FLAG_IRQ = BIT(2),
TPM_CHIP_FLAG_VIRTUAL = BIT(3),
TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
+ TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
};
struct tpm_bios_log {
@@ -247,7 +252,7 @@ struct tpm_output_header {
__be32 return_code;
} __packed;
-#define TPM_TAG_RQU_COMMAND cpu_to_be16(193)
+#define TPM_TAG_RQU_COMMAND 193
struct stclear_flags_t {
__be16 tag;
@@ -339,17 +344,6 @@ enum tpm_sub_capabilities {
TPM_CAP_PROP_TIS_DURATION = 0x120,
};
-struct tpm_getcap_params_in {
- __be32 cap;
- __be32 subcap_size;
- __be32 subcap;
-} __packed;
-
-struct tpm_getcap_params_out {
- __be32 cap_size;
- cap_t cap;
-} __packed;
-
struct tpm_readpubek_params_out {
u8 algorithm[4];
u8 encscheme[2];
@@ -374,11 +368,6 @@ struct tpm_pcrread_in {
__be32 pcr_idx;
} __packed;
-struct tpm_pcrextend_in {
- __be32 pcr_idx;
- u8 hash[TPM_DIGEST_SIZE];
-} __packed;
-
/* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
* bytes, but 128 is still a relatively large number of random bytes and
* anything much bigger causes users of struct tpm_cmd_t to start getting
@@ -394,21 +383,13 @@ struct tpm_getrandom_in {
__be32 num_bytes;
} __packed;
-struct tpm_startup_in {
- __be16 startup_type;
-} __packed;
-
typedef union {
- struct tpm_getcap_params_out getcap_out;
struct tpm_readpubek_params_out readpubek_out;
u8 readpubek_out_buffer[sizeof(struct tpm_readpubek_params_out)];
- struct tpm_getcap_params_in getcap_in;
struct tpm_pcrread_in pcrread_in;
struct tpm_pcrread_out pcrread_out;
- struct tpm_pcrextend_in pcrextend_in;
struct tpm_getrandom_in getrandom_in;
struct tpm_getrandom_out getrandom_out;
- struct tpm_startup_in startup_in;
} tpm_cmd_params;
struct tpm_cmd_t {
@@ -525,6 +506,7 @@ extern struct idr dev_nums_idr;
enum tpm_transmit_flags {
TPM_TRANSMIT_UNLOCKED = BIT(0),
+ TPM_TRANSMIT_RAW = BIT(1),
};
ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
@@ -533,6 +515,7 @@ ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
const void *buf, size_t bufsiz,
size_t min_rsp_body_length, unsigned int flags,
const char *desc);
+int tpm_startup(struct tpm_chip *chip);
ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
const char *desc, size_t min_cap_length);
int tpm_get_timeouts(struct tpm_chip *);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 3ee6883f26c1..f7f34b2aa981 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -35,24 +35,6 @@ struct tpm2_self_test_in {
u8 full_test;
} __packed;
-struct tpm2_pcr_read_in {
- __be32 pcr_selects_cnt;
- __be16 hash_alg;
- u8 pcr_select_size;
- u8 pcr_select[TPM2_PCR_SELECT_MIN];
-} __packed;
-
-struct tpm2_pcr_read_out {
- __be32 update_cnt;
- __be32 pcr_selects_cnt;
- __be16 hash_alg;
- u8 pcr_select_size;
- u8 pcr_select[TPM2_PCR_SELECT_MIN];
- __be32 digests_cnt;
- __be16 digest_size;
- u8 digest[TPM_DIGEST_SIZE];
-} __packed;
-
struct tpm2_get_tpm_pt_in {
__be32 cap_id;
__be32 property_id;
@@ -79,8 +61,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_pcr_read_in pcrread_in;
- struct tpm2_pcr_read_out pcrread_out;
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;
@@ -227,18 +207,16 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
TPM_UNDEFINED /* 18f */
};
-#define TPM2_PCR_READ_IN_SIZE \
- (sizeof(struct tpm_input_header) + \
- sizeof(struct tpm2_pcr_read_in))
-
-#define TPM2_PCR_READ_RESP_BODY_SIZE \
- sizeof(struct tpm2_pcr_read_out)
-
-static const struct tpm_input_header tpm2_pcrread_header = {
- .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
- .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE),
- .ordinal = cpu_to_be32(TPM2_CC_PCR_READ)
-};
+struct tpm2_pcr_read_out {
+ __be32 update_cnt;
+ __be32 pcr_selects_cnt;
+ __be16 hash_alg;
+ u8 pcr_select_size;
+ u8 pcr_select[TPM2_PCR_SELECT_MIN];
+ __be32 digests_cnt;
+ __be16 digest_size;
+ u8 digest[];
+} __packed;
/**
* tpm2_pcr_read() - read a PCR value
@@ -251,29 +229,33 @@ static const struct tpm_input_header tpm2_pcrread_header = {
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
{
int rc;
- struct tpm2_cmd cmd;
- u8 *buf;
+ struct tpm_buf buf;
+ struct tpm2_pcr_read_out *out;
+ u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0};
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
- cmd.header.in = tpm2_pcrread_header;
- cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
- cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
- cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
+ rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ);
+ if (rc)
+ return rc;
+
+ pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
- memset(cmd.params.pcrread_in.pcr_select, 0,
- sizeof(cmd.params.pcrread_in.pcr_select));
- cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
+ tpm_buf_append_u32(&buf, 1);
+ tpm_buf_append_u16(&buf, TPM2_ALG_SHA1);
+ tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN);
+ tpm_buf_append(&buf, (const unsigned char *)pcr_select,
+ sizeof(pcr_select));
- rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd),
- TPM2_PCR_READ_RESP_BODY_SIZE,
- 0, "attempting to read a pcr value");
- if (rc == 0) {
- buf = cmd.params.pcrread_out.digest;
- memcpy(res_buf, buf, TPM_DIGEST_SIZE);
+ rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
+ res_buf ? "attempting to read a pcr value" : NULL);
+ if (rc == 0 && res_buf) {
+ out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE];
+ memcpy(res_buf, out->digest, SHA1_DIGEST_SIZE);
}
+ tpm_buf_destroy(&buf);
return rc;
}
@@ -779,36 +761,6 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
}
EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt);
-#define TPM2_STARTUP_IN_SIZE \
- (sizeof(struct tpm_input_header) + \
- sizeof(struct tpm2_startup_in))
-
-static const struct tpm_input_header tpm2_startup_header = {
- .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
- .length = cpu_to_be32(TPM2_STARTUP_IN_SIZE),
- .ordinal = cpu_to_be32(TPM2_CC_STARTUP)
-};
-
-/**
- * tpm2_startup() - send startup command to the TPM chip
- *
- * @chip: TPM chip to use.
- * @startup_type: startup type. The value is either
- * TPM_SU_CLEAR or TPM_SU_STATE.
- *
- * Return: Same as with tpm_transmit_cmd.
- */
-static int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
-{
- struct tpm2_cmd cmd;
-
- cmd.header.in = tpm2_startup_header;
-
- cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
- return tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0,
- "attempting to start the TPM");
-}
-
#define TPM2_SHUTDOWN_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_startup_in))
@@ -840,7 +792,7 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
/* In places where shutdown command is sent there's no much we can do
* except print the error code on a system failure.
*/
- if (rc < 0)
+ if (rc < 0 && rc != -EPIPE)
dev_warn(&chip->dev, "transmit returned %d while stopping the TPM",
rc);
}
@@ -928,7 +880,6 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
unsigned int loops;
unsigned int delay_msec = 100;
unsigned long duration;
- struct tpm2_cmd cmd;
int i;
duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
@@ -941,20 +892,10 @@ static int tpm2_do_selftest(struct tpm_chip *chip)
for (i = 0; i < loops; i++) {
/* Attempt to read a PCR value */
- cmd.header.in = tpm2_pcrread_header;
- cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
- cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
- cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
- cmd.params.pcrread_in.pcr_select[0] = 0x01;
- cmd.params.pcrread_in.pcr_select[1] = 0x00;
- cmd.params.pcrread_in.pcr_select[2] = 0x00;
-
- rc = tpm_transmit_cmd(chip, NULL, &cmd, sizeof(cmd), 0, 0,
- NULL);
+ rc = tpm2_pcr_read(chip, 0, NULL);
if (rc < 0)
break;
- rc = be32_to_cpu(cmd.header.out.return_code);
if (rc != TPM2_RC_TESTING)
break;
@@ -1150,7 +1091,7 @@ int tpm2_auto_startup(struct tpm_chip *chip)
}
if (rc == TPM2_RC_INITIALIZE) {
- rc = tpm2_startup(chip, TPM2_SU_CLEAR);
+ rc = tpm_startup(chip);
if (rc)
goto out;
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 0d322ab11faa..66a14526aaf4 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -144,13 +144,11 @@ static void atml_plat_remove(void)
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
struct tpm_atmel_priv *priv = dev_get_drvdata(&chip->dev);
- if (chip) {
- tpm_chip_unregister(chip);
- if (priv->have_region)
- atmel_release_region(priv->base, priv->region_size);
- atmel_put_base_addr(priv->iobase);
- platform_device_unregister(pdev);
- }
+ tpm_chip_unregister(chip);
+ if (priv->have_region)
+ atmel_release_region(priv->base, priv->region_size);
+ atmel_put_base_addr(priv->iobase);
+ platform_device_unregister(pdev);
}
static SIMPLE_DEV_PM_OPS(tpm_atml_pm, tpm_pm_suspend, tpm_pm_resume);
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index c378c7b15d49..a4ac63a21d8a 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -514,11 +514,12 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
goto out;
}
- priv->cmd_size = cmd_size;
-
priv->rsp = priv->cmd;
out:
+ if (!ret)
+ priv->cmd_size = cmd_size;
+
crb_go_idle(dev, priv);
return ret;
@@ -563,12 +564,12 @@ static int crb_acpi_add(struct acpi_device *device)
sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD)
priv->flags |= CRB_FL_ACPI_START;
- if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_SMC) {
+ if (sm == ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC) {
if (buf->header.length < (sizeof(*buf) + sizeof(*crb_smc))) {
dev_err(dev,
FW_BUG "TPM2 ACPI table has wrong size %u for start method type %d\n",
buf->header.length,
- ACPI_TPM2_COMMAND_BUFFER_WITH_SMC);
+ ACPI_TPM2_COMMAND_BUFFER_WITH_ARM_SMC);
return -EINVAL;
}
crb_smc = ACPI_ADD_PTR(struct tpm2_crb_smc, buf, sizeof(*buf));
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index dc47fa222a26..79d6bbb58e39 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -70,6 +70,7 @@ struct tpm_inf_dev {
u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */
struct tpm_chip *chip;
enum i2c_chip_type chip_type;
+ unsigned int adapterlimit;
};
static struct tpm_inf_dev tpm_dev;
@@ -111,6 +112,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
int rc = 0;
int count;
+ unsigned int msglen = len;
/* Lock the adapter for the duration of the whole sequence. */
if (!tpm_dev.client->adapter->algo->master_xfer)
@@ -131,27 +133,61 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
}
} else {
- /* slb9635 protocol should work in all cases */
- for (count = 0; count < MAX_COUNT; count++) {
- rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1);
- if (rc > 0)
- break; /* break here to skip sleep */
-
- usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
- }
-
- if (rc <= 0)
- goto out;
-
- /* After the TPM has successfully received the register address
- * it needs some time, thus we're sleeping here again, before
- * retrieving the data
+ /* Expect to send one command message and one data message, but
+ * support looping over each or both if necessary.
*/
- for (count = 0; count < MAX_COUNT; count++) {
- usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI);
- rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1);
- if (rc > 0)
- break;
+ while (len > 0) {
+ /* slb9635 protocol should work in all cases */
+ for (count = 0; count < MAX_COUNT; count++) {
+ rc = __i2c_transfer(tpm_dev.client->adapter,
+ &msg1, 1);
+ if (rc > 0)
+ break; /* break here to skip sleep */
+
+ usleep_range(SLEEP_DURATION_LOW,
+ SLEEP_DURATION_HI);
+ }
+
+ if (rc <= 0)
+ goto out;
+
+ /* After the TPM has successfully received the register
+ * address it needs some time, thus we're sleeping here
+ * again, before retrieving the data
+ */
+ for (count = 0; count < MAX_COUNT; count++) {
+ if (tpm_dev.adapterlimit) {
+ msglen = min_t(unsigned int,
+ tpm_dev.adapterlimit,
+ len);
+ msg2.len = msglen;
+ }
+ usleep_range(SLEEP_DURATION_LOW,
+ SLEEP_DURATION_HI);
+ rc = __i2c_transfer(tpm_dev.client->adapter,
+ &msg2, 1);
+ if (rc > 0) {
+ /* Since len is unsigned, make doubly
+ * sure we do not underflow it.
+ */
+ if (msglen > len)
+ len = 0;
+ else
+ len -= msglen;
+ msg2.buf += msglen;
+ break;
+ }
+ /* If the I2C adapter rejected the request (e.g
+ * when the quirk read_max_len < len) fall back
+ * to a sane minimum value and try again.
+ */
+ if (rc == -EOPNOTSUPP)
+ tpm_dev.adapterlimit =
+ I2C_SMBUS_BLOCK_MAX;
+ }
+
+ if (rc <= 0)
+ goto out;
}
}
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index e3cf9f3545c5..3b1b9f9322d5 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -397,7 +397,7 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
int vendorid[2];
int version[2];
int productid[2];
- char chipname[20];
+ const char *chipname;
struct tpm_chip *chip;
/* read IO-ports through PnP */
@@ -488,13 +488,13 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
switch ((productid[0] << 8) | productid[1]) {
case 6:
- snprintf(chipname, sizeof(chipname), " (SLD 9630 TT 1.1)");
+ chipname = " (SLD 9630 TT 1.1)";
break;
case 11:
- snprintf(chipname, sizeof(chipname), " (SLB 9635 TT 1.2)");
+ chipname = " (SLB 9635 TT 1.2)";
break;
default:
- snprintf(chipname, sizeof(chipname), " (unknown chip)");
+ chipname = " (unknown chip)";
break;
}
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c
index de57d4ac8901..aadb7f464076 100644
--- a/drivers/char/tpm/tpm_of.c
+++ b/drivers/char/tpm/tpm_of.c
@@ -36,6 +36,9 @@ int tpm_read_log_of(struct tpm_chip *chip)
else
return -ENODEV;
+ if (of_property_read_bool(np, "powered-while-suspended"))
+ chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
+
sizep = of_get_property(np, "linux,sml-size", NULL);
basep = of_get_property(np, "linux,sml-base", NULL);
if (sizep == NULL && basep == NULL)
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index c7e1384f1b08..7e55aa9ce680 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -80,6 +80,8 @@ static int has_hid(struct acpi_device *dev, const char *hid)
static inline int is_itpm(struct acpi_device *dev)
{
+ if (!dev)
+ return 0;
return has_hid(dev, "INTC0102");
}
#else
@@ -89,13 +91,134 @@ static inline int is_itpm(struct acpi_device *dev)
}
#endif
+#if defined(CONFIG_ACPI)
+#define DEVICE_IS_TPM2 1
+
+static const struct acpi_device_id tpm_acpi_tbl[] = {
+ {"MSFT0101", DEVICE_IS_TPM2},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, tpm_acpi_tbl);
+
+static int check_acpi_tpm2(struct device *dev)
+{
+ const struct acpi_device_id *aid = acpi_match_device(tpm_acpi_tbl, dev);
+ struct acpi_table_tpm2 *tbl;
+ acpi_status st;
+
+ if (!aid || aid->driver_data != DEVICE_IS_TPM2)
+ return 0;
+
+ /* If the ACPI TPM2 signature is matched then a global ACPI_SIG_TPM2
+ * table is mandatory
+ */
+ st =
+ acpi_get_table(ACPI_SIG_TPM2, 1, (struct acpi_table_header **)&tbl);
+ if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
+ dev_err(dev, FW_BUG "failed to get TPM2 ACPI table\n");
+ return -EINVAL;
+ }
+
+ /* The tpm2_crb driver handles this device */
+ if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
+ return -ENODEV;
+
+ return 0;
+}
+#else
+static int check_acpi_tpm2(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_X86
+#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000
+#define ILB_REMAP_SIZE 0x100
+#define LPC_CNTRL_REG_OFFSET 0x84
+#define LPC_CLKRUN_EN (1 << 2)
+
+static void __iomem *ilb_base_addr;
+
+static inline bool is_bsw(void)
+{
+ return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0);
+}
+
+/**
+ * tpm_platform_begin_xfer() - clear LPC CLKRUN_EN i.e. clocks will be running
+ */
+static void tpm_platform_begin_xfer(void)
+{
+ u32 clkrun_val;
+
+ if (!is_bsw())
+ return;
+
+ clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET);
+
+ /* Disable LPC CLKRUN# */
+ clkrun_val &= ~LPC_CLKRUN_EN;
+ iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET);
+
+ /*
+ * Write any random value on port 0x80 which is on LPC, to make
+ * sure LPC clock is running before sending any TPM command.
+ */
+ outb(0xCC, 0x80);
+
+}
+
+/**
+ * tpm_platform_end_xfer() - set LPC CLKRUN_EN i.e. clocks can be turned off
+ */
+static void tpm_platform_end_xfer(void)
+{
+ u32 clkrun_val;
+
+ if (!is_bsw())
+ return;
+
+ clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET);
+
+ /* Enable LPC CLKRUN# */
+ clkrun_val |= LPC_CLKRUN_EN;
+ iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET);
+
+ /*
+ * Write any random value on port 0x80 which is on LPC, to make
+ * sure LPC clock is running before sending any TPM command.
+ */
+ outb(0xCC, 0x80);
+
+}
+#else
+static inline bool is_bsw(void)
+{
+ return false;
+}
+
+static void tpm_platform_begin_xfer(void)
+{
+}
+
+static void tpm_platform_end_xfer(void)
+{
+}
+#endif
+
static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
u8 *result)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
+ tpm_platform_begin_xfer();
+
while (len--)
*result++ = ioread8(phy->iobase + addr);
+
+ tpm_platform_end_xfer();
+
return 0;
}
@@ -104,8 +227,13 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
+ tpm_platform_begin_xfer();
+
while (len--)
iowrite8(*value++, phy->iobase + addr);
+
+ tpm_platform_end_xfer();
+
return 0;
}
@@ -113,7 +241,12 @@ static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
+ tpm_platform_begin_xfer();
+
*result = ioread16(phy->iobase + addr);
+
+ tpm_platform_end_xfer();
+
return 0;
}
@@ -121,7 +254,12 @@ static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
+ tpm_platform_begin_xfer();
+
*result = ioread32(phy->iobase + addr);
+
+ tpm_platform_end_xfer();
+
return 0;
}
@@ -129,7 +267,12 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
+ tpm_platform_begin_xfer();
+
iowrite32(value, phy->iobase + addr);
+
+ tpm_platform_end_xfer();
+
return 0;
}
@@ -141,11 +284,15 @@ static const struct tpm_tis_phy_ops tpm_tcg = {
.write32 = tpm_tcg_write32,
};
-static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
- acpi_handle acpi_dev_handle)
+static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
{
struct tpm_tis_tcg_phy *phy;
int irq = -1;
+ int rc;
+
+ rc = check_acpi_tpm2(dev);
+ if (rc)
+ return rc;
phy = devm_kzalloc(dev, sizeof(struct tpm_tis_tcg_phy), GFP_KERNEL);
if (phy == NULL)
@@ -158,11 +305,11 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
if (interrupts)
irq = tpm_info->irq;
- if (itpm)
+ if (itpm || is_itpm(ACPI_COMPANION(dev)))
phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND;
return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
- acpi_dev_handle);
+ ACPI_HANDLE(dev));
}
static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
@@ -171,7 +318,6 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
const struct pnp_device_id *pnp_id)
{
struct tpm_info tpm_info = {};
- acpi_handle acpi_dev_handle = NULL;
struct resource *res;
res = pnp_get_resource(pnp_dev, IORESOURCE_MEM, 0);
@@ -184,14 +330,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
else
tpm_info.irq = -1;
- if (pnp_acpi_device(pnp_dev)) {
- if (is_itpm(pnp_acpi_device(pnp_dev)))
- itpm = true;
-
- acpi_dev_handle = ACPI_HANDLE(&pnp_dev->dev);
- }
-
- return tpm_tis_init(&pnp_dev->dev, &tpm_info, acpi_dev_handle);
+ return tpm_tis_init(&pnp_dev->dev, &tpm_info);
}
static struct pnp_device_id tpm_pnp_tbl[] = {
@@ -231,93 +370,6 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
-#ifdef CONFIG_ACPI
-static int tpm_check_resource(struct acpi_resource *ares, void *data)
-{
- struct tpm_info *tpm_info = (struct tpm_info *) data;
- struct resource res;
-
- if (acpi_dev_resource_interrupt(ares, 0, &res))
- tpm_info->irq = res.start;
- else if (acpi_dev_resource_memory(ares, &res)) {
- tpm_info->res = res;
- tpm_info->res.name = NULL;
- }
-
- return 1;
-}
-
-static int tpm_tis_acpi_init(struct acpi_device *acpi_dev)
-{
- struct acpi_table_tpm2 *tbl;
- acpi_status st;
- struct list_head resources;
- struct tpm_info tpm_info = {};
- int ret;
-
- st = acpi_get_table(ACPI_SIG_TPM2, 1,
- (struct acpi_table_header **) &tbl);
- if (ACPI_FAILURE(st) || tbl->header.length < sizeof(*tbl)) {
- dev_err(&acpi_dev->dev,
- FW_BUG "failed to get TPM2 ACPI table\n");
- return -EINVAL;
- }
-
- if (tbl->start_method != ACPI_TPM2_MEMORY_MAPPED)
- return -ENODEV;
-
- INIT_LIST_HEAD(&resources);
- tpm_info.irq = -1;
- ret = acpi_dev_get_resources(acpi_dev, &resources, tpm_check_resource,
- &tpm_info);
- if (ret < 0)
- return ret;
-
- acpi_dev_free_resource_list(&resources);
-
- if (resource_type(&tpm_info.res) != IORESOURCE_MEM) {
- dev_err(&acpi_dev->dev,
- FW_BUG "TPM2 ACPI table does not define a memory resource\n");
- return -EINVAL;
- }
-
- if (is_itpm(acpi_dev))
- itpm = true;
-
- return tpm_tis_init(&acpi_dev->dev, &tpm_info, acpi_dev->handle);
-}
-
-static int tpm_tis_acpi_remove(struct acpi_device *dev)
-{
- struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
-
- tpm_chip_unregister(chip);
- tpm_tis_remove(chip);
-
- return 0;
-}
-
-static struct acpi_device_id tpm_acpi_tbl[] = {
- {"MSFT0101", 0}, /* TPM 2.0 */
- /* Add new here */
- {"", 0}, /* User Specified */
- {"", 0} /* Terminator */
-};
-MODULE_DEVICE_TABLE(acpi, tpm_acpi_tbl);
-
-static struct acpi_driver tis_acpi_driver = {
- .name = "tpm_tis",
- .ids = tpm_acpi_tbl,
- .ops = {
- .add = tpm_tis_acpi_init,
- .remove = tpm_tis_acpi_remove,
- },
- .drv = {
- .pm = &tpm_tis_pm,
- },
-};
-#endif
-
static struct platform_device *force_pdev;
static int tpm_tis_plat_probe(struct platform_device *pdev)
@@ -332,18 +384,16 @@ static int tpm_tis_plat_probe(struct platform_device *pdev)
}
tpm_info.res = *res;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res) {
- tpm_info.irq = res->start;
- } else {
- if (pdev == force_pdev)
+ tpm_info.irq = platform_get_irq(pdev, 0);
+ if (tpm_info.irq <= 0) {
+ if (pdev != force_pdev)
tpm_info.irq = -1;
else
/* When forcing auto probe the IRQ */
tpm_info.irq = 0;
}
- return tpm_tis_init(&pdev->dev, &tpm_info, NULL);
+ return tpm_tis_init(&pdev->dev, &tpm_info);
}
static int tpm_tis_plat_remove(struct platform_device *pdev)
@@ -371,6 +421,7 @@ static struct platform_driver tis_drv = {
.name = "tpm_tis",
.pm = &tpm_tis_pm,
.of_match_table = of_match_ptr(tis_of_platform_match),
+ .acpi_match_table = ACPI_PTR(tpm_acpi_tbl),
},
};
@@ -409,15 +460,15 @@ static int __init init_tis(void)
if (rc)
goto err_force;
+#ifdef CONFIG_X86
+ if (is_bsw())
+ ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR,
+ ILB_REMAP_SIZE);
+#endif
rc = platform_driver_register(&tis_drv);
if (rc)
goto err_platform;
-#ifdef CONFIG_ACPI
- rc = acpi_bus_register_driver(&tis_acpi_driver);
- if (rc)
- goto err_acpi;
-#endif
if (IS_ENABLED(CONFIG_PNP)) {
rc = pnp_register_driver(&tis_pnp_driver);
@@ -428,14 +479,14 @@ static int __init init_tis(void)
return 0;
err_pnp:
-#ifdef CONFIG_ACPI
- acpi_bus_unregister_driver(&tis_acpi_driver);
-err_acpi:
-#endif
platform_driver_unregister(&tis_drv);
err_platform:
if (force_pdev)
platform_device_unregister(force_pdev);
+#ifdef CONFIG_X86
+ if (is_bsw())
+ iounmap(ilb_base_addr);
+#endif
err_force:
return rc;
}
@@ -443,11 +494,12 @@ err_force:
static void __exit cleanup_tis(void)
{
pnp_unregister_driver(&tis_pnp_driver);
-#ifdef CONFIG_ACPI
- acpi_bus_unregister_driver(&tis_acpi_driver);
-#endif
platform_driver_unregister(&tis_drv);
+#ifdef CONFIG_X86
+ if (is_bsw())
+ iounmap(ilb_base_addr);
+#endif
if (force_pdev)
platform_device_unregister(force_pdev);
}
diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c
index 751059d2140a..1d877cc9af97 100644
--- a/drivers/char/tpm/tpm_vtpm_proxy.c
+++ b/drivers/char/tpm/tpm_vtpm_proxy.c
@@ -43,6 +43,7 @@ struct proxy_dev {
#define STATE_OPENED_FLAG BIT(0)
#define STATE_WAIT_RESPONSE_FLAG BIT(1) /* waiting for emulator response */
#define STATE_REGISTERED_FLAG BIT(2)
+#define STATE_DRIVER_COMMAND BIT(3) /* sending a driver specific command */
size_t req_len; /* length of queued TPM request */
size_t resp_len; /* length of queued TPM response */
@@ -299,6 +300,28 @@ out:
return len;
}
+static int vtpm_proxy_is_driver_command(struct tpm_chip *chip,
+ u8 *buf, size_t count)
+{
+ struct tpm_input_header *hdr = (struct tpm_input_header *)buf;
+
+ if (count < sizeof(struct tpm_input_header))
+ return 0;
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ switch (be32_to_cpu(hdr->ordinal)) {
+ case TPM2_CC_SET_LOCALITY:
+ return 1;
+ }
+ } else {
+ switch (be32_to_cpu(hdr->ordinal)) {
+ case TPM_ORD_SET_LOCALITY:
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
* Called when core TPM driver forwards TPM requests to 'server side'.
*
@@ -321,6 +344,10 @@ static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count)
return -EIO;
}
+ if (!(proxy_dev->state & STATE_DRIVER_COMMAND) &&
+ vtpm_proxy_is_driver_command(chip, buf, count))
+ return -EFAULT;
+
mutex_lock(&proxy_dev->buf_lock);
if (!(proxy_dev->state & STATE_OPENED_FLAG)) {
@@ -371,6 +398,47 @@ static bool vtpm_proxy_tpm_req_canceled(struct tpm_chip *chip, u8 status)
return ret;
}
+static int vtpm_proxy_request_locality(struct tpm_chip *chip, int locality)
+{
+ struct tpm_buf buf;
+ int rc;
+ const struct tpm_output_header *header;
+ struct proxy_dev *proxy_dev = dev_get_drvdata(&chip->dev);
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS,
+ TPM2_CC_SET_LOCALITY);
+ else
+ rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND,
+ TPM_ORD_SET_LOCALITY);
+ if (rc)
+ return rc;
+ tpm_buf_append_u8(&buf, locality);
+
+ proxy_dev->state |= STATE_DRIVER_COMMAND;
+
+ rc = tpm_transmit_cmd(chip, NULL, buf.data, tpm_buf_length(&buf), 0,
+ TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW,
+ "attempting to set locality");
+
+ proxy_dev->state &= ~STATE_DRIVER_COMMAND;
+
+ if (rc < 0) {
+ locality = rc;
+ goto out;
+ }
+
+ header = (const struct tpm_output_header *)buf.data;
+ rc = be32_to_cpu(header->return_code);
+ if (rc)
+ locality = -1;
+
+out:
+ tpm_buf_destroy(&buf);
+
+ return locality;
+}
+
static const struct tpm_class_ops vtpm_proxy_tpm_ops = {
.flags = TPM_OPS_AUTO_STARTUP,
.recv = vtpm_proxy_tpm_op_recv,
@@ -380,6 +448,7 @@ static const struct tpm_class_ops vtpm_proxy_tpm_ops = {
.req_complete_mask = VTPM_PROXY_REQ_COMPLETE_FLAG,
.req_complete_val = VTPM_PROXY_REQ_COMPLETE_FLAG,
.req_canceled = vtpm_proxy_tpm_req_canceled,
+ .request_locality = vtpm_proxy_request_locality,
};
/*
diff --git a/drivers/char/tpm/tpmrm-dev.c b/drivers/char/tpm/tpmrm-dev.c
index c636e7fdd1f5..1a0e97a5da5a 100644
--- a/drivers/char/tpm/tpmrm-dev.c
+++ b/drivers/char/tpm/tpmrm-dev.c
@@ -45,7 +45,7 @@ static int tpmrm_release(struct inode *inode, struct file *file)
return 0;
}
-ssize_t tpmrm_write(struct file *file, const char __user *buf,
+static ssize_t tpmrm_write(struct file *file, const char __user *buf,
size_t size, loff_t *off)
{
struct file_priv *fpriv = file->private_data;
OpenPOWER on IntegriCloud