Commit 700d8bdc authored by Nishanth Aravamudan's avatar Nishanth Aravamudan Committed by Linus Torvalds
Browse files

[PATCH] char/tpm: use msleep(), clean-up timers,



The TPM driver unnecessarily uses timers when it simply needs to maintain a
maximum delay via time_before().  msleep() is used instead of
schedule_timeout() to guarantee the task delays as expected.  While
compile-testing, I found a typo in the driver, using tpm_chp instead of
tpm_chip.  Remove the now unused timer callback function and change
TPM_TIMEOUT's units to milliseconds.  Patch is compile-tested.

Signed-off-by: default avatarNishanth Aravamudan <nacc@us.ibm.com>
Acked-by: default avatarKylene Hall <kjhall@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 6a94f920
Loading
Loading
Loading
Loading
+7 −28
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
 * 
 * Note, the TPM chip is not interrupt driven (only polling)
 * and can have very long timeouts (minutes!). Hence the unusual
 * calls to schedule_timeout.
 * calls to msleep.
 *
 */

@@ -52,14 +52,6 @@ static void user_reader_timeout(unsigned long ptr)
	up(&chip->buffer_mutex);
}

void tpm_time_expired(unsigned long ptr)
{
	int *exp = (int *) ptr;
	*exp = 1;
}

EXPORT_SYMBOL_GPL(tpm_time_expired);

/*
 * Initialize the LPC bus and enable the TPM ports
 */
@@ -135,6 +127,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
	ssize_t len;
	u32 count;
	__be32 *native_size;
	unsigned long stop;

	native_size = (__force __be32 *) (buf + 2);
	count = be32_to_cpu(*native_size);
@@ -155,28 +148,16 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
		return len;
	}

	down(&chip->timer_manipulation_mutex);
	chip->time_expired = 0;
	init_timer(&chip->device_timer);
	chip->device_timer.function = tpm_time_expired;
	chip->device_timer.expires = jiffies + 2 * 60 * HZ;
	chip->device_timer.data = (unsigned long) &chip->time_expired;
	add_timer(&chip->device_timer);
	up(&chip->timer_manipulation_mutex);

	stop = jiffies + 2 * 60 * HZ;
	do {
		u8 status = inb(chip->vendor->base + 1);
		if ((status & chip->vendor->req_complete_mask) ==
		    chip->vendor->req_complete_val) {
			down(&chip->timer_manipulation_mutex);
			del_singleshot_timer_sync(&chip->device_timer);
			up(&chip->timer_manipulation_mutex);
			goto out_recv;
		}
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(TPM_TIMEOUT);
		msleep(TPM_TIMEOUT); /* CHECK */
		rmb();
	} while (!chip->time_expired);
	} while (time_before(jiffies, stop));


	chip->vendor->cancel(chip);
@@ -453,10 +434,8 @@ ssize_t tpm_write(struct file * file, const char __user * buf,

	/* cannot perform a write until the read has cleared
	   either via tpm_read or a user_read_timer timeout */
	while (atomic_read(&chip->data_pending) != 0) {
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(TPM_TIMEOUT);
	}
	while (atomic_read(&chip->data_pending) != 0)
		msleep(TPM_TIMEOUT);

	down(&chip->buffer_mutex);

+1 −2
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>

#define TPM_TIMEOUT msecs_to_jiffies(5)
#define TPM_TIMEOUT	5	/* msecs */

/* TPM addresses */
#define	TPM_ADDR			0x4E
@@ -78,7 +78,6 @@ static inline void tpm_write_index(int index, int value)
	outb(value & 0xFF, TPM_DATA);
}

extern void tpm_time_expired(unsigned long);
extern int tpm_lpc_bus_init(struct pci_dev *, u16);

extern int tpm_register_hardware(struct pci_dev *,
+10 −22
Original line number Diff line number Diff line
@@ -55,10 +55,7 @@
 */
static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
{
	int expired = 0;
	struct timer_list status_timer =
	    TIMER_INITIALIZER(tpm_time_expired, jiffies + 10 * HZ,
			      (unsigned long) &expired);
	unsigned long stop;

	/* status immediately available check */
	*data = inb(chip->vendor->base + NSC_STATUS);
@@ -66,17 +63,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
		return 0;

	/* wait for status */
	add_timer(&status_timer);
	stop = jiffies + 10 * HZ;
	do {
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(TPM_TIMEOUT);
		msleep(TPM_TIMEOUT);
		*data = inb(chip->vendor->base + 1);
		if ((*data & mask) == val) {
			del_singleshot_timer_sync(&status_timer);
		if ((*data & mask) == val)
			return 0;
	}
	}
	while (!expired);
	while (time_before(jiffies, stop));

	return -EBUSY;
}
@@ -84,10 +78,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
static int nsc_wait_for_ready(struct tpm_chip *chip)
{
	int status;
	int expired = 0;
	struct timer_list status_timer =
	    TIMER_INITIALIZER(tpm_time_expired, jiffies + 100,
			      (unsigned long) &expired);
	unsigned long stop;

	/* status immediately available check */
	status = inb(chip->vendor->base + NSC_STATUS);
@@ -97,19 +88,16 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
		return 0;

	/* wait for status */
	add_timer(&status_timer);
	stop = jiffies + 100;
	do {
		set_current_state(TASK_UNINTERRUPTIBLE);
		schedule_timeout(TPM_TIMEOUT);
		msleep(TPM_TIMEOUT);
		status = inb(chip->vendor->base + NSC_STATUS);
		if (status & NSC_STATUS_OBF)
			status = inb(chip->vendor->base + NSC_DATA);
		if (status & NSC_STATUS_RDY) {
			del_singleshot_timer_sync(&status_timer);
		if (status & NSC_STATUS_RDY)
			return 0;
	}
	}
	while (!expired);
	while (time_before(jiffies, stop));

	dev_info(&chip->pci_dev->dev, "wait for ready failed\n");
	return -EBUSY;