diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/hw_random/mtk-rng.c | 42 | ||||
-rw-r--r-- | drivers/char/hw_random/omap3-rom-rng.c | 11 | ||||
-rw-r--r-- | drivers/char/hw_random/timeriomem-rng.c | 7 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_devintf.c | 333 | ||||
-rw-r--r-- | drivers/char/pcmcia/synclink_cs.c | 2 | ||||
-rw-r--r-- | drivers/char/tpm/st33zp24/i2c.c | 3 | ||||
-rw-r--r-- | drivers/char/tpm/st33zp24/spi.c | 3 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 34 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 182 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-sysfs.c | 12 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 33 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 123 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_atmel.c | 12 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_crb.c | 9 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_infineon.c | 76 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_infineon.c | 8 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_of.c | 3 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 288 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_vtpm_proxy.c | 69 | ||||
-rw-r--r-- | drivers/char/tpm/tpmrm-dev.c | 2 |
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; |