Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: - EVM gains support for loading an x509 cert from the kernel (EVM_LOAD_X509), into the EVM trusted kernel keyring. - Smack implements 'file receive' process-based permission checking for sockets, rather than just depending on inode checks. - Misc enhancments for TPM & TPM2. - Cleanups and bugfixes for SELinux, Keys, and IMA. * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (41 commits) selinux: Inode label revalidation performance fix KEYS: refcount bug fix ima: ima_write_policy() limit locking IMA: policy can be updated zero times selinux: rate-limit netlink message warnings in selinux_nlmsg_perm() selinux: export validatetrans decisions gfs2: Invalid security labels of inodes when they go invalid selinux: Revalidate invalid inode security labels security: Add hook to invalidate inode security labels selinux: Add accessor functions for inode->i_security security: Make inode argument of inode_getsecid non-const security: Make inode argument of inode_getsecurity non-const selinux: Remove unused variable in selinux_inode_init_security keys, trusted: seal with a TPM2 authorization policy keys, trusted: select hash algorithm for TPM2 chips keys, trusted: fix: *do not* allow duplicate key options tpm_ibmvtpm: properly handle interrupted packet receptions tpm_tis: Tighten IRQ auto-probing tpm_tis: Refactor the interrupt setup tpm_tis: Get rid of the duplicate IRQ probing code ...
This commit is contained in:
@@ -310,10 +310,12 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
|
||||
{
|
||||
int duration_idx = TPM_UNDEFINED;
|
||||
int duration = 0;
|
||||
u8 category = (ordinal >> 24) & 0xFF;
|
||||
|
||||
if ((category == TPM_PROTECTED_COMMAND && ordinal < TPM_MAX_ORDINAL) ||
|
||||
(category == TPM_CONNECTION_COMMAND && ordinal < TSC_MAX_ORDINAL))
|
||||
/*
|
||||
* We only have a duration table for protected commands, where the upper
|
||||
* 16 bits are 0. For the few other ordinals the fallback will be used.
|
||||
*/
|
||||
if (ordinal < TPM_MAX_ORDINAL)
|
||||
duration_idx = tpm_ordinal_duration[ordinal];
|
||||
|
||||
if (duration_idx != TPM_UNDEFINED)
|
||||
@@ -501,6 +503,21 @@ int tpm_get_timeouts(struct tpm_chip *chip)
|
||||
struct duration_t *duration_cap;
|
||||
ssize_t rc;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
/* Fixed timeouts for TPM2 */
|
||||
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
|
||||
chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
|
||||
chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
|
||||
chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
|
||||
chip->vendor.duration[TPM_SHORT] =
|
||||
msecs_to_jiffies(TPM2_DURATION_SHORT);
|
||||
chip->vendor.duration[TPM_MEDIUM] =
|
||||
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
|
||||
chip->vendor.duration[TPM_LONG] =
|
||||
msecs_to_jiffies(TPM2_DURATION_LONG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tpm_cmd.header.in = tpm_getcap_header;
|
||||
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||
|
||||
@@ -83,16 +83,20 @@ enum tpm2_structures {
|
||||
};
|
||||
|
||||
enum tpm2_return_codes {
|
||||
TPM2_RC_INITIALIZE = 0x0100,
|
||||
TPM2_RC_TESTING = 0x090A,
|
||||
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
|
||||
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
|
||||
TPM2_RC_DISABLED = 0x0120,
|
||||
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
|
||||
};
|
||||
|
||||
enum tpm2_algorithms {
|
||||
TPM2_ALG_SHA1 = 0x0004,
|
||||
TPM2_ALG_KEYEDHASH = 0x0008,
|
||||
TPM2_ALG_SHA256 = 0x000B,
|
||||
TPM2_ALG_NULL = 0x0010
|
||||
TPM2_ALG_SHA384 = 0x000C,
|
||||
TPM2_ALG_SHA512 = 0x000D,
|
||||
TPM2_ALG_NULL = 0x0010,
|
||||
TPM2_ALG_SM3_256 = 0x0012,
|
||||
};
|
||||
|
||||
enum tpm2_command_codes {
|
||||
@@ -138,7 +142,6 @@ struct tpm_vendor_specific {
|
||||
unsigned long base; /* TPM base address */
|
||||
|
||||
int irq;
|
||||
int probed_irq;
|
||||
|
||||
int region_size;
|
||||
int have_region;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "tpm.h"
|
||||
#include <crypto/hash_info.h>
|
||||
#include <keys/trusted-type.h>
|
||||
|
||||
enum tpm2_object_attributes {
|
||||
@@ -104,6 +105,19 @@ struct tpm2_cmd {
|
||||
union tpm2_cmd_params params;
|
||||
} __packed;
|
||||
|
||||
struct tpm2_hash {
|
||||
unsigned int crypto_id;
|
||||
unsigned int tpm_id;
|
||||
};
|
||||
|
||||
static struct tpm2_hash tpm2_hash_map[] = {
|
||||
{HASH_ALGO_SHA1, TPM2_ALG_SHA1},
|
||||
{HASH_ALGO_SHA256, TPM2_ALG_SHA256},
|
||||
{HASH_ALGO_SHA384, TPM2_ALG_SHA384},
|
||||
{HASH_ALGO_SHA512, TPM2_ALG_SHA512},
|
||||
{HASH_ALGO_SM3_256, TPM2_ALG_SM3_256},
|
||||
};
|
||||
|
||||
/*
|
||||
* Array with one entry per ordinal defining the maximum amount
|
||||
* of time the chip could take to return the result. The values
|
||||
@@ -429,8 +443,20 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
||||
{
|
||||
unsigned int blob_len;
|
||||
struct tpm_buf buf;
|
||||
u32 hash;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) {
|
||||
if (options->hash == tpm2_hash_map[i].crypto_id) {
|
||||
hash = tpm2_hash_map[i].tpm_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(tpm2_hash_map))
|
||||
return -EINVAL;
|
||||
|
||||
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_CREATE);
|
||||
if (rc)
|
||||
return rc;
|
||||
@@ -452,12 +478,26 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
||||
tpm_buf_append_u8(&buf, payload->migratable);
|
||||
|
||||
/* public */
|
||||
tpm_buf_append_u16(&buf, 14);
|
||||
if (options->policydigest)
|
||||
tpm_buf_append_u16(&buf, 14 + options->digest_len);
|
||||
else
|
||||
tpm_buf_append_u16(&buf, 14);
|
||||
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_KEYEDHASH);
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_SHA256);
|
||||
tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
|
||||
tpm_buf_append_u16(&buf, 0); /* policy digest size */
|
||||
tpm_buf_append_u16(&buf, hash);
|
||||
|
||||
/* policy */
|
||||
if (options->policydigest) {
|
||||
tpm_buf_append_u32(&buf, 0);
|
||||
tpm_buf_append_u16(&buf, options->digest_len);
|
||||
tpm_buf_append(&buf, options->policydigest,
|
||||
options->digest_len);
|
||||
} else {
|
||||
tpm_buf_append_u32(&buf, TPM2_ATTR_USER_WITH_AUTH);
|
||||
tpm_buf_append_u16(&buf, 0);
|
||||
}
|
||||
|
||||
/* public parameters */
|
||||
tpm_buf_append_u16(&buf, TPM2_ALG_NULL);
|
||||
tpm_buf_append_u16(&buf, 0);
|
||||
|
||||
@@ -488,8 +528,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
|
||||
out:
|
||||
tpm_buf_destroy(&buf);
|
||||
|
||||
if (rc > 0)
|
||||
rc = -EPERM;
|
||||
if (rc > 0) {
|
||||
if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
rc = -EPERM;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -583,7 +627,9 @@ static int tpm2_unseal(struct tpm_chip *chip,
|
||||
return rc;
|
||||
|
||||
tpm_buf_append_u32(&buf, blob_handle);
|
||||
tpm2_buf_append_auth(&buf, TPM2_RS_PW,
|
||||
tpm2_buf_append_auth(&buf,
|
||||
options->policyhandle ?
|
||||
options->policyhandle : TPM2_RS_PW,
|
||||
NULL /* nonce */, 0,
|
||||
0 /* session_attributes */,
|
||||
options->blobauth /* hmac */,
|
||||
|
||||
@@ -284,17 +284,9 @@ static int crb_acpi_add(struct acpi_device *device)
|
||||
|
||||
chip->vendor.priv = priv;
|
||||
|
||||
/* Default timeouts and durations */
|
||||
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
|
||||
chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
|
||||
chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
|
||||
chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
|
||||
chip->vendor.duration[TPM_SHORT] =
|
||||
msecs_to_jiffies(TPM2_DURATION_SHORT);
|
||||
chip->vendor.duration[TPM_MEDIUM] =
|
||||
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
|
||||
chip->vendor.duration[TPM_LONG] =
|
||||
msecs_to_jiffies(TPM2_DURATION_LONG);
|
||||
rc = tpm_get_timeouts(chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
chip->acpi_dev_handle = device->handle;
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0);
|
||||
sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
|
||||
if (sig)
|
||||
return -EINTR;
|
||||
|
||||
@@ -125,7 +125,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
struct ibmvtpm_dev *ibmvtpm;
|
||||
struct ibmvtpm_crq crq;
|
||||
__be64 *word = (__be64 *)&crq;
|
||||
int rc;
|
||||
int rc, sig;
|
||||
|
||||
ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
|
||||
|
||||
@@ -141,18 +141,35 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ibmvtpm->tpm_processing_cmd) {
|
||||
dev_info(ibmvtpm->dev,
|
||||
"Need to wait for TPM to finish\n");
|
||||
/* wait for previous command to finish */
|
||||
sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
|
||||
if (sig)
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
spin_lock(&ibmvtpm->rtce_lock);
|
||||
ibmvtpm->res_len = 0;
|
||||
memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
|
||||
crq.valid = (u8)IBMVTPM_VALID_CMD;
|
||||
crq.msg = (u8)VTPM_TPM_COMMAND;
|
||||
crq.len = cpu_to_be16(count);
|
||||
crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
|
||||
|
||||
/*
|
||||
* set the processing flag before the Hcall, since we may get the
|
||||
* result (interrupt) before even being able to check rc.
|
||||
*/
|
||||
ibmvtpm->tpm_processing_cmd = true;
|
||||
|
||||
rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
|
||||
be64_to_cpu(word[1]));
|
||||
if (rc != H_SUCCESS) {
|
||||
dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
|
||||
rc = 0;
|
||||
ibmvtpm->tpm_processing_cmd = false;
|
||||
} else
|
||||
rc = count;
|
||||
|
||||
@@ -515,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
|
||||
case VTPM_TPM_COMMAND_RES:
|
||||
/* len of the data in rtce buffer */
|
||||
ibmvtpm->res_len = be16_to_cpu(crq->len);
|
||||
ibmvtpm->tpm_processing_cmd = false;
|
||||
wake_up_interruptible(&ibmvtpm->wq);
|
||||
return;
|
||||
default:
|
||||
|
||||
@@ -45,6 +45,7 @@ struct ibmvtpm_dev {
|
||||
wait_queue_head_t wq;
|
||||
u16 res_len;
|
||||
u32 vtpm_version;
|
||||
bool tpm_processing_cmd;
|
||||
};
|
||||
|
||||
#define CRQ_RES_BUF_SIZE PAGE_SIZE
|
||||
|
||||
+109
-147
@@ -401,7 +401,7 @@ static void disable_interrupts(struct tpm_chip *chip)
|
||||
iowrite32(intmask,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
free_irq(chip->vendor.irq, chip);
|
||||
devm_free_irq(chip->pdev, chip->vendor.irq, chip);
|
||||
chip->vendor.irq = 0;
|
||||
}
|
||||
|
||||
@@ -461,11 +461,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
chip->vendor.irq = irq;
|
||||
if (!priv->irq_tested)
|
||||
msleep(1);
|
||||
if (!priv->irq_tested) {
|
||||
if (!priv->irq_tested)
|
||||
disable_interrupts(chip);
|
||||
dev_err(chip->pdev,
|
||||
FW_BUG "TPM interrupt not working, polling instead\n");
|
||||
}
|
||||
priv->irq_tested = true;
|
||||
return rc;
|
||||
}
|
||||
@@ -570,26 +567,6 @@ static const struct tpm_class_ops tpm_tis = {
|
||||
.req_canceled = tpm_tis_req_canceled,
|
||||
};
|
||||
|
||||
static irqreturn_t tis_int_probe(int irq, void *dev_id)
|
||||
{
|
||||
struct tpm_chip *chip = dev_id;
|
||||
u32 interrupt;
|
||||
|
||||
interrupt = ioread32(chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality));
|
||||
|
||||
if (interrupt == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
chip->vendor.probed_irq = irq;
|
||||
|
||||
/* Clear interrupts handled with TPM_EOI */
|
||||
iowrite32(interrupt,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||
{
|
||||
struct tpm_chip *chip = dev_id;
|
||||
@@ -622,6 +599,84 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
|
||||
int flags, int irq)
|
||||
{
|
||||
struct priv_data *priv = chip->vendor.priv;
|
||||
u8 original_int_vec;
|
||||
|
||||
if (devm_request_irq(chip->pdev, irq, tis_int_handler, flags,
|
||||
chip->devname, chip) != 0) {
|
||||
dev_info(chip->pdev, "Unable to request irq: %d for probe\n",
|
||||
irq);
|
||||
return -1;
|
||||
}
|
||||
chip->vendor.irq = irq;
|
||||
|
||||
original_int_vec = ioread8(chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
iowrite8(irq,
|
||||
chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality));
|
||||
|
||||
/* Clear all existing */
|
||||
iowrite32(ioread32(chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality)),
|
||||
chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
|
||||
|
||||
/* Turn on */
|
||||
iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
|
||||
chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
|
||||
|
||||
priv->irq_tested = false;
|
||||
|
||||
/* Generate an interrupt by having the core call through to
|
||||
* tpm_tis_send
|
||||
*/
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
tpm2_gen_interrupt(chip);
|
||||
else
|
||||
tpm_gen_interrupt(chip);
|
||||
|
||||
/* tpm_tis_send will either confirm the interrupt is working or it
|
||||
* will call disable_irq which undoes all of the above.
|
||||
*/
|
||||
if (!chip->vendor.irq) {
|
||||
iowrite8(original_int_vec,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to find the IRQ the TPM is using. This is for legacy x86 systems that
|
||||
* do not have ACPI/etc. We typically expect the interrupt to be declared if
|
||||
* present.
|
||||
*/
|
||||
static void tpm_tis_probe_irq(struct tpm_chip *chip, u32 intmask)
|
||||
{
|
||||
u8 original_int_vec;
|
||||
int i;
|
||||
|
||||
original_int_vec = ioread8(chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
|
||||
if (!original_int_vec) {
|
||||
if (IS_ENABLED(CONFIG_X86))
|
||||
for (i = 3; i <= 15; i++)
|
||||
if (!tpm_tis_probe_irq_single(chip, intmask, 0,
|
||||
i))
|
||||
return;
|
||||
} else if (!tpm_tis_probe_irq_single(chip, intmask, 0,
|
||||
original_int_vec))
|
||||
return;
|
||||
}
|
||||
|
||||
static bool interrupts = true;
|
||||
module_param(interrupts, bool, 0444);
|
||||
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
||||
@@ -644,8 +699,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
|
||||
acpi_handle acpi_dev_handle)
|
||||
{
|
||||
u32 vendor, intfcaps, intmask;
|
||||
int rc, i, irq_s, irq_e, probe;
|
||||
int irq_r = -1;
|
||||
int rc, probe;
|
||||
struct tpm_chip *chip;
|
||||
struct priv_data *priv;
|
||||
|
||||
@@ -677,6 +731,15 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Take control of the TPM's interrupt hardware and shut it off */
|
||||
intmask = ioread32(chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
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;
|
||||
iowrite32(intmask,
|
||||
chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
|
||||
|
||||
if (request_locality(chip, 0) != 0) {
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
@@ -731,126 +794,31 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
|
||||
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
|
||||
dev_dbg(dev, "\tData Avail Int Support\n");
|
||||
|
||||
/* Very early on issue a command to the TPM in polling mode to make
|
||||
* sure it works. May as well use that command to set the proper
|
||||
* timeouts for the driver.
|
||||
*/
|
||||
if (tpm_get_timeouts(chip)) {
|
||||
dev_err(dev, "Could not get TPM timeouts and durations\n");
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* INTERRUPT Setup */
|
||||
init_waitqueue_head(&chip->vendor.read_queue);
|
||||
init_waitqueue_head(&chip->vendor.int_queue);
|
||||
|
||||
intmask =
|
||||
ioread32(chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
|
||||
intmask |= TPM_INTF_CMD_READY_INT
|
||||
| TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
|
||||
| TPM_INTF_STS_VALID_INT;
|
||||
|
||||
iowrite32(intmask,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
if (interrupts)
|
||||
chip->vendor.irq = tpm_info->irq;
|
||||
if (interrupts && !chip->vendor.irq) {
|
||||
irq_s =
|
||||
ioread8(chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
irq_r = irq_s;
|
||||
if (irq_s) {
|
||||
irq_e = irq_s;
|
||||
} else {
|
||||
irq_s = 3;
|
||||
irq_e = 15;
|
||||
}
|
||||
|
||||
for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
|
||||
iowrite8(i, chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
if (devm_request_irq
|
||||
(dev, i, tis_int_probe, IRQF_SHARED,
|
||||
chip->devname, chip) != 0) {
|
||||
dev_info(chip->pdev,
|
||||
"Unable to request irq: %d for probe\n",
|
||||
i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Clear all existing */
|
||||
iowrite32(ioread32
|
||||
(chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality)),
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality));
|
||||
|
||||
/* Turn on */
|
||||
iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
|
||||
chip->vendor.probed_irq = 0;
|
||||
|
||||
/* Generate Interrupts */
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
tpm2_gen_interrupt(chip);
|
||||
else
|
||||
tpm_gen_interrupt(chip);
|
||||
|
||||
chip->vendor.irq = chip->vendor.probed_irq;
|
||||
|
||||
/* free_irq will call into tis_int_probe;
|
||||
clear all irqs we haven't seen while doing
|
||||
tpm_gen_interrupt */
|
||||
iowrite32(ioread32
|
||||
(chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality)),
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality));
|
||||
|
||||
/* Turn off */
|
||||
iowrite32(intmask,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
|
||||
devm_free_irq(dev, i, chip);
|
||||
}
|
||||
if (interrupts) {
|
||||
if (tpm_info->irq) {
|
||||
tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
|
||||
tpm_info->irq);
|
||||
if (!chip->vendor.irq)
|
||||
dev_err(chip->pdev, FW_BUG
|
||||
"TPM interrupt not working, polling instead\n");
|
||||
} else
|
||||
tpm_tis_probe_irq(chip, intmask);
|
||||
}
|
||||
if (chip->vendor.irq) {
|
||||
iowrite8(chip->vendor.irq,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
if (devm_request_irq
|
||||
(dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
|
||||
chip->devname, chip) != 0) {
|
||||
dev_info(chip->pdev,
|
||||
"Unable to request irq: %d for use\n",
|
||||
chip->vendor.irq);
|
||||
chip->vendor.irq = 0;
|
||||
} else {
|
||||
/* Clear all existing */
|
||||
iowrite32(ioread32
|
||||
(chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality)),
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_STATUS(chip->vendor.locality));
|
||||
|
||||
/* Turn on */
|
||||
iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
|
||||
chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
}
|
||||
} else if (irq_r != -1)
|
||||
iowrite8(irq_r, chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
|
||||
chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
|
||||
chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
|
||||
chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
|
||||
chip->vendor.duration[TPM_SHORT] =
|
||||
msecs_to_jiffies(TPM2_DURATION_SHORT);
|
||||
chip->vendor.duration[TPM_MEDIUM] =
|
||||
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
|
||||
chip->vendor.duration[TPM_LONG] =
|
||||
msecs_to_jiffies(TPM2_DURATION_LONG);
|
||||
|
||||
rc = tpm2_do_selftest(chip);
|
||||
if (rc == TPM2_RC_INITIALIZE) {
|
||||
dev_warn(dev, "Firmware has not started TPM\n");
|
||||
@@ -866,12 +834,6 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
|
||||
goto out_err;
|
||||
}
|
||||
} else {
|
||||
if (tpm_get_timeouts(chip)) {
|
||||
dev_err(dev, "Could not get TPM timeouts and durations\n");
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (tpm_do_selftest(chip)) {
|
||||
dev_err(dev, "TPM self test failed\n");
|
||||
rc = -ENODEV;
|
||||
|
||||
Reference in New Issue
Block a user