mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 11:11:45 -04:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (54 commits) tpm_nsc: Fix bug when loading multiple TPM drivers tpm: Move tpm_tis_reenable_interrupts out of CONFIG_PNP block tpm: Fix compilation warning when CONFIG_PNP is not defined TOMOYO: Update kernel-doc. tpm: Fix a typo tpm_tis: Probing function for Intel iTPM bug tpm_tis: Fix the probing for interrupts tpm_tis: Delay ACPI S3 suspend while the TPM is busy tpm_tis: Re-enable interrupts upon (S3) resume tpm: Fix display of data in pubek sysfs entry tpm_tis: Add timeouts sysfs entry tpm: Adjust interface timeouts if they are too small tpm: Use interface timeouts returned from the TPM tpm_tis: Introduce durations sysfs entry tpm: Adjust the durations if they are too small tpm: Use durations returned from TPM TOMOYO: Enable conditional ACL. TOMOYO: Allow using argv[]/envp[] of execve() as conditions. TOMOYO: Allow using executable's realpath and symlink's target as conditions. TOMOYO: Allow using owner/group etc. of file objects as conditions. ... Fix up trivial conflict in security/tomoyo/realpath.c
This commit is contained in:
commit
95b6886526
36 changed files with 6487 additions and 2843 deletions
|
|
@ -534,6 +534,7 @@ void tpm_get_timeouts(struct tpm_chip *chip)
|
|||
struct duration_t *duration_cap;
|
||||
ssize_t rc;
|
||||
u32 timeout;
|
||||
unsigned int scale = 1;
|
||||
|
||||
tpm_cmd.header.in = tpm_getcap_header;
|
||||
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
||||
|
|
@ -545,24 +546,30 @@ void tpm_get_timeouts(struct tpm_chip *chip)
|
|||
if (rc)
|
||||
goto duration;
|
||||
|
||||
if (be32_to_cpu(tpm_cmd.header.out.length)
|
||||
!= 4 * sizeof(u32))
|
||||
goto duration;
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
|
||||
be32_to_cpu(tpm_cmd.header.out.length)
|
||||
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
|
||||
return;
|
||||
|
||||
timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
|
||||
/* Don't overwrite default if value is 0 */
|
||||
timeout = be32_to_cpu(timeout_cap->a);
|
||||
if (timeout && timeout < 1000) {
|
||||
/* timeouts in msec rather usec */
|
||||
scale = 1000;
|
||||
chip->vendor.timeout_adjusted = true;
|
||||
}
|
||||
if (timeout)
|
||||
chip->vendor.timeout_a = usecs_to_jiffies(timeout);
|
||||
chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale);
|
||||
timeout = be32_to_cpu(timeout_cap->b);
|
||||
if (timeout)
|
||||
chip->vendor.timeout_b = usecs_to_jiffies(timeout);
|
||||
chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale);
|
||||
timeout = be32_to_cpu(timeout_cap->c);
|
||||
if (timeout)
|
||||
chip->vendor.timeout_c = usecs_to_jiffies(timeout);
|
||||
chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale);
|
||||
timeout = be32_to_cpu(timeout_cap->d);
|
||||
if (timeout)
|
||||
chip->vendor.timeout_d = usecs_to_jiffies(timeout);
|
||||
chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale);
|
||||
|
||||
duration:
|
||||
tpm_cmd.header.in = tpm_getcap_header;
|
||||
|
|
@ -575,23 +582,31 @@ duration:
|
|||
if (rc)
|
||||
return;
|
||||
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code)
|
||||
!= 3 * sizeof(u32))
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
|
||||
be32_to_cpu(tpm_cmd.header.out.length)
|
||||
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
|
||||
return;
|
||||
|
||||
duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
|
||||
chip->vendor.duration[TPM_SHORT] =
|
||||
usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short));
|
||||
/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
|
||||
* value wrong and apparently reports msecs rather than usecs. So we
|
||||
* fix up the resulting too-small TPM_SHORT value to make things work.
|
||||
*/
|
||||
if (chip->vendor.duration[TPM_SHORT] < (HZ/100))
|
||||
chip->vendor.duration[TPM_SHORT] = HZ;
|
||||
|
||||
chip->vendor.duration[TPM_MEDIUM] =
|
||||
usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium));
|
||||
chip->vendor.duration[TPM_LONG] =
|
||||
usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long));
|
||||
|
||||
/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
|
||||
* value wrong and apparently reports msecs rather than usecs. So we
|
||||
* fix up the resulting too-small TPM_SHORT value to make things work.
|
||||
* We also scale the TPM_MEDIUM and -_LONG values by 1000.
|
||||
*/
|
||||
if (chip->vendor.duration[TPM_SHORT] < (HZ / 100)) {
|
||||
chip->vendor.duration[TPM_SHORT] = HZ;
|
||||
chip->vendor.duration[TPM_MEDIUM] *= 1000;
|
||||
chip->vendor.duration[TPM_LONG] *= 1000;
|
||||
chip->vendor.duration_adjusted = true;
|
||||
dev_info(chip->dev, "Adjusting TPM timeout parameters.");
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_get_timeouts);
|
||||
|
||||
|
|
@ -600,7 +615,7 @@ void tpm_continue_selftest(struct tpm_chip *chip)
|
|||
u8 data[] = {
|
||||
0, 193, /* TPM_TAG_RQU_COMMAND */
|
||||
0, 0, 0, 10, /* length */
|
||||
0, 0, 0, 83, /* TPM_ORD_GetCapability */
|
||||
0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */
|
||||
};
|
||||
|
||||
tpm_transmit(chip, data, sizeof(data));
|
||||
|
|
@ -863,18 +878,24 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
|
|||
data = tpm_cmd.params.readpubek_out_buffer;
|
||||
str +=
|
||||
sprintf(str,
|
||||
"Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
|
||||
"Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
|
||||
" %02X %02X %02X %02X %02X %02X %02X %02X\n"
|
||||
"Modulus length: %d\nModulus: \n",
|
||||
data[10], data[11], data[12], data[13], data[14],
|
||||
data[15], data[16], data[17], data[22], data[23],
|
||||
data[24], data[25], data[26], data[27], data[28],
|
||||
data[29], data[30], data[31], data[32], data[33],
|
||||
be32_to_cpu(*((__be32 *) (data + 34))));
|
||||
"Algorithm: %02X %02X %02X %02X\n"
|
||||
"Encscheme: %02X %02X\n"
|
||||
"Sigscheme: %02X %02X\n"
|
||||
"Parameters: %02X %02X %02X %02X "
|
||||
"%02X %02X %02X %02X "
|
||||
"%02X %02X %02X %02X\n"
|
||||
"Modulus length: %d\n"
|
||||
"Modulus:\n",
|
||||
data[0], data[1], data[2], data[3],
|
||||
data[4], data[5],
|
||||
data[6], data[7],
|
||||
data[12], data[13], data[14], data[15],
|
||||
data[16], data[17], data[18], data[19],
|
||||
data[20], data[21], data[22], data[23],
|
||||
be32_to_cpu(*((__be32 *) (data + 24))));
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
str += sprintf(str, "%02X ", data[i + 38]);
|
||||
str += sprintf(str, "%02X ", data[i + 28]);
|
||||
if ((i + 1) % 16 == 0)
|
||||
str += sprintf(str, "\n");
|
||||
}
|
||||
|
|
@ -937,6 +958,35 @@ ssize_t tpm_show_caps_1_2(struct device * dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_show_caps_1_2);
|
||||
|
||||
ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d %d %d [%s]\n",
|
||||
jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]),
|
||||
jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]),
|
||||
jiffies_to_usecs(chip->vendor.duration[TPM_LONG]),
|
||||
chip->vendor.duration_adjusted
|
||||
? "adjusted" : "original");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_show_durations);
|
||||
|
||||
ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d %d %d %d [%s]\n",
|
||||
jiffies_to_usecs(chip->vendor.timeout_a),
|
||||
jiffies_to_usecs(chip->vendor.timeout_b),
|
||||
jiffies_to_usecs(chip->vendor.timeout_c),
|
||||
jiffies_to_usecs(chip->vendor.timeout_d),
|
||||
chip->vendor.timeout_adjusted
|
||||
? "adjusted" : "original");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_show_timeouts);
|
||||
|
||||
ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr,
|
|||
char *);
|
||||
extern ssize_t tpm_show_temp_deactivated(struct device *,
|
||||
struct device_attribute *attr, char *);
|
||||
extern ssize_t tpm_show_durations(struct device *,
|
||||
struct device_attribute *attr, char *);
|
||||
extern ssize_t tpm_show_timeouts(struct device *,
|
||||
struct device_attribute *attr, char *);
|
||||
|
||||
struct tpm_chip;
|
||||
|
||||
|
|
@ -67,6 +71,7 @@ struct tpm_vendor_specific {
|
|||
unsigned long base; /* TPM base address */
|
||||
|
||||
int irq;
|
||||
int probed_irq;
|
||||
|
||||
int region_size;
|
||||
int have_region;
|
||||
|
|
@ -81,7 +86,9 @@ struct tpm_vendor_specific {
|
|||
struct list_head list;
|
||||
int locality;
|
||||
unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
|
||||
bool timeout_adjusted;
|
||||
unsigned long duration[3]; /* jiffies */
|
||||
bool duration_adjusted;
|
||||
|
||||
wait_queue_head_t read_queue;
|
||||
wait_queue_head_t int_queue;
|
||||
|
|
|
|||
|
|
@ -330,12 +330,12 @@ static int __init init_nsc(void)
|
|||
pdev->dev.driver = &nsc_drv.driver;
|
||||
pdev->dev.release = tpm_nsc_remove;
|
||||
|
||||
if ((rc = platform_device_register(pdev)) < 0)
|
||||
goto err_free_dev;
|
||||
if ((rc = platform_device_add(pdev)) < 0)
|
||||
goto err_put_dev;
|
||||
|
||||
if (request_region(base, 2, "tpm_nsc0") == NULL ) {
|
||||
rc = -EBUSY;
|
||||
goto err_unreg_dev;
|
||||
goto err_del_dev;
|
||||
}
|
||||
|
||||
if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
|
||||
|
|
@ -382,10 +382,10 @@ static int __init init_nsc(void)
|
|||
|
||||
err_rel_reg:
|
||||
release_region(base, 2);
|
||||
err_unreg_dev:
|
||||
platform_device_unregister(pdev);
|
||||
err_free_dev:
|
||||
kfree(pdev);
|
||||
err_del_dev:
|
||||
platform_device_del(pdev);
|
||||
err_put_dev:
|
||||
platform_device_put(pdev);
|
||||
err_unreg_drv:
|
||||
platform_driver_unregister(&nsc_drv);
|
||||
return rc;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/freezer.h>
|
||||
#include "tpm.h"
|
||||
|
||||
#define TPM_HEADER_SIZE 10
|
||||
|
|
@ -79,7 +80,7 @@ enum tis_defaults {
|
|||
static LIST_HEAD(tis_chips);
|
||||
static DEFINE_SPINLOCK(tis_lock);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#ifdef CONFIG_PNP
|
||||
static int is_itpm(struct pnp_dev *dev)
|
||||
{
|
||||
struct acpi_device *acpi = pnp_acpi_device(dev);
|
||||
|
|
@ -92,11 +93,6 @@ static int is_itpm(struct pnp_dev *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int is_itpm(struct pnp_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check_locality(struct tpm_chip *chip, int l)
|
||||
|
|
@ -120,7 +116,7 @@ static void release_locality(struct tpm_chip *chip, int l, int force)
|
|||
|
||||
static int request_locality(struct tpm_chip *chip, int l)
|
||||
{
|
||||
unsigned long stop;
|
||||
unsigned long stop, timeout;
|
||||
long rc;
|
||||
|
||||
if (check_locality(chip, l) >= 0)
|
||||
|
|
@ -129,17 +125,25 @@ static int request_locality(struct tpm_chip *chip, int l)
|
|||
iowrite8(TPM_ACCESS_REQUEST_USE,
|
||||
chip->vendor.iobase + TPM_ACCESS(l));
|
||||
|
||||
stop = jiffies + chip->vendor.timeout_a;
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
again:
|
||||
timeout = stop - jiffies;
|
||||
if ((long)timeout <= 0)
|
||||
return -1;
|
||||
rc = wait_event_interruptible_timeout(chip->vendor.int_queue,
|
||||
(check_locality
|
||||
(chip, l) >= 0),
|
||||
chip->vendor.timeout_a);
|
||||
timeout);
|
||||
if (rc > 0)
|
||||
return l;
|
||||
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
/* wait for burstcount */
|
||||
stop = jiffies + chip->vendor.timeout_a;
|
||||
do {
|
||||
if (check_locality(chip, l) >= 0)
|
||||
return l;
|
||||
|
|
@ -196,15 +200,24 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
|||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
|
||||
stop = jiffies + timeout;
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
again:
|
||||
timeout = stop - jiffies;
|
||||
if ((long)timeout <= 0)
|
||||
return -ETIME;
|
||||
rc = wait_event_interruptible_timeout(*queue,
|
||||
((tpm_tis_status
|
||||
(chip) & mask) ==
|
||||
mask), timeout);
|
||||
if (rc > 0)
|
||||
return 0;
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
stop = jiffies + timeout;
|
||||
do {
|
||||
msleep(TPM_TIMEOUT);
|
||||
status = tpm_tis_status(chip);
|
||||
|
|
@ -288,11 +301,10 @@ MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
|
|||
* tpm.c can skip polling for the data to be available as the interrupt is
|
||||
* waited for here
|
||||
*/
|
||||
static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
{
|
||||
int rc, status, burstcnt;
|
||||
size_t count = 0;
|
||||
u32 ordinal;
|
||||
|
||||
if (request_locality(chip, 0) < 0)
|
||||
return -EBUSY;
|
||||
|
|
@ -327,8 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
|||
|
||||
/* write last byte */
|
||||
iowrite8(buf[count],
|
||||
chip->vendor.iobase +
|
||||
TPM_DATA_FIFO(chip->vendor.locality));
|
||||
chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
|
||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
status = tpm_tis_status(chip);
|
||||
|
|
@ -337,6 +348,28 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
|||
goto out_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
tpm_tis_ready(chip);
|
||||
release_locality(chip, chip->vendor.locality, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* If interrupts are used (signaled by an irq set in the vendor structure)
|
||||
* tpm.c can skip polling for the data to be available as the interrupt is
|
||||
* waited for here
|
||||
*/
|
||||
static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
{
|
||||
int rc;
|
||||
u32 ordinal;
|
||||
|
||||
rc = tpm_tis_send_data(chip, buf, len);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* go and do it */
|
||||
iowrite8(TPM_STS_GO,
|
||||
chip->vendor.iobase + TPM_STS(chip->vendor.locality));
|
||||
|
|
@ -358,6 +391,47 @@ out_err:
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Early probing for iTPM with STS_DATA_EXPECT flaw.
|
||||
* Try sending command without itpm flag set and if that
|
||||
* fails, repeat with itpm flag set.
|
||||
*/
|
||||
static int probe_itpm(struct tpm_chip *chip)
|
||||
{
|
||||
int rc = 0;
|
||||
u8 cmd_getticks[] = {
|
||||
0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a,
|
||||
0x00, 0x00, 0x00, 0xf1
|
||||
};
|
||||
size_t len = sizeof(cmd_getticks);
|
||||
int rem_itpm = itpm;
|
||||
|
||||
itpm = 0;
|
||||
|
||||
rc = tpm_tis_send_data(chip, cmd_getticks, len);
|
||||
if (rc == 0)
|
||||
goto out;
|
||||
|
||||
tpm_tis_ready(chip);
|
||||
release_locality(chip, chip->vendor.locality, 0);
|
||||
|
||||
itpm = 1;
|
||||
|
||||
rc = tpm_tis_send_data(chip, cmd_getticks, len);
|
||||
if (rc == 0) {
|
||||
dev_info(chip->dev, "Detected an iTPM.\n");
|
||||
rc = 1;
|
||||
} else
|
||||
rc = -EFAULT;
|
||||
|
||||
out:
|
||||
itpm = rem_itpm;
|
||||
tpm_tis_ready(chip);
|
||||
release_locality(chip, chip->vendor.locality, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations tis_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
|
|
@ -376,6 +450,8 @@ static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated,
|
|||
NULL);
|
||||
static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL);
|
||||
static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel);
|
||||
static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL);
|
||||
static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL);
|
||||
|
||||
static struct attribute *tis_attrs[] = {
|
||||
&dev_attr_pubek.attr,
|
||||
|
|
@ -385,7 +461,9 @@ static struct attribute *tis_attrs[] = {
|
|||
&dev_attr_owned.attr,
|
||||
&dev_attr_temp_deactivated.attr,
|
||||
&dev_attr_caps.attr,
|
||||
&dev_attr_cancel.attr, NULL,
|
||||
&dev_attr_cancel.attr,
|
||||
&dev_attr_durations.attr,
|
||||
&dev_attr_timeouts.attr, NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group tis_attr_grp = {
|
||||
|
|
@ -416,7 +494,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id)
|
|||
if (interrupt == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
chip->vendor.irq = irq;
|
||||
chip->vendor.probed_irq = irq;
|
||||
|
||||
/* Clear interrupts handled with TPM_EOI */
|
||||
iowrite32(interrupt,
|
||||
|
|
@ -464,7 +542,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
|||
resource_size_t len, unsigned int irq)
|
||||
{
|
||||
u32 vendor, intfcaps, intmask;
|
||||
int rc, i;
|
||||
int rc, i, irq_s, irq_e;
|
||||
struct tpm_chip *chip;
|
||||
|
||||
if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
|
||||
|
|
@ -493,6 +571,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
|||
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
|
||||
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
|
||||
|
||||
if (!itpm) {
|
||||
itpm = probe_itpm(chip);
|
||||
if (itpm < 0) {
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (itpm)
|
||||
dev_info(dev, "Intel iTPM workaround enabled\n");
|
||||
|
||||
|
|
@ -522,6 +608,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
|||
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
|
||||
dev_dbg(dev, "\tData Avail Int Support\n");
|
||||
|
||||
/* get the timeouts before testing for irqs */
|
||||
tpm_get_timeouts(chip);
|
||||
|
||||
/* INTERRUPT Setup */
|
||||
init_waitqueue_head(&chip->vendor.read_queue);
|
||||
init_waitqueue_head(&chip->vendor.int_queue);
|
||||
|
|
@ -540,13 +629,19 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
|||
if (interrupts)
|
||||
chip->vendor.irq = irq;
|
||||
if (interrupts && !chip->vendor.irq) {
|
||||
chip->vendor.irq =
|
||||
irq_s =
|
||||
ioread8(chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
if (irq_s) {
|
||||
irq_e = irq_s;
|
||||
} else {
|
||||
irq_s = 3;
|
||||
irq_e = 15;
|
||||
}
|
||||
|
||||
for (i = 3; i < 16 && chip->vendor.irq == 0; i++) {
|
||||
for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
|
||||
iowrite8(i, chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
if (request_irq
|
||||
(i, tis_int_probe, IRQF_SHARED,
|
||||
chip->vendor.miscdev.name, chip) != 0) {
|
||||
|
|
@ -568,9 +663,22 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
|||
chip->vendor.iobase +
|
||||
TPM_INT_ENABLE(chip->vendor.locality));
|
||||
|
||||
chip->vendor.probed_irq = 0;
|
||||
|
||||
/* Generate Interrupts */
|
||||
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 +
|
||||
|
|
@ -609,7 +717,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
|||
list_add(&chip->vendor.list, &tis_chips);
|
||||
spin_unlock(&tis_lock);
|
||||
|
||||
tpm_get_timeouts(chip);
|
||||
tpm_continue_selftest(chip);
|
||||
|
||||
return 0;
|
||||
|
|
@ -619,6 +726,29 @@ out_err:
|
|||
tpm_remove_hardware(chip->dev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
|
||||
{
|
||||
u32 intmask;
|
||||
|
||||
/* reenable interrupts that device may have lost or
|
||||
BIOS/firmware may have disabled */
|
||||
iowrite8(chip->vendor.irq, chip->vendor.iobase +
|
||||
TPM_INT_VECTOR(chip->vendor.locality));
|
||||
|
||||
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 | TPM_GLOBAL_INT_ENABLE;
|
||||
|
||||
iowrite32(intmask,
|
||||
chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
|
||||
const struct pnp_device_id *pnp_id)
|
||||
|
|
@ -650,6 +780,9 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
|
|||
struct tpm_chip *chip = pnp_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (chip->vendor.irq)
|
||||
tpm_tis_reenable_interrupts(chip);
|
||||
|
||||
ret = tpm_pm_resume(&dev->dev);
|
||||
if (!ret)
|
||||
tpm_continue_selftest(chip);
|
||||
|
|
@ -702,6 +835,11 @@ static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
|
|||
|
||||
static int tpm_tis_resume(struct platform_device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
|
||||
|
||||
if (chip->vendor.irq)
|
||||
tpm_tis_reenable_interrupts(chip);
|
||||
|
||||
return tpm_pm_resume(&dev->dev);
|
||||
}
|
||||
static struct platform_driver tis_drv = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue