diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-11 21:58:41 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-11 21:58:41 +0100 |
commit | dabd40ecaf693a18afd4c59c8d7280610d95b66e (patch) | |
tree | 880b7680689a44b6e514508d30de36295fe2e700 /drivers/char | |
parent | Merge branch 'pcmcia-next' of git://git.kernel.org/pub/scm/linux/kernel/git/b... (diff) | |
parent | lib: remove redundant assignment to variable ret (diff) | |
download | linux-dabd40ecaf693a18afd4c59c8d7280610d95b66e.tar.xz linux-dabd40ecaf693a18afd4c59c8d7280610d95b66e.zip |
Merge tag 'tpmdd-next-v5.17-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd
Pull TPM updates from Jarkko Sakkinen:
"Other than bug fixes for TPM, this includes a patch for asymmetric
keys to allow to look up and verify with self-signed certificates
(keys without so called AKID - Authority Key Identifier) using a new
"dn:" prefix in the query"
* tag 'tpmdd-next-v5.17-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
lib: remove redundant assignment to variable ret
tpm: fix NPE on probe for missing device
tpm: fix potential NULL pointer access in tpm_del_char_device
tpm: Add Upgrade/Reduced mode support for TPM2 modules
char: tpm: cr50: Set TPM_FIRMWARE_POWER_MANAGED based on device property
keys: X.509 public key issuer lookup without AKID
tpm_tis: Fix an error handling path in 'tpm_tis_core_init()'
tpm: tpm_tis_spi_cr50: Add default RNG quality
tpm/st33zp24: drop unneeded over-commenting
tpm: add request_locality before write TPM_INT_ENABLE
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/tpm/st33zp24/st33zp24.c | 122 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 37 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-sysfs.c | 3 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 6 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.c | 14 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_i2c_cr50.c | 16 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_spi_cr50.c | 20 |
7 files changed, 96 insertions, 122 deletions
diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 4ec10ab5e576..ce9efb73c144 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -61,9 +61,7 @@ enum tis_defaults { }; /* - * clear_interruption clear the pending interrupt. - * @param: tpm_dev, the tpm device device. - * @return: the interrupt status value. + * clear the pending interrupt. */ static u8 clear_interruption(struct st33zp24_dev *tpm_dev) { @@ -72,12 +70,10 @@ static u8 clear_interruption(struct st33zp24_dev *tpm_dev) tpm_dev->ops->recv(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1); tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1); return interrupt; -} /* clear_interruption() */ +} /* - * st33zp24_cancel, cancel the current command execution or - * set STS to COMMAND READY. - * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h + * cancel the current command execution or set STS to COMMAND READY. */ static void st33zp24_cancel(struct tpm_chip *chip) { @@ -86,12 +82,10 @@ static void st33zp24_cancel(struct tpm_chip *chip) data = TPM_STS_COMMAND_READY; tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1); -} /* st33zp24_cancel() */ +} /* - * st33zp24_status return the TPM_STS register - * @param: chip, the tpm chip description - * @return: the TPM_STS register value. + * return the TPM_STS register */ static u8 st33zp24_status(struct tpm_chip *chip) { @@ -100,12 +94,10 @@ static u8 st33zp24_status(struct tpm_chip *chip) tpm_dev->ops->recv(tpm_dev->phy_id, TPM_STS, &data, 1); return data; -} /* st33zp24_status() */ +} /* - * check_locality if the locality is active - * @param: chip, the tpm chip description - * @return: true if LOCALITY0 is active, otherwise false + * if the locality is active */ static bool check_locality(struct tpm_chip *chip) { @@ -120,13 +112,8 @@ static bool check_locality(struct tpm_chip *chip) return true; return false; -} /* check_locality() */ +} -/* - * request_locality request the TPM locality - * @param: chip, the chip description - * @return: the active locality or negative value. - */ static int request_locality(struct tpm_chip *chip) { struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); @@ -153,12 +140,8 @@ static int request_locality(struct tpm_chip *chip) /* could not get locality */ return -EACCES; -} /* request_locality() */ +} -/* - * release_locality release the active locality - * @param: chip, the tpm chip description. - */ static void release_locality(struct tpm_chip *chip) { struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); @@ -171,8 +154,6 @@ static void release_locality(struct tpm_chip *chip) /* * get_burstcount return the burstcount value - * @param: chip, the chip description - * return: the burstcount or negative value. */ static int get_burstcount(struct tpm_chip *chip) { @@ -200,18 +181,8 @@ static int get_burstcount(struct tpm_chip *chip) msleep(TPM_TIMEOUT); } while (time_before(jiffies, stop)); return -EBUSY; -} /* get_burstcount() */ - +} -/* - * wait_for_tpm_stat_cond - * @param: chip, chip description - * @param: mask, expected mask value - * @param: check_cancel, does the command expected to be canceled ? - * @param: canceled, did we received a cancel request ? - * @return: true if status == mask or if the command is canceled. - * false in other cases. - */ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel, bool *canceled) { @@ -228,13 +199,7 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, } /* - * wait_for_stat wait for a TPM_STS value - * @param: chip, the tpm chip description - * @param: mask, the value mask to wait - * @param: timeout, the timeout - * @param: queue, the wait queue. - * @param: check_cancel, does the command can be cancelled ? - * @return: the tpm status, 0 if success, -ETIME if timeout is reached. + * wait for a TPM_STS value */ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, wait_queue_head_t *queue, bool check_cancel) @@ -292,15 +257,8 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, } return -ETIME; -} /* wait_for_stat() */ +} -/* - * recv_data receive data - * @param: chip, the tpm chip description - * @param: buf, the buffer where the data are received - * @param: count, the number of data to receive - * @return: the number of bytes read from TPM FIFO. - */ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev); @@ -325,12 +283,6 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) return size; } -/* - * tpm_ioserirq_handler the serirq irq handler - * @param: irq, the tpm chip description - * @param: dev_id, the description of the chip - * @return: the status of the handler. - */ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) { struct tpm_chip *chip = dev_id; @@ -341,16 +293,10 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id) disable_irq_nosync(tpm_dev->irq); return IRQ_HANDLED; -} /* tpm_ioserirq_handler() */ +} /* - * st33zp24_send send TPM commands through the I2C bus. - * - * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h - * @param: buf, the buffer to send. - * @param: count, the number of bytes to send. - * @return: In case of success the number of bytes sent. - * In other case, a < 0 value describing the issue. + * send TPM commands through the I2C bus. */ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf, size_t len) @@ -431,14 +377,6 @@ out_err: return ret; } -/* - * st33zp24_recv received TPM response through TPM phy. - * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. - * @param: buf, the buffer to store datas. - * @param: count, the number of bytes to send. - * @return: In case of success the number of bytes received. - * In other case, a < 0 value describing the issue. - */ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, size_t count) { @@ -478,12 +416,6 @@ out: return size; } -/* - * st33zp24_req_canceled - * @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h. - * @param: status, the TPM status. - * @return: Does TPM ready to compute a new command ? true. - */ static bool st33zp24_req_canceled(struct tpm_chip *chip, u8 status) { return (status == TPM_STS_COMMAND_READY); @@ -501,11 +433,7 @@ static const struct tpm_class_ops st33zp24_tpm = { }; /* - * st33zp24_probe initialize the TPM device - * @param: client, the i2c_client description (TPM I2C description). - * @param: id, the i2c_device_id struct. - * @return: 0 in case of success. - * -1 in other case. + * initialize the TPM device */ int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops, struct device *dev, int irq, int io_lpcpd) @@ -583,11 +511,6 @@ _tpm_clean_answer: } EXPORT_SYMBOL(st33zp24_probe); -/* - * st33zp24_remove remove the TPM device - * @param: tpm_data, the tpm phy. - * @return: 0 in case of success. - */ int st33zp24_remove(struct tpm_chip *chip) { tpm_chip_unregister(chip); @@ -596,12 +519,6 @@ int st33zp24_remove(struct tpm_chip *chip) EXPORT_SYMBOL(st33zp24_remove); #ifdef CONFIG_PM_SLEEP -/* - * st33zp24_pm_suspend suspend the TPM device - * @param: tpm_data, the tpm phy. - * @param: mesg, the power management message. - * @return: 0 in case of success. - */ int st33zp24_pm_suspend(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); @@ -615,14 +532,9 @@ int st33zp24_pm_suspend(struct device *dev) ret = tpm_pm_suspend(dev); return ret; -} /* st33zp24_pm_suspend() */ +} EXPORT_SYMBOL(st33zp24_pm_suspend); -/* - * st33zp24_pm_resume resume the TPM device - * @param: tpm_data, the tpm phy. - * @return: 0 in case of success. - */ int st33zp24_pm_resume(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); @@ -640,7 +552,7 @@ int st33zp24_pm_resume(struct device *dev) tpm1_do_selftest(chip); } return ret; -} /* st33zp24_pm_resume() */ +} EXPORT_SYMBOL(st33zp24_pm_resume); #endif diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index ddaeceb7e109..b009e7479b70 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -444,7 +444,7 @@ static int tpm_add_char_device(struct tpm_chip *chip) return rc; } - if (chip->flags & TPM_CHIP_FLAG_TPM2) { + if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) { rc = cdev_device_add(&chip->cdevs, &chip->devs); if (rc) { dev_err(&chip->devs, @@ -474,13 +474,21 @@ static void tpm_del_char_device(struct tpm_chip *chip) /* Make the driver uncallable. */ down_write(&chip->ops_sem); - if (chip->flags & TPM_CHIP_FLAG_TPM2) { - if (!tpm_chip_start(chip)) { - tpm2_shutdown(chip, TPM2_SU_CLEAR); - tpm_chip_stop(chip); + + /* + * Check if chip->ops is still valid: In case that the controller + * drivers shutdown handler unregisters the controller in its + * shutdown handler we are called twice and chip->ops to NULL. + */ + if (chip->ops) { + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + if (!tpm_chip_start(chip)) { + tpm2_shutdown(chip, TPM2_SU_CLEAR); + tpm_chip_stop(chip); + } } + chip->ops = NULL; } - chip->ops = NULL; up_write(&chip->ops_sem); } @@ -488,7 +496,8 @@ static void tpm_del_legacy_sysfs(struct tpm_chip *chip) { struct attribute **i; - if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL)) + if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) || + tpm_is_firmware_upgrade(chip)) return; sysfs_remove_link(&chip->dev.parent->kobj, "ppi"); @@ -506,7 +515,8 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) struct attribute **i; int rc; - if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL)) + if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) || + tpm_is_firmware_upgrade(chip)) return 0; rc = compat_only_sysfs_link_entry_to_kobj( @@ -536,7 +546,7 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) static int tpm_add_hwrng(struct tpm_chip *chip) { - if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip)) return 0; snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), @@ -550,6 +560,9 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip) { int rc; + if (tpm_is_firmware_upgrade(chip)) + return 0; + rc = (chip->flags & TPM_CHIP_FLAG_TPM2) ? tpm2_get_pcr_allocation(chip) : tpm1_get_pcr_allocation(chip); @@ -612,7 +625,7 @@ int tpm_chip_register(struct tpm_chip *chip) return 0; out_hwrng: - if (IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip)) hwrng_unregister(&chip->hwrng); out_ppi: tpm_bios_log_teardown(chip); @@ -637,10 +650,10 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); void tpm_chip_unregister(struct tpm_chip *chip) { tpm_del_legacy_sysfs(chip); - if (IS_ENABLED(CONFIG_HW_RANDOM_TPM)) + if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip)) hwrng_unregister(&chip->hwrng); tpm_bios_log_teardown(chip); - if (chip->flags & TPM_CHIP_FLAG_TPM2) + if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) cdev_device_del(&chip->cdevs, &chip->devs); tpm_del_char_device(chip); } diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 63f03cfb8e6a..54c71473aa29 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -480,6 +480,9 @@ void tpm_sysfs_add_device(struct tpm_chip *chip) WARN_ON(chip->groups_cnt != 0); + if (tpm_is_firmware_upgrade(chip)) + return; + if (chip->flags & TPM_CHIP_FLAG_TPM2) chip->groups[chip->groups_cnt++] = &tpm2_dev_group; else diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index a25815a6f625..4704fa553098 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -745,6 +745,12 @@ int tpm2_auto_startup(struct tpm_chip *chip) rc = tpm2_get_cc_attrs_tbl(chip); out: + if (rc == TPM2_RC_UPGRADE) { + dev_info(&chip->dev, "TPM in field upgrade mode, requires firmware upgrade\n"); + chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE; + rc = 0; + } + if (rc > 0) rc = -ENODEV; return rc; diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index b2659a4c4016..dc56b976d816 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -950,9 +950,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, priv->timeout_max = TPM_TIMEOUT_USECS_MAX; priv->phy_ops = phy_ops; + dev_set_drvdata(&chip->dev, priv); + rc = tpm_tis_read32(priv, TPM_DID_VID(0), &vendor); if (rc < 0) - goto out_err; + return rc; priv->manufacturer_id = vendor; @@ -962,8 +964,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, priv->timeout_max = TIS_TIMEOUT_MAX_ATML; } - dev_set_drvdata(&chip->dev, priv); - if (is_bsw()) { priv->ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR, ILB_REMAP_SIZE); @@ -994,7 +994,15 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT; intmask &= ~TPM_GLOBAL_INT_ENABLE; + + rc = request_locality(chip, 0); + if (rc < 0) { + rc = -ENODEV; + goto out_err; + } + tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); + release_locality(chip, 0); rc = tpm_chip_start(chip); if (rc) diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index c89278103703..f6c0affbb456 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -628,6 +628,19 @@ static bool tpm_cr50_i2c_req_canceled(struct tpm_chip *chip, u8 status) return status == TPM_STS_COMMAND_READY; } +static bool tpm_cr50_i2c_is_firmware_power_managed(struct device *dev) +{ + u8 val; + int ret; + + /* This flag should default true when the device property is not present */ + ret = device_property_read_u8(dev, "firmware-power-managed", &val); + if (ret) + return true; + + return val; +} + static const struct tpm_class_ops cr50_i2c = { .flags = TPM_OPS_AUTO_STARTUP, .status = &tpm_cr50_i2c_tis_status, @@ -686,7 +699,8 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client) /* cr50 is a TPM 2.0 chip */ chip->flags |= TPM_CHIP_FLAG_TPM2; - chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED; + if (tpm_cr50_i2c_is_firmware_power_managed(dev)) + chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED; /* Default timeouts */ chip->timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); diff --git a/drivers/char/tpm/tpm_tis_spi_cr50.c b/drivers/char/tpm/tpm_tis_spi_cr50.c index ea759af25634..7bf123d3c537 100644 --- a/drivers/char/tpm/tpm_tis_spi_cr50.c +++ b/drivers/char/tpm/tpm_tis_spi_cr50.c @@ -36,6 +36,9 @@ #define TPM_CR50_FW_VER(l) (0x0f90 | ((l) << 12)) #define TPM_CR50_MAX_FW_VER_LEN 64 +/* Default quality for hwrng. */ +#define TPM_CR50_DEFAULT_RNG_QUALITY 700 + struct cr50_spi_phy { struct tpm_tis_spi_phy spi_phy; @@ -182,6 +185,19 @@ static int cr50_spi_flow_control(struct tpm_tis_spi_phy *phy, return 0; } +static bool tpm_cr50_spi_is_firmware_power_managed(struct device *dev) +{ + u8 val; + int ret; + + /* This flag should default true when the device property is not present */ + ret = device_property_read_u8(dev, "firmware-power-managed", &val); + if (ret) + return true; + + return val; +} + static int tpm_tis_spi_cr50_transfer(struct tpm_tis_data *data, u32 addr, u16 len, u8 *in, const u8 *out) { @@ -264,6 +280,7 @@ int cr50_spi_probe(struct spi_device *spi) phy = &cr50_phy->spi_phy; phy->flow_control = cr50_spi_flow_control; phy->wake_after = jiffies; + phy->priv.rng_quality = TPM_CR50_DEFAULT_RNG_QUALITY; init_completion(&phy->ready); cr50_phy->access_delay = CR50_NOIRQ_ACCESS_DELAY; @@ -305,7 +322,8 @@ int cr50_spi_probe(struct spi_device *spi) cr50_print_fw_version(&phy->priv); chip = dev_get_drvdata(&spi->dev); - chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED; + if (tpm_cr50_spi_is_firmware_power_managed(&spi->dev)) + chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED; return 0; } |