Commit f2f393c3 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tpmdd-v6.5-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull tpm fixes from Jarkko Sakkinen.

Mostly interrupt storm fixes, with some other minor changes.

* tag 'tpmdd-v6.5-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  tpm,tpm_tis: Disable interrupts after 1000 unhandled IRQs
  tpm/tpm_tis: Disable interrupts for Lenovo L590 devices
  tpm: Do not remap from ACPI resources again for Pluton TPM
  tpm/tpm_tis: Disable interrupts for Framework Laptop Intel 13th gen
  tpm/tpm_tis: Disable interrupts for Framework Laptop Intel 12th gen
  security: keys: Modify mismatched function name
  tpm: return false from tpm_amd_is_rng_defective on non-x86 platforms
  keys: Fix linking a duplicate key to a keyring's assoc_array
  tpm: tis_i2c: Limit write bursts to I2C_SMBUS_BLOCK_MAX (32) bytes
  tpm: tis_i2c: Limit read bursts to I2C_SMBUS_BLOCK_MAX (32) bytes
  tpm_tis_spi: Release chip select when flow control fails
  tpm: tpm_tis: Disable interrupts *only* for AEON UPX-i11
  tpm: tpm_vtpm_proxy: fix a race condition in /dev/vtpmx creation
parents fdf0eaf1 481c2d14
......@@ -518,6 +518,7 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
* 6.x.y.z series: 6.0.18.6 +
* 3.x.y.z series: 3.57.y.5 +
*/
#ifdef CONFIG_X86
static bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
{
u32 val1, val2;
......@@ -566,6 +567,12 @@ static bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
return true;
}
#else
static inline bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
{
return false;
}
#endif /* CONFIG_X86 */
static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
......
......@@ -563,15 +563,18 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
u32 rsp_size;
int ret;
INIT_LIST_HEAD(&acpi_resource_list);
ret = acpi_dev_get_resources(device, &acpi_resource_list,
crb_check_resource, iores_array);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&acpi_resource_list);
/* Pluton doesn't appear to define ACPI memory regions */
/*
* Pluton sometimes does not define ACPI memory regions.
* Mapping is then done in crb_map_pluton
*/
if (priv->sm != ACPI_TPM2_COMMAND_BUFFER_WITH_PLUTON) {
INIT_LIST_HEAD(&acpi_resource_list);
ret = acpi_dev_get_resources(device, &acpi_resource_list,
crb_check_resource, iores_array);
if (ret < 0)
return ret;
acpi_dev_free_resource_list(&acpi_resource_list);
if (resource_type(iores_array) != IORESOURCE_MEM) {
dev_err(dev, FW_BUG "TPM2 ACPI table does not define a memory resource\n");
return -EINVAL;
......
......@@ -114,6 +114,22 @@ static int tpm_tis_disable_irq(const struct dmi_system_id *d)
}
static const struct dmi_system_id tpm_tis_dmi_table[] = {
{
.callback = tpm_tis_disable_irq,
.ident = "Framework Laptop (12th Gen Intel Core)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (12th Gen Intel Core)"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "Framework Laptop (13th Gen Intel Core)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (13th Gen Intel Core)"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkPad T490s",
......@@ -138,11 +154,20 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L490"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkPad L590",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L590"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "UPX-TGL",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
DMI_MATCH(DMI_PRODUCT_VERSION, "UPX-TGL"),
},
},
{}
......
......@@ -24,9 +24,12 @@
#include <linux/wait.h>
#include <linux/acpi.h>
#include <linux/freezer.h>
#include <linux/dmi.h>
#include "tpm.h"
#include "tpm_tis_core.h"
#define TPM_TIS_MAX_UNHANDLED_IRQS 1000
static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value);
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
......@@ -468,25 +471,29 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
return rc;
}
static void disable_interrupts(struct tpm_chip *chip)
static void __tpm_tis_disable_interrupts(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
u32 int_mask = 0;
tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &int_mask);
int_mask &= ~TPM_GLOBAL_INT_ENABLE;
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), int_mask);
chip->flags &= ~TPM_CHIP_FLAG_IRQ;
}
static void tpm_tis_disable_interrupts(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
u32 intmask;
int rc;
if (priv->irq == 0)
return;
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
if (rc < 0)
intmask = 0;
intmask &= ~TPM_GLOBAL_INT_ENABLE;
rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
__tpm_tis_disable_interrupts(chip);
devm_free_irq(chip->dev.parent, priv->irq, chip);
priv->irq = 0;
chip->flags &= ~TPM_CHIP_FLAG_IRQ;
}
/*
......@@ -552,7 +559,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
tpm_msleep(1);
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
disable_interrupts(chip);
tpm_tis_disable_interrupts(chip);
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
return rc;
}
......@@ -752,6 +759,57 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
return status == TPM_STS_COMMAND_READY;
}
static irqreturn_t tpm_tis_revert_interrupts(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
const char *product;
const char *vendor;
dev_warn(&chip->dev, FW_BUG
"TPM interrupt storm detected, polling instead\n");
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
product = dmi_get_system_info(DMI_PRODUCT_VERSION);
if (vendor && product) {
dev_info(&chip->dev,
"Consider adding the following entry to tpm_tis_dmi_table:\n");
dev_info(&chip->dev, "\tDMI_SYS_VENDOR: %s\n", vendor);
dev_info(&chip->dev, "\tDMI_PRODUCT_VERSION: %s\n", product);
}
if (tpm_tis_request_locality(chip, 0) != 0)
return IRQ_NONE;
__tpm_tis_disable_interrupts(chip);
tpm_tis_relinquish_locality(chip, 0);
schedule_work(&priv->free_irq_work);
return IRQ_HANDLED;
}
static irqreturn_t tpm_tis_update_unhandled_irqs(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
irqreturn_t irqret = IRQ_HANDLED;
if (!(chip->flags & TPM_CHIP_FLAG_IRQ))
return IRQ_HANDLED;
if (time_after(jiffies, priv->last_unhandled_irq + HZ/10))
priv->unhandled_irqs = 1;
else
priv->unhandled_irqs++;
priv->last_unhandled_irq = jiffies;
if (priv->unhandled_irqs > TPM_TIS_MAX_UNHANDLED_IRQS)
irqret = tpm_tis_revert_interrupts(chip);
return irqret;
}
static irqreturn_t tis_int_handler(int dummy, void *dev_id)
{
struct tpm_chip *chip = dev_id;
......@@ -761,10 +819,10 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt);
if (rc < 0)
return IRQ_NONE;
goto err;
if (interrupt == 0)
return IRQ_NONE;
goto err;
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
if (interrupt & TPM_INTF_DATA_AVAIL_INT)
......@@ -780,10 +838,13 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt);
tpm_tis_relinquish_locality(chip, 0);
if (rc < 0)
return IRQ_NONE;
goto err;
tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt);
return IRQ_HANDLED;
err:
return tpm_tis_update_unhandled_irqs(chip);
}
static void tpm_tis_gen_interrupt(struct tpm_chip *chip)
......@@ -804,6 +865,15 @@ static void tpm_tis_gen_interrupt(struct tpm_chip *chip)
chip->flags &= ~TPM_CHIP_FLAG_IRQ;
}
static void tpm_tis_free_irq_func(struct work_struct *work)
{
struct tpm_tis_data *priv = container_of(work, typeof(*priv), free_irq_work);
struct tpm_chip *chip = priv->chip;
devm_free_irq(chip->dev.parent, priv->irq, chip);
priv->irq = 0;
}
/* Register the IRQ and issue a command that will cause an interrupt. If an
* irq is seen then leave the chip setup for IRQ operation, otherwise reverse
* everything and leave in polling mode. Returns 0 on success.
......@@ -816,6 +886,7 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
int rc;
u32 int_status;
INIT_WORK(&priv->free_irq_work, tpm_tis_free_irq_func);
rc = devm_request_threaded_irq(chip->dev.parent, irq, NULL,
tis_int_handler, IRQF_ONESHOT | flags,
......@@ -918,6 +989,7 @@ void tpm_tis_remove(struct tpm_chip *chip)
interrupt = 0;
tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt);
flush_work(&priv->free_irq_work);
tpm_tis_clkrun_enable(chip, false);
......@@ -1021,6 +1093,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
chip->timeout_b = msecs_to_jiffies(TIS_TIMEOUT_B_MAX);
chip->timeout_c = msecs_to_jiffies(TIS_TIMEOUT_C_MAX);
chip->timeout_d = msecs_to_jiffies(TIS_TIMEOUT_D_MAX);
priv->chip = chip;
priv->timeout_min = TPM_TIMEOUT_USECS_MIN;
priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
priv->phy_ops = phy_ops;
......@@ -1179,7 +1252,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
rc = tpm_tis_request_locality(chip, 0);
if (rc < 0)
goto out_err;
disable_interrupts(chip);
tpm_tis_disable_interrupts(chip);
tpm_tis_relinquish_locality(chip, 0);
}
}
......
......@@ -91,11 +91,15 @@ enum tpm_tis_flags {
};
struct tpm_tis_data {
struct tpm_chip *chip;
u16 manufacturer_id;
struct mutex locality_count_mutex;
unsigned int locality_count;
int locality;
int irq;
struct work_struct free_irq_work;
unsigned long last_unhandled_irq;
unsigned int unhandled_irqs;
unsigned int int_mask;
unsigned long flags;
void __iomem *ilb_base_addr;
......
......@@ -189,21 +189,28 @@ static int tpm_tis_i2c_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
int ret;
for (i = 0; i < TPM_RETRY; i++) {
/* write register */
msg.len = sizeof(reg);
msg.buf = &reg;
msg.flags = 0;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
/* read data */
msg.buf = result;
msg.len = len;
msg.flags = I2C_M_RD;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
u16 read = 0;
while (read < len) {
/* write register */
msg.len = sizeof(reg);
msg.buf = &reg;
msg.flags = 0;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
/* read data */
msg.buf = result + read;
msg.len = len - read;
msg.flags = I2C_M_RD;
if (msg.len > I2C_SMBUS_BLOCK_MAX)
msg.len = I2C_SMBUS_BLOCK_MAX;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
read += msg.len;
}
ret = tpm_tis_i2c_sanity_check_read(reg, len, result);
if (ret == 0)
......@@ -223,19 +230,27 @@ static int tpm_tis_i2c_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
struct i2c_msg msg = { .addr = phy->i2c_client->addr };
u8 reg = tpm_tis_i2c_address_to_register(addr);
int ret;
u16 wrote = 0;
if (len > TPM_BUFSIZE - 1)
return -EIO;
/* write register and data in one go */
phy->io_buf[0] = reg;
memcpy(phy->io_buf + sizeof(reg), value, len);
msg.len = sizeof(reg) + len;
msg.buf = phy->io_buf;
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
while (wrote < len) {
/* write register and data in one go */
msg.len = sizeof(reg) + len - wrote;
if (msg.len > I2C_SMBUS_BLOCK_MAX)
msg.len = I2C_SMBUS_BLOCK_MAX;
memcpy(phy->io_buf + sizeof(reg), value + wrote,
msg.len - sizeof(reg));
ret = tpm_tis_i2c_retry_transfer_until_ack(data, &msg);
if (ret < 0)
return ret;
wrote += msg.len - sizeof(reg);
}
return 0;
}
......
......@@ -136,6 +136,14 @@ int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
}
exit:
if (ret < 0) {
/* Deactivate chip select */
memset(&spi_xfer, 0, sizeof(spi_xfer));
spi_message_init(&m);
spi_message_add_tail(&spi_xfer, &m);
spi_sync_locked(phy->spi_device, &m);
}
spi_bus_unlock(phy->spi_device->master);
return ret;
}
......
......@@ -683,37 +683,21 @@ static struct miscdevice vtpmx_miscdev = {
.fops = &vtpmx_fops,
};
static int vtpmx_init(void)
{
return misc_register(&vtpmx_miscdev);
}
static void vtpmx_cleanup(void)
{
misc_deregister(&vtpmx_miscdev);
}
static int __init vtpm_module_init(void)
{
int rc;
rc = vtpmx_init();
if (rc) {
pr_err("couldn't create vtpmx device\n");
return rc;
}
workqueue = create_workqueue("tpm-vtpm");
if (!workqueue) {
pr_err("couldn't create workqueue\n");
rc = -ENOMEM;
goto err_vtpmx_cleanup;
return -ENOMEM;
}
return 0;
err_vtpmx_cleanup:
vtpmx_cleanup();
rc = misc_register(&vtpmx_miscdev);
if (rc) {
pr_err("couldn't create vtpmx device\n");
destroy_workqueue(workqueue);
}
return rc;
}
......@@ -721,7 +705,7 @@ static int __init vtpm_module_init(void)
static void __exit vtpm_module_exit(void)
{
destroy_workqueue(workqueue);
vtpmx_cleanup();
misc_deregister(&vtpmx_miscdev);
}
module_init(vtpm_module_init);
......
......@@ -401,17 +401,21 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
if (dest_keyring) {
ret = __key_link_lock(dest_keyring, &ctx->index_key);
ret = __key_link_lock(dest_keyring, &key->index_key);
if (ret < 0)
goto link_lock_failed;
ret = __key_link_begin(dest_keyring, &ctx->index_key, &edit);
if (ret < 0)
goto link_prealloc_failed;
}
/* attach the key to the destination keyring under lock, but we do need
/*
* Attach the key to the destination keyring under lock, but we do need
* to do another check just in case someone beat us to it whilst we
* waited for locks */
* waited for locks.
*
* The caller might specify a comparison function which looks for keys
* that do not exactly match but are still equivalent from the caller's
* perspective. The __key_link_begin() operation must be done only after
* an actual key is determined.
*/
mutex_lock(&key_construction_mutex);
rcu_read_lock();
......@@ -420,12 +424,16 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
if (!IS_ERR(key_ref))
goto key_already_present;
if (dest_keyring)
if (dest_keyring) {
ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
if (ret < 0)
goto link_alloc_failed;
__key_link(dest_keyring, key, &edit);
}
mutex_unlock(&key_construction_mutex);
if (dest_keyring)
__key_link_end(dest_keyring, &ctx->index_key, edit);
__key_link_end(dest_keyring, &key->index_key, edit);
mutex_unlock(&user->cons_lock);
*_key = key;
kleave(" = 0 [%d]", key_serial(key));
......@@ -438,10 +446,13 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
mutex_unlock(&key_construction_mutex);
key = key_ref_to_ptr(key_ref);
if (dest_keyring) {
ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
if (ret < 0)
goto link_alloc_failed_unlocked;
ret = __key_link_check_live_key(dest_keyring, key);
if (ret == 0)
__key_link(dest_keyring, key, &edit);
__key_link_end(dest_keyring, &ctx->index_key, edit);
__key_link_end(dest_keyring, &key->index_key, edit);
if (ret < 0)
goto link_check_failed;
}
......@@ -456,8 +467,10 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
kleave(" = %d [linkcheck]", ret);
return ret;
link_prealloc_failed:
__key_link_end(dest_keyring, &ctx->index_key, edit);
link_alloc_failed:
mutex_unlock(&key_construction_mutex);
link_alloc_failed_unlocked:
__key_link_end(dest_keyring, &key->index_key, edit);
link_lock_failed:
mutex_unlock(&user->cons_lock);
key_put(key);
......
......@@ -186,7 +186,7 @@ int tpm2_key_priv(void *context, size_t hdrlen,
}
/**
* tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
* tpm2_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer.
*
* @buf: an allocated tpm_buf instance
* @session_handle: session handle
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment