linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64
@ 2012-08-14 23:23 Ashley Lai
  2012-08-14 23:34 ` [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM Ashley Lai
                   ` (3 more replies)
  0 siblings, 4 replies; 19+ messages in thread
From: Ashley Lai @ 2012-08-14 23:23 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, tpmdd-devel, benh, linuxppc-dev, rcj, key,
	adlai, adlai

Change log V3:
- Replaced TPM_NO_EVENT_LOG macro with stubs
- Removed tpm_noeventlog.c file 
- Called of_node_put() before return in tpm_of.c

Change log V2:
- Removed unnecessary tpm_bios_log_setup and tpm_bios_log_teardown
  functions in tpm_eventlog.h (patch 3/3).
- Added more descriptions on vTPM (patch 1/3).

These patches add support for IBM vTPM for PPC64. This new device driver
works on firmware that supports vTPM (firmware release 740 or higher).

Tested on Power7+ system with firmware level ZM770_001.

Applied to Kent Yoder tree at:
https://github.com/shpedoikal/linux/tree/v3.6-rc1-tpmdd-staging

Ashley Lai (3):
  drivers/char/tpm: Add new device driver to support IBM vTPM
  PPC64: Add support for instantiating SML from Open Firmware
  drivers/char/tpm: Add securityfs support for event log

 arch/powerpc/kernel/prom_init.c |   62 ++++
 drivers/char/tpm/Kconfig        |    8 +
 drivers/char/tpm/Makefile       |    6 +
 drivers/char/tpm/tpm.h          |   13 +-
 drivers/char/tpm/tpm_eventlog.h |   15 +
 drivers/char/tpm/tpm_ibmvtpm.c  |  749 +++++++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm_ibmvtpm.h  |   83 +++++
 drivers/char/tpm/tpm_of.c       |   73 ++++
 8 files changed, 997 insertions(+), 12 deletions(-)
 create mode 100644 drivers/char/tpm/tpm_ibmvtpm.c
 create mode 100644 drivers/char/tpm/tpm_ibmvtpm.h
 create mode 100644 drivers/char/tpm/tpm_of.c



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-08-14 23:23 [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Ashley Lai
@ 2012-08-14 23:34 ` Ashley Lai
  2012-08-22 21:17   ` Ashley Lai
  2012-08-14 23:34 ` [PATCH V3 2/3] PPC64: Add support for instantiating SML from Open Firmware Ashley Lai
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 19+ messages in thread
From: Ashley Lai @ 2012-08-14 23:34 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, tpmdd-devel, benh, linuxppc-dev, rcj, key,
	adlai, adlai

This patch adds a new device driver to support IBM virtual TPM
(vTPM) for PPC64.  IBM vTPM is supported through the adjunct
partition with firmware release 740 or higher.  With vTPM
support, each lpar is able to have its own vTPM without the
physical TPM hardware.

This driver provides TPM functionalities by communicating with
the vTPM adjunct partition through Hypervisor calls (Hcalls)
and Command/Response Queue (CRQ) commands.

Signed-off-by: Ashley Lai <adlai@us.ibm.com>
---
 drivers/char/tpm/Kconfig       |    8 +
 drivers/char/tpm/Makefile      |    1 +
 drivers/char/tpm/tpm.h         |    1 +
 drivers/char/tpm/tpm_ibmvtpm.c |  749 ++++++++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm_ibmvtpm.h |   83 +++++
 5 files changed, 842 insertions(+), 0 deletions(-)
 create mode 100644 drivers/char/tpm/tpm_ibmvtpm.c
 create mode 100644 drivers/char/tpm/tpm_ibmvtpm.h

diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index c4aac48..915875e 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -73,4 +73,12 @@ config TCG_INFINEON
 	  Further information on this driver and the supported hardware
 	  can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 

+config TCG_IBMVTPM
+	tristate "IBM VTPM Interface"
+	depends on PPC64
+	---help---
+	  If you have IBM virtual TPM (VTPM) support say Yes and it
+	  will be accessible from within Linux.  To compile this driver
+	  as a module, choose M here; the module will be called tpm_ibmvtpm.
+
 endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index beac52f..547509d 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
 obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
+obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 645136e..870fde7 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -100,6 +100,7 @@ struct tpm_vendor_specific {
 	bool timeout_adjusted;
 	unsigned long duration[3]; /* jiffies */
 	bool duration_adjusted;
+	void *data;
 
 	wait_queue_head_t read_queue;
 	wait_queue_head_t int_queue;
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
new file mode 100644
index 0000000..efc4ab3
--- /dev/null
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2012 IBM Corporation
+ *
+ * Author: Ashley Lai <adlai@us.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/slab.h>
+#include <asm/vio.h>
+#include <asm/irq.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <asm/prom.h>
+
+#include "tpm.h"
+#include "tpm_ibmvtpm.h"
+
+static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm";
+
+static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = {
+	{ "IBM,vtpm", "IBM,vtpm"},
+	{ "", "" }
+};
+MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
+
+DECLARE_WAIT_QUEUE_HEAD(wq);
+
+/**
+ * ibmvtpm_send_crq - Send a CRQ request
+ * @vdev:	vio device struct
+ * @w1:		first word
+ * @w2:		second word
+ *
+ * Return value:
+ *	0 -Sucess
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2)
+{
+	return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2);
+}
+
+/**
+ * ibmvtpm_get_data - Retrieve ibm vtpm data
+ * @dev:	device struct
+ *
+ * Return value:
+ *	vtpm device struct
+ */
+static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev)
+{
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+	if (chip)
+		return (struct ibmvtpm_dev *)chip->vendor.data;
+	return NULL;
+}
+
+/**
+ * tpm_ibmvtpm_recv - Receive data after send
+ * @chip:	tpm chip struct
+ * @buf:	buffer to read
+ * count:	size of buffer
+ *
+ * Return value:
+ *	Number of bytes read
+ */
+static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+	struct ibmvtpm_dev *ibmvtpm;
+	u16 len;
+
+	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
+
+	if (!ibmvtpm->rtce_buf) {
+		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
+		return 0;
+	}
+
+	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
+
+	if (count < ibmvtpm->crq_res.len) {
+		dev_err(ibmvtpm->dev,
+			"Invalid size in recv: count=%ld, crq_size=%d\n",
+			count, ibmvtpm->crq_res.len);
+		return -EIO;
+	}
+
+	spin_lock(&ibmvtpm->rtce_lock);
+	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len);
+	memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len);
+	ibmvtpm->crq_res.valid = 0;
+	ibmvtpm->crq_res.msg = 0;
+	len = ibmvtpm->crq_res.len;
+	ibmvtpm->crq_res.len = 0;
+	spin_unlock(&ibmvtpm->rtce_lock);
+	return len;
+}
+
+/**
+ * tpm_ibmvtpm_send - Send tpm request
+ * @chip:	tpm chip struct
+ * @buf:	buffer contains data to send
+ * count:	size of buffer
+ *
+ * Return value:
+ *	Number of bytes sent
+ */
+static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+	struct ibmvtpm_dev *ibmvtpm;
+	struct ibmvtpm_crq crq;
+	u64 *word = (u64 *) &crq;
+	int rc;
+
+	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
+
+	if (!ibmvtpm->rtce_buf) {
+		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
+		return 0;
+	}
+
+	if (count > ibmvtpm->rtce_size) {
+		dev_err(ibmvtpm->dev,
+			"Invalid size in send: count=%ld, rtce_size=%d\n",
+			count, ibmvtpm->rtce_size);
+		return -EIO;
+	}
+
+	spin_lock(&ibmvtpm->rtce_lock);
+	memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_TPM_COMMAND;
+	crq.len = (u16)count;
+	crq.data = ibmvtpm->rtce_dma_handle;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]);
+	if (rc != H_SUCCESS) {
+		dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
+		rc = 0;
+	} else
+		rc = count;
+
+	spin_unlock(&ibmvtpm->rtce_lock);
+	return rc;
+}
+
+static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
+{
+	return;
+}
+
+static u8 tpm_ibmvtpm_status(struct tpm_chip *chip)
+{
+	return 0;
+}
+
+/**
+ * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
+{
+	struct ibmvtpm_crq crq;
+	u64 *buf = (u64 *) &crq;
+	int rc;
+
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version
+ *			   - Note that this is vtpm version and not tpm version
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
+{
+	struct ibmvtpm_crq crq;
+	u64 *buf = (u64 *) &crq;
+	int rc;
+
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_GET_VERSION;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_get_version failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_send_init_complete failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_crq_send_init - Send a CRQ initialize message
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_send_init failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * tpm_ibmvtpm_remove - ibm vtpm remove entry point
+ * @vdev:	vio device struct
+ *
+ * Return value:
+ *	0
+ */
+static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+	int rc = 0;
+
+	free_irq(vdev->irq, ibmvtpm);
+	tasklet_kill(&ibmvtpm->tasklet);
+
+	do {
+		if (rc)
+			msleep(100);
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	dma_unmap_single(ibmvtpm->dev, ibmvtpm->crq_dma_handle,
+			 CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL);
+	free_page((unsigned long)ibmvtpm->crq_queue.crq_addr);
+
+	if (ibmvtpm->rtce_buf) {
+		dma_unmap_single(ibmvtpm->dev, ibmvtpm->rtce_dma_handle,
+				 ibmvtpm->rtce_size, DMA_BIDIRECTIONAL);
+		kfree(ibmvtpm->rtce_buf);
+	}
+
+	tpm_remove_hardware(ibmvtpm->dev);
+
+	kfree(ibmvtpm);
+
+	return 0;
+}
+
+/**
+ * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver
+ * @vdev:	vio device struct
+ *
+ * Return value:
+ *	Number of bytes the driver needs to DMA map
+ */
+static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+	return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
+}
+
+/**
+ * tpm_ibmvtpm_suspend - Suspend
+ * @dev:	device struct
+ *
+ * Return value:
+ *	0
+ */
+static int tpm_ibmvtpm_suspend(struct device *dev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
+	struct ibmvtpm_crq crq;
+	u64 *buf = (u64 *) &crq;
+	int rc = 0;
+
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"tpm_ibmvtpm_suspend failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_reset_crq - Reset CRQ
+ * @ibmvtpm:	ibm vtpm struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc = 0;
+
+	do {
+		if (rc)
+			msleep(100);
+		rc = plpar_hcall_norets(H_FREE_CRQ,
+					ibmvtpm->vdev->unit_address);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	memset(ibmvtpm->crq_queue.crq_addr, 0, CRQ_RES_BUF_SIZE);
+	ibmvtpm->crq_queue.index = 0;
+
+	return plpar_hcall_norets(H_REG_CRQ, ibmvtpm->vdev->unit_address,
+				  ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
+}
+
+/**
+ * tpm_ibmvtpm_resume - Resume from suspend
+ * @dev:	device struct
+ *
+ * Return value:
+ *	0
+ */
+static int tpm_ibmvtpm_resume(struct device *dev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
+	unsigned long flags;
+	int rc = 0;
+
+	do {
+		if (rc)
+			msleep(100);
+		rc = plpar_hcall_norets(H_ENABLE_CRQ,
+					ibmvtpm->vdev->unit_address);
+	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	if (rc) {
+		dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
+		return rc;
+	}
+
+	spin_lock_irqsave(&ibmvtpm->lock, flags);
+	vio_disable_interrupts(ibmvtpm->vdev);
+	tasklet_schedule(&ibmvtpm->tasklet);
+	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+
+	rc = ibmvtpm_crq_send_init(ibmvtpm);
+	if (rc)
+		dev_err(dev, "Error send_init rc=%d\n", rc);
+
+	return rc;
+}
+
+static const struct file_operations ibmvtpm_ops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.open = tpm_open,
+	.read = tpm_read,
+	.write = tpm_write,
+	.release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
+static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
+static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
+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 *ibmvtpm_attrs[] = {
+	&dev_attr_pubek.attr,
+	&dev_attr_pcrs.attr,
+	&dev_attr_enabled.attr,
+	&dev_attr_active.attr,
+	&dev_attr_owned.attr,
+	&dev_attr_temp_deactivated.attr,
+	&dev_attr_caps.attr,
+	&dev_attr_cancel.attr,
+	&dev_attr_durations.attr,
+	&dev_attr_timeouts.attr, NULL,
+};
+
+static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs };
+
+static const struct tpm_vendor_specific tpm_ibmvtpm = {
+	.recv = tpm_ibmvtpm_recv,
+	.send = tpm_ibmvtpm_send,
+	.cancel = tpm_ibmvtpm_cancel,
+	.status = tpm_ibmvtpm_status,
+	.req_complete_mask = 0,
+	.req_complete_val = 0,
+	.req_canceled = 0,
+	.attr_group = &ibmvtpm_attr_grp,
+	.miscdev = { .fops = &ibmvtpm_ops, },
+};
+
+static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = {
+	.suspend = tpm_ibmvtpm_suspend,
+	.resume = tpm_ibmvtpm_resume,
+};
+
+/**
+ * ibmvtpm_crq_get_next - Get next responded crq
+ * @ibmvtpm	vtpm device struct
+ *
+ * Return value:
+ *	vtpm crq pointer
+ */
+static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
+{
+	struct ibmvtpm_crq_queue *crq_q = &ibmvtpm->crq_queue;
+	struct ibmvtpm_crq *crq = &crq_q->crq_addr[crq_q->index];
+
+	if (crq->valid & VTPM_MSG_RES) {
+		if (++crq_q->index == crq_q->num_entry)
+			crq_q->index = 0;
+		rmb();
+	} else
+		crq = NULL;
+	return crq;
+}
+
+/**
+ * ibmvtpm_crq_process - Process responded crq
+ * @crq		crq to be processed
+ * @ibmvtpm	vtpm device struct
+ *
+ * Return value:
+ *	Nothing
+ */
+static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
+				struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc = 0;
+
+	switch (crq->valid) {
+	case VALID_INIT_CRQ:
+		switch (crq->msg) {
+		case INIT_CRQ_RES:
+			dev_info(ibmvtpm->dev, "CRQ initialized\n");
+			rc = ibmvtpm_crq_send_init_complete(ibmvtpm);
+			if (rc)
+				dev_err(ibmvtpm->dev, "Unable to send CRQ init complete rc=%d\n", rc);
+			return;
+		case INIT_CRQ_COMP_RES:
+			dev_info(ibmvtpm->dev,
+				 "CRQ initialization completed\n");
+			return;
+		default:
+			dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg);
+			return;
+		}
+		return;
+	case IBMVTPM_VALID_CMD:
+		switch (crq->msg) {
+		case VTPM_GET_RTCE_BUFFER_SIZE_RES:
+			if (crq->len <= 0) {
+				dev_err(ibmvtpm->dev, "Invalid rtce size\n");
+				return;
+			}
+			ibmvtpm->rtce_size = crq->len;
+			ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
+						    GFP_KERNEL);
+			if (!ibmvtpm->rtce_buf) {
+				dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
+				return;
+			}
+
+			ibmvtpm->rtce_dma_handle = dma_map_single(ibmvtpm->dev,
+				ibmvtpm->rtce_buf, ibmvtpm->rtce_size,
+				DMA_BIDIRECTIONAL);
+
+			if (dma_mapping_error(ibmvtpm->dev,
+					      ibmvtpm->rtce_dma_handle)) {
+				kfree(ibmvtpm->rtce_buf);
+				ibmvtpm->rtce_buf = NULL;
+				dev_err(ibmvtpm->dev, "Failed to dma map rtce buffer\n");
+			}
+
+			return;
+		case VTPM_GET_VERSION_RES:
+			ibmvtpm->vtpm_version = crq->data;
+			return;
+		case VTPM_TPM_COMMAND_RES:
+			ibmvtpm->crq_res.valid = crq->valid;
+			ibmvtpm->crq_res.msg = crq->msg;
+			ibmvtpm->crq_res.len = crq->len;
+			ibmvtpm->crq_res.data = crq->data;
+			wake_up_interruptible(&wq);
+			return;
+		default:
+			return;
+		}
+	}
+	return;
+}
+
+/**
+ * ibmvtpm_interrupt -	Interrupt handler
+ * @irq:		irq number to handle
+ * @vtpm_instance:	vtpm that received interrupt
+ *
+ * Returns:
+ *	IRQ_HANDLED
+ **/
+static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
+{
+	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ibmvtpm->lock, flags);
+	vio_disable_interrupts(ibmvtpm->vdev);
+	tasklet_schedule(&ibmvtpm->tasklet);
+	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ibmvtpm_tasklet - Interrupt handler tasklet
+ * @data:	ibm vtpm device struct
+ *
+ * Returns:
+ *	Nothing
+ **/
+static void ibmvtpm_tasklet(void *data)
+{
+	struct ibmvtpm_dev *ibmvtpm = data;
+	struct ibmvtpm_crq *crq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ibmvtpm->lock, flags);
+	while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
+		ibmvtpm_crq_process(crq, ibmvtpm);
+		crq->valid = 0;
+		wmb();
+	}
+
+	vio_enable_interrupts(ibmvtpm->vdev);
+	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+}
+
+/**
+ * tpm_ibmvtpm_probe - ibm vtpm initialize entry point
+ * @vio_dev:	vio device struct
+ * @id:		vio device id struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
+				   const struct vio_device_id *id)
+{
+	struct ibmvtpm_dev *ibmvtpm;
+	struct device *dev = &vio_dev->dev;
+	struct ibmvtpm_crq_queue *crq_q;
+	struct tpm_chip *chip;
+	int rc = -ENOMEM, rc1;
+
+	chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
+	if (!chip) {
+		dev_err(dev, "tpm_register_hardware failed\n");
+		return -ENODEV;
+	}
+
+	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
+	if (!ibmvtpm) {
+		dev_err(dev, "kzalloc for ibmvtpm failed\n");
+		goto cleanup;
+	}
+
+	crq_q = &ibmvtpm->crq_queue;
+	crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL);
+	if (!crq_q->crq_addr) {
+		dev_err(dev, "Unable to allocate memory for crq_addr\n");
+		goto cleanup;
+	}
+
+	crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr);
+	ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr,
+						 CRQ_RES_BUF_SIZE,
+						 DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) {
+		dev_err(dev, "dma mapping failed\n");
+		goto cleanup;
+	}
+
+	rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address,
+				ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
+	if (rc == H_RESOURCE)
+		rc = ibmvtpm_reset_crq(ibmvtpm);
+
+	if (rc) {
+		dev_err(dev, "Unable to register CRQ rc=%d\n", rc);
+		goto reg_crq_cleanup;
+	}
+
+	tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet,
+		     (unsigned long)ibmvtpm);
+
+	rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0,
+			 tpm_ibmvtpm_driver_name, ibmvtpm);
+	if (rc) {
+		dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq);
+		goto init_irq_cleanup;
+	}
+
+	rc = vio_enable_interrupts(vio_dev);
+	if (rc) {
+		dev_err(dev, "Error %d enabling interrupts\n", rc);
+		goto init_irq_cleanup;
+	}
+
+	crq_q->index = 0;
+
+	ibmvtpm->dev = dev;
+	ibmvtpm->vdev = vio_dev;
+	chip->vendor.data = (void *)ibmvtpm;
+
+	spin_lock_init(&ibmvtpm->lock);
+	spin_lock_init(&ibmvtpm->rtce_lock);
+
+	rc = ibmvtpm_crq_send_init(ibmvtpm);
+	if (rc)
+		goto init_irq_cleanup;
+
+	rc = ibmvtpm_crq_get_version(ibmvtpm);
+	if (rc)
+		goto init_irq_cleanup;
+
+	rc = ibmvtpm_crq_get_rtce_size(ibmvtpm);
+	if (rc)
+		goto init_irq_cleanup;
+
+	return rc;
+init_irq_cleanup:
+	tasklet_kill(&ibmvtpm->tasklet);
+	do {
+		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
+	} while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1));
+reg_crq_cleanup:
+	dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE,
+			 DMA_BIDIRECTIONAL);
+cleanup:
+	if (ibmvtpm) {
+		if (crq_q->crq_addr)
+			free_page((unsigned long)crq_q->crq_addr);
+		kfree(ibmvtpm);
+	}
+
+	tpm_remove_hardware(dev);
+
+	return rc;
+}
+
+static struct vio_driver ibmvtpm_driver = {
+	.id_table	 = tpm_ibmvtpm_device_table,
+	.probe		 = tpm_ibmvtpm_probe,
+	.remove		 = tpm_ibmvtpm_remove,
+	.get_desired_dma = tpm_ibmvtpm_get_desired_dma,
+	.name		 = tpm_ibmvtpm_driver_name,
+	.pm		 = &tpm_ibmvtpm_pm_ops,
+};
+
+/**
+ * ibmvtpm_module_init - Initialize ibm vtpm module
+ *
+ * Return value:
+ *	0 -Success
+ *	Non-zero - Failure
+ */
+static int __init ibmvtpm_module_init(void)
+{
+	return vio_register_driver(&ibmvtpm_driver);
+}
+
+/**
+ * ibmvtpm_module_exit - Teardown ibm vtpm module
+ *
+ * Return value:
+ *	Nothing
+ */
+static void __exit ibmvtpm_module_exit(void)
+{
+	vio_unregister_driver(&ibmvtpm_driver);
+}
+
+module_init(ibmvtpm_module_init);
+module_exit(ibmvtpm_module_exit);
+
+MODULE_AUTHOR("adlai@us.ibm.com");
+MODULE_DESCRIPTION("IBM vTPM Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
new file mode 100644
index 0000000..fb930dd
--- /dev/null
+++ b/drivers/char/tpm/tpm_ibmvtpm.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012 IBM Corporation
+ *
+ * Author: Ashley Lai <adlai@us.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * These difference are required on power because the device must be
+ * discovered through the device tree and iomap must be used to get
+ * around the need for holes in the io_page_mask.  This does not happen
+ * automatically because the tpm is not a normal pci device and lives
+ * under the root node.
+ *
+ */
+
+#ifndef __TPM_IBMVTPM_H__
+#define __TPM_IBMVTPM_H__
+
+/* vTPM Message Format 1 */
+struct ibmvtpm_crq {
+	u8 valid;
+	u8 msg;
+	u16 len;
+	u32 data;
+	u64 reserved;
+} __attribute__((packed, aligned(8)));
+
+struct ibmvtpm_crq_queue {
+	struct ibmvtpm_crq *crq_addr;
+	u32 index;
+	u32 num_entry;
+};
+
+struct ibmvtpm_dev {
+	struct device *dev;
+	struct vio_dev *vdev;
+	struct ibmvtpm_crq_queue crq_queue;
+	dma_addr_t crq_dma_handle;
+	spinlock_t lock;
+	struct tasklet_struct tasklet;
+	u32 rtce_size;
+	void __iomem *rtce_buf;
+	dma_addr_t rtce_dma_handle;
+	spinlock_t rtce_lock;
+	struct ibmvtpm_crq crq_res;
+	u32 vtpm_version;
+};
+
+#define CRQ_RES_BUF_SIZE	PAGE_SIZE
+
+/* Initialize CRQ */
+#define INIT_CRQ_CMD		0xC001000000000000LL /* Init cmd */
+#define INIT_CRQ_COMP_CMD	0xC002000000000000LL /* Init complete cmd */
+#define INIT_CRQ_RES		0x01	/* Init respond */
+#define INIT_CRQ_COMP_RES	0x02	/* Init complete respond */
+#define VALID_INIT_CRQ		0xC0	/* Valid command for init crq */
+
+/* vTPM CRQ response is the message type | 0x80 */
+#define VTPM_MSG_RES		0x80
+#define IBMVTPM_VALID_CMD	0x80
+
+/* vTPM CRQ message types */
+#define VTPM_GET_VERSION			0x01
+#define VTPM_GET_VERSION_RES			(0x01 | VTPM_MSG_RES)
+
+#define VTPM_TPM_COMMAND			0x02
+#define VTPM_TPM_COMMAND_RES			(0x02 | VTPM_MSG_RES)
+
+#define VTPM_GET_RTCE_BUFFER_SIZE		0x03
+#define VTPM_GET_RTCE_BUFFER_SIZE_RES		(0x03 | VTPM_MSG_RES)
+
+#define VTPM_PREPARE_TO_SUSPEND			0x04
+#define VTPM_PREPARE_TO_SUSPEND_RES		(0x04 | VTPM_MSG_RES)
+
+#endif
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH V3 2/3] PPC64: Add support for instantiating SML from Open Firmware
  2012-08-14 23:23 [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Ashley Lai
  2012-08-14 23:34 ` [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM Ashley Lai
@ 2012-08-14 23:34 ` Ashley Lai
  2012-08-14 23:35 ` [PATCH V3 3/3] drivers/char/tpm: Add securityfs support for event log Ashley Lai
  2012-08-15 19:59 ` [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Kent Yoder
  3 siblings, 0 replies; 19+ messages in thread
From: Ashley Lai @ 2012-08-14 23:34 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, tpmdd-devel, benh, linuxppc-dev, rcj, key,
	adlai, adlai

This patch instantiate Stored Measurement Log (SML) and put the
log address and size in the device tree.

Signed-off-by: Ashley Lai <adlai@us.ibm.com>
---
 arch/powerpc/kernel/prom_init.c |   62 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 0794a30..e144498 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -1624,6 +1624,63 @@ static void __init prom_instantiate_rtas(void)
 
 #ifdef CONFIG_PPC64
 /*
+ * Allocate room for and instantiate Stored Measurement Log (SML)
+ */
+static void __init prom_instantiate_sml(void)
+{
+	phandle ibmvtpm_node;
+	ihandle ibmvtpm_inst;
+	u32 entry = 0, size = 0;
+	u64 base;
+
+	prom_debug("prom_instantiate_sml: start...\n");
+
+	ibmvtpm_node = call_prom("finddevice", 1, 1, ADDR("/ibm,vtpm"));
+	prom_debug("ibmvtpm_node: %x\n", ibmvtpm_node);
+	if (!PHANDLE_VALID(ibmvtpm_node))
+		return;
+
+	ibmvtpm_inst = call_prom("open", 1, 1, ADDR("/ibm,vtpm"));
+	if (!IHANDLE_VALID(ibmvtpm_inst)) {
+		prom_printf("opening vtpm package failed (%x)\n", ibmvtpm_inst);
+		return;
+	}
+
+	if (call_prom_ret("call-method", 2, 2, &size,
+			  ADDR("sml-get-handover-size"),
+			  ibmvtpm_inst) != 0 || size == 0) {
+		prom_printf("SML get handover size failed\n");
+		return;
+	}
+
+	base = alloc_down(size, PAGE_SIZE, 0);
+	if (base == 0)
+		prom_panic("Could not allocate memory for sml\n");
+
+	prom_printf("instantiating sml at 0x%x...", base);
+
+	if (call_prom_ret("call-method", 4, 2, &entry,
+			  ADDR("sml-handover"),
+			  ibmvtpm_inst, size, base) != 0 || entry == 0) {
+		prom_printf("SML handover failed\n");
+		return;
+	}
+	prom_printf(" done\n");
+
+	reserve_mem(base, size);
+
+	prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-base",
+		     &base, sizeof(base));
+	prom_setprop(ibmvtpm_node, "/ibm,vtpm", "linux,sml-size",
+		     &size, sizeof(size));
+
+	prom_debug("sml base     = 0x%x\n", base);
+	prom_debug("sml size     = 0x%x\n", (long)size);
+
+	prom_debug("prom_instantiate_sml: end...\n");
+}
+
+/*
  * Allocate room for and initialize TCE tables
  */
 static void __init prom_initialize_tce_table(void)
@@ -2916,6 +2973,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
 		prom_instantiate_opal();
 #endif
 
+#ifdef CONFIG_PPC64
+	/* instantiate sml */
+	prom_instantiate_sml();
+#endif
+
 	/*
 	 * On non-powermacs, put all CPUs in spin-loops.
 	 *
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH V3 3/3] drivers/char/tpm: Add securityfs support for event log
  2012-08-14 23:23 [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Ashley Lai
  2012-08-14 23:34 ` [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM Ashley Lai
  2012-08-14 23:34 ` [PATCH V3 2/3] PPC64: Add support for instantiating SML from Open Firmware Ashley Lai
@ 2012-08-14 23:35 ` Ashley Lai
  2012-08-15 19:59 ` [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Kent Yoder
  3 siblings, 0 replies; 19+ messages in thread
From: Ashley Lai @ 2012-08-14 23:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, tpmdd-devel, benh, linuxppc-dev, rcj, key,
	adlai, adlai

This patch retrieves the event log data from the device tree
during file open. The event log data will then displayed through
securityfs.

Signed-off-by: Ashley Lai <adlai@us.ibm.com>
---
 drivers/char/tpm/Makefile       |    5 +++
 drivers/char/tpm/tpm.h          |   12 ------
 drivers/char/tpm/tpm_eventlog.h |   15 ++++++++
 drivers/char/tpm/tpm_of.c       |   73 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 12 deletions(-)
 create mode 100644 drivers/char/tpm/tpm_of.c

diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 547509d..9080cc4 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -5,6 +5,11 @@ obj-$(CONFIG_TCG_TPM) += tpm.o
 ifdef CONFIG_ACPI
 	obj-$(CONFIG_TCG_TPM) += tpm_bios.o
 	tpm_bios-objs += tpm_eventlog.o tpm_acpi.o
+else
+ifdef CONFIG_TCG_IBMVTPM
+	obj-$(CONFIG_TCG_TPM) += tpm_bios.o
+	tpm_bios-objs += tpm_eventlog.o tpm_of.o
+endif
 endif
 obj-$(CONFIG_TCG_TIS) += tpm_tis.o
 obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 870fde7..f1af738 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -327,15 +327,3 @@ extern int tpm_pm_suspend(struct device *);
 extern int tpm_pm_resume(struct device *);
 extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
 			     wait_queue_head_t *);
-#ifdef CONFIG_ACPI
-extern struct dentry ** tpm_bios_log_setup(char *);
-extern void tpm_bios_log_teardown(struct dentry **);
-#else
-static inline struct dentry ** tpm_bios_log_setup(char *name)
-{
-	return NULL;
-}
-static inline void tpm_bios_log_teardown(struct dentry **dir)
-{
-}
-#endif
diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h
index 8e23ccd..e7da086 100644
--- a/drivers/char/tpm/tpm_eventlog.h
+++ b/drivers/char/tpm/tpm_eventlog.h
@@ -68,4 +68,19 @@ enum tcpa_pc_event_ids {
 };
 
 int read_log(struct tpm_bios_log *log);
+
+#if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \
+	defined(CONFIG_ACPI)
+extern struct dentry **tpm_bios_log_setup(char *);
+extern void tpm_bios_log_teardown(struct dentry **);
+#else
+static inline struct dentry **tpm_bios_log_setup(char *name)
+{
+	return NULL;
+}
+static inline void tpm_bios_log_teardown(struct dentry **dir)
+{
+}
+#endif
+
 #endif
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c
new file mode 100644
index 0000000..98ba2bd
--- /dev/null
+++ b/drivers/char/tpm/tpm_of.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 IBM Corporation
+ *
+ * Author: Ashley Lai <adlai@us.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Read the event log created by the firmware on PPC64
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "tpm.h"
+#include "tpm_eventlog.h"
+
+int read_log(struct tpm_bios_log *log)
+{
+	struct device_node *np;
+	const u32 *sizep;
+	const __be64 *basep;
+
+	if (log->bios_event_log != NULL) {
+		pr_err("%s: ERROR - Eventlog already initialized\n", __func__);
+		return -EFAULT;
+	}
+
+	np = of_find_node_by_name(NULL, "ibm,vtpm");
+	if (!np) {
+		pr_err("%s: ERROR - IBMVTPM not supported\n", __func__);
+		return -ENODEV;
+	}
+
+	sizep = of_get_property(np, "linux,sml-size", NULL);
+	if (sizep == NULL) {
+		pr_err("%s: ERROR - SML size not found\n", __func__);
+		goto cleanup_eio;
+	}
+	if (*sizep == 0) {
+		pr_err("%s: ERROR - event log area empty\n", __func__);
+		goto cleanup_eio;
+	}
+
+	basep = of_get_property(np, "linux,sml-base", NULL);
+	if (basep == NULL) {
+		pr_err(KERN_ERR "%s: ERROR - SML not found\n", __func__);
+		goto cleanup_eio;
+	}
+
+	of_node_put(np);
+	log->bios_event_log = kmalloc(*sizep, GFP_KERNEL);
+	if (!log->bios_event_log) {
+		pr_err("%s: ERROR - Not enough memory for BIOS measurements\n",
+		       __func__);
+		return -ENOMEM;
+	}
+
+	log->bios_event_log_end = log->bios_event_log + *sizep;
+
+	memcpy(log->bios_event_log, __va(be64_to_cpup(basep)), *sizep);
+
+	return 0;
+
+cleanup_eio:
+	of_node_put(np);
+	return -EIO;
+}
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64
  2012-08-14 23:23 [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Ashley Lai
                   ` (2 preceding siblings ...)
  2012-08-14 23:35 ` [PATCH V3 3/3] drivers/char/tpm: Add securityfs support for event log Ashley Lai
@ 2012-08-15 19:59 ` Kent Yoder
  3 siblings, 0 replies; 19+ messages in thread
From: Kent Yoder @ 2012-08-15 19:59 UTC (permalink / raw)
  To: Ashley Lai
  Cc: linux-kernel, linux-security-module, tpmdd-devel, benh,
	linuxppc-dev, rcj, adlai

On Tue, Aug 14, 2012 at 06:23:58PM -0500, Ashley Lai wrote:
> Change log V3:
> - Replaced TPM_NO_EVENT_LOG macro with stubs
> - Removed tpm_noeventlog.c file 
> - Called of_node_put() before return in tpm_of.c
> 
> Change log V2:
> - Removed unnecessary tpm_bios_log_setup and tpm_bios_log_teardown
>   functions in tpm_eventlog.h (patch 3/3).
> - Added more descriptions on vTPM (patch 1/3).
> 
> These patches add support for IBM vTPM for PPC64. This new device driver
> works on firmware that supports vTPM (firmware release 740 or higher).
> 
> Tested on Power7+ system with firmware level ZM770_001.
> 
> Applied to Kent Yoder tree at:
> https://github.com/shpedoikal/linux/tree/v3.6-rc1-tpmdd-staging

  Thanks Ashley, I've added the patches to that tree.

Kent

> 
> Ashley Lai (3):
>   drivers/char/tpm: Add new device driver to support IBM vTPM
>   PPC64: Add support for instantiating SML from Open Firmware
>   drivers/char/tpm: Add securityfs support for event log
> 
>  arch/powerpc/kernel/prom_init.c |   62 ++++
>  drivers/char/tpm/Kconfig        |    8 +
>  drivers/char/tpm/Makefile       |    6 +
>  drivers/char/tpm/tpm.h          |   13 +-
>  drivers/char/tpm/tpm_eventlog.h |   15 +
>  drivers/char/tpm/tpm_ibmvtpm.c  |  749 +++++++++++++++++++++++++++++++++++++++
>  drivers/char/tpm/tpm_ibmvtpm.h  |   83 +++++
>  drivers/char/tpm/tpm_of.c       |   73 ++++
>  8 files changed, 997 insertions(+), 12 deletions(-)
>  create mode 100644 drivers/char/tpm/tpm_ibmvtpm.c
>  create mode 100644 drivers/char/tpm/tpm_ibmvtpm.h
>  create mode 100644 drivers/char/tpm/tpm_of.c
> 
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-08-14 23:34 ` [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM Ashley Lai
@ 2012-08-22 21:17   ` Ashley Lai
  2012-08-22 21:42     ` Kent Yoder
  2012-09-12 17:49     ` [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup Ashley Lai
  0 siblings, 2 replies; 19+ messages in thread
From: Ashley Lai @ 2012-08-22 21:17 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, tpmdd-devel, benh, linuxppc-dev, rcj, key,
	adlai, adlai

This patch adds a new device driver to support IBM virtual TPM
(vTPM) for PPC64.  IBM vTPM is supported through the adjunct
partition with firmware release 740 or higher.  With vTPM
support, each lpar is able to have its own vTPM without the
physical TPM hardware.

This driver provides TPM functionalities by communicating with
the vTPM adjunct partition through Hypervisor calls (Hcalls)
and Command/Response Queue (CRQ) commands.

Signed-off-by: Ashley Lai <adlai@us.ibm.com>
---

Oopps... I forgot to remove some invalid comments.  Please use this patch for 1/3.

 drivers/char/tpm/Kconfig       |    8 +
 drivers/char/tpm/Makefile      |    1 +
 drivers/char/tpm/tpm.h         |    1 +
 drivers/char/tpm/tpm_ibmvtpm.c |  749 ++++++++++++++++++++++++++++++++++++++++
 drivers/char/tpm/tpm_ibmvtpm.h |   77 ++++
 5 files changed, 836 insertions(+), 0 deletions(-)
 create mode 100644 drivers/char/tpm/tpm_ibmvtpm.c
 create mode 100644 drivers/char/tpm/tpm_ibmvtpm.h

diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index c4aac48..915875e 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -73,4 +73,12 @@ config TCG_INFINEON
 	  Further information on this driver and the supported hardware
 	  can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 

+config TCG_IBMVTPM
+	tristate "IBM VTPM Interface"
+	depends on PPC64
+	---help---
+	  If you have IBM virtual TPM (VTPM) support say Yes and it
+	  will be accessible from within Linux.  To compile this driver
+	  as a module, choose M here; the module will be called tpm_ibmvtpm.
+
 endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index beac52f..547509d 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
 obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
+obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 645136e..870fde7 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -100,6 +100,7 @@ struct tpm_vendor_specific {
 	bool timeout_adjusted;
 	unsigned long duration[3]; /* jiffies */
 	bool duration_adjusted;
+	void *data;
 
 	wait_queue_head_t read_queue;
 	wait_queue_head_t int_queue;
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
new file mode 100644
index 0000000..efc4ab3
--- /dev/null
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2012 IBM Corporation
+ *
+ * Author: Ashley Lai <adlai@us.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/slab.h>
+#include <asm/vio.h>
+#include <asm/irq.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <asm/prom.h>
+
+#include "tpm.h"
+#include "tpm_ibmvtpm.h"
+
+static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm";
+
+static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = {
+	{ "IBM,vtpm", "IBM,vtpm"},
+	{ "", "" }
+};
+MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
+
+DECLARE_WAIT_QUEUE_HEAD(wq);
+
+/**
+ * ibmvtpm_send_crq - Send a CRQ request
+ * @vdev:	vio device struct
+ * @w1:		first word
+ * @w2:		second word
+ *
+ * Return value:
+ *	0 -Sucess
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2)
+{
+	return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2);
+}
+
+/**
+ * ibmvtpm_get_data - Retrieve ibm vtpm data
+ * @dev:	device struct
+ *
+ * Return value:
+ *	vtpm device struct
+ */
+static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev)
+{
+	struct tpm_chip *chip = dev_get_drvdata(dev);
+	if (chip)
+		return (struct ibmvtpm_dev *)chip->vendor.data;
+	return NULL;
+}
+
+/**
+ * tpm_ibmvtpm_recv - Receive data after send
+ * @chip:	tpm chip struct
+ * @buf:	buffer to read
+ * count:	size of buffer
+ *
+ * Return value:
+ *	Number of bytes read
+ */
+static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+	struct ibmvtpm_dev *ibmvtpm;
+	u16 len;
+
+	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
+
+	if (!ibmvtpm->rtce_buf) {
+		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
+		return 0;
+	}
+
+	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
+
+	if (count < ibmvtpm->crq_res.len) {
+		dev_err(ibmvtpm->dev,
+			"Invalid size in recv: count=%ld, crq_size=%d\n",
+			count, ibmvtpm->crq_res.len);
+		return -EIO;
+	}
+
+	spin_lock(&ibmvtpm->rtce_lock);
+	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len);
+	memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len);
+	ibmvtpm->crq_res.valid = 0;
+	ibmvtpm->crq_res.msg = 0;
+	len = ibmvtpm->crq_res.len;
+	ibmvtpm->crq_res.len = 0;
+	spin_unlock(&ibmvtpm->rtce_lock);
+	return len;
+}
+
+/**
+ * tpm_ibmvtpm_send - Send tpm request
+ * @chip:	tpm chip struct
+ * @buf:	buffer contains data to send
+ * count:	size of buffer
+ *
+ * Return value:
+ *	Number of bytes sent
+ */
+static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+	struct ibmvtpm_dev *ibmvtpm;
+	struct ibmvtpm_crq crq;
+	u64 *word = (u64 *) &crq;
+	int rc;
+
+	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
+
+	if (!ibmvtpm->rtce_buf) {
+		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
+		return 0;
+	}
+
+	if (count > ibmvtpm->rtce_size) {
+		dev_err(ibmvtpm->dev,
+			"Invalid size in send: count=%ld, rtce_size=%d\n",
+			count, ibmvtpm->rtce_size);
+		return -EIO;
+	}
+
+	spin_lock(&ibmvtpm->rtce_lock);
+	memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_TPM_COMMAND;
+	crq.len = (u16)count;
+	crq.data = ibmvtpm->rtce_dma_handle;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]);
+	if (rc != H_SUCCESS) {
+		dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
+		rc = 0;
+	} else
+		rc = count;
+
+	spin_unlock(&ibmvtpm->rtce_lock);
+	return rc;
+}
+
+static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
+{
+	return;
+}
+
+static u8 tpm_ibmvtpm_status(struct tpm_chip *chip)
+{
+	return 0;
+}
+
+/**
+ * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
+{
+	struct ibmvtpm_crq crq;
+	u64 *buf = (u64 *) &crq;
+	int rc;
+
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version
+ *			   - Note that this is vtpm version and not tpm version
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
+{
+	struct ibmvtpm_crq crq;
+	u64 *buf = (u64 *) &crq;
+	int rc;
+
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_GET_VERSION;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_get_version failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_send_init_complete failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_crq_send_init - Send a CRQ initialize message
+ * @ibmvtpm:	vtpm device struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"ibmvtpm_crq_send_init failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * tpm_ibmvtpm_remove - ibm vtpm remove entry point
+ * @vdev:	vio device struct
+ *
+ * Return value:
+ *	0
+ */
+static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+	int rc = 0;
+
+	free_irq(vdev->irq, ibmvtpm);
+	tasklet_kill(&ibmvtpm->tasklet);
+
+	do {
+		if (rc)
+			msleep(100);
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	dma_unmap_single(ibmvtpm->dev, ibmvtpm->crq_dma_handle,
+			 CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL);
+	free_page((unsigned long)ibmvtpm->crq_queue.crq_addr);
+
+	if (ibmvtpm->rtce_buf) {
+		dma_unmap_single(ibmvtpm->dev, ibmvtpm->rtce_dma_handle,
+				 ibmvtpm->rtce_size, DMA_BIDIRECTIONAL);
+		kfree(ibmvtpm->rtce_buf);
+	}
+
+	tpm_remove_hardware(ibmvtpm->dev);
+
+	kfree(ibmvtpm);
+
+	return 0;
+}
+
+/**
+ * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver
+ * @vdev:	vio device struct
+ *
+ * Return value:
+ *	Number of bytes the driver needs to DMA map
+ */
+static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+	return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
+}
+
+/**
+ * tpm_ibmvtpm_suspend - Suspend
+ * @dev:	device struct
+ *
+ * Return value:
+ *	0
+ */
+static int tpm_ibmvtpm_suspend(struct device *dev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
+	struct ibmvtpm_crq crq;
+	u64 *buf = (u64 *) &crq;
+	int rc = 0;
+
+	crq.valid = (u8)IBMVTPM_VALID_CMD;
+	crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND;
+
+	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+	if (rc != H_SUCCESS)
+		dev_err(ibmvtpm->dev,
+			"tpm_ibmvtpm_suspend failed rc=%d\n", rc);
+
+	return rc;
+}
+
+/**
+ * ibmvtpm_reset_crq - Reset CRQ
+ * @ibmvtpm:	ibm vtpm struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc = 0;
+
+	do {
+		if (rc)
+			msleep(100);
+		rc = plpar_hcall_norets(H_FREE_CRQ,
+					ibmvtpm->vdev->unit_address);
+	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	memset(ibmvtpm->crq_queue.crq_addr, 0, CRQ_RES_BUF_SIZE);
+	ibmvtpm->crq_queue.index = 0;
+
+	return plpar_hcall_norets(H_REG_CRQ, ibmvtpm->vdev->unit_address,
+				  ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
+}
+
+/**
+ * tpm_ibmvtpm_resume - Resume from suspend
+ * @dev:	device struct
+ *
+ * Return value:
+ *	0
+ */
+static int tpm_ibmvtpm_resume(struct device *dev)
+{
+	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
+	unsigned long flags;
+	int rc = 0;
+
+	do {
+		if (rc)
+			msleep(100);
+		rc = plpar_hcall_norets(H_ENABLE_CRQ,
+					ibmvtpm->vdev->unit_address);
+	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
+
+	if (rc) {
+		dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
+		return rc;
+	}
+
+	spin_lock_irqsave(&ibmvtpm->lock, flags);
+	vio_disable_interrupts(ibmvtpm->vdev);
+	tasklet_schedule(&ibmvtpm->tasklet);
+	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+
+	rc = ibmvtpm_crq_send_init(ibmvtpm);
+	if (rc)
+		dev_err(dev, "Error send_init rc=%d\n", rc);
+
+	return rc;
+}
+
+static const struct file_operations ibmvtpm_ops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.open = tpm_open,
+	.read = tpm_read,
+	.write = tpm_write,
+	.release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
+static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
+static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
+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 *ibmvtpm_attrs[] = {
+	&dev_attr_pubek.attr,
+	&dev_attr_pcrs.attr,
+	&dev_attr_enabled.attr,
+	&dev_attr_active.attr,
+	&dev_attr_owned.attr,
+	&dev_attr_temp_deactivated.attr,
+	&dev_attr_caps.attr,
+	&dev_attr_cancel.attr,
+	&dev_attr_durations.attr,
+	&dev_attr_timeouts.attr, NULL,
+};
+
+static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs };
+
+static const struct tpm_vendor_specific tpm_ibmvtpm = {
+	.recv = tpm_ibmvtpm_recv,
+	.send = tpm_ibmvtpm_send,
+	.cancel = tpm_ibmvtpm_cancel,
+	.status = tpm_ibmvtpm_status,
+	.req_complete_mask = 0,
+	.req_complete_val = 0,
+	.req_canceled = 0,
+	.attr_group = &ibmvtpm_attr_grp,
+	.miscdev = { .fops = &ibmvtpm_ops, },
+};
+
+static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = {
+	.suspend = tpm_ibmvtpm_suspend,
+	.resume = tpm_ibmvtpm_resume,
+};
+
+/**
+ * ibmvtpm_crq_get_next - Get next responded crq
+ * @ibmvtpm	vtpm device struct
+ *
+ * Return value:
+ *	vtpm crq pointer
+ */
+static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
+{
+	struct ibmvtpm_crq_queue *crq_q = &ibmvtpm->crq_queue;
+	struct ibmvtpm_crq *crq = &crq_q->crq_addr[crq_q->index];
+
+	if (crq->valid & VTPM_MSG_RES) {
+		if (++crq_q->index == crq_q->num_entry)
+			crq_q->index = 0;
+		rmb();
+	} else
+		crq = NULL;
+	return crq;
+}
+
+/**
+ * ibmvtpm_crq_process - Process responded crq
+ * @crq		crq to be processed
+ * @ibmvtpm	vtpm device struct
+ *
+ * Return value:
+ *	Nothing
+ */
+static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
+				struct ibmvtpm_dev *ibmvtpm)
+{
+	int rc = 0;
+
+	switch (crq->valid) {
+	case VALID_INIT_CRQ:
+		switch (crq->msg) {
+		case INIT_CRQ_RES:
+			dev_info(ibmvtpm->dev, "CRQ initialized\n");
+			rc = ibmvtpm_crq_send_init_complete(ibmvtpm);
+			if (rc)
+				dev_err(ibmvtpm->dev, "Unable to send CRQ init complete rc=%d\n", rc);
+			return;
+		case INIT_CRQ_COMP_RES:
+			dev_info(ibmvtpm->dev,
+				 "CRQ initialization completed\n");
+			return;
+		default:
+			dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg);
+			return;
+		}
+		return;
+	case IBMVTPM_VALID_CMD:
+		switch (crq->msg) {
+		case VTPM_GET_RTCE_BUFFER_SIZE_RES:
+			if (crq->len <= 0) {
+				dev_err(ibmvtpm->dev, "Invalid rtce size\n");
+				return;
+			}
+			ibmvtpm->rtce_size = crq->len;
+			ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
+						    GFP_KERNEL);
+			if (!ibmvtpm->rtce_buf) {
+				dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
+				return;
+			}
+
+			ibmvtpm->rtce_dma_handle = dma_map_single(ibmvtpm->dev,
+				ibmvtpm->rtce_buf, ibmvtpm->rtce_size,
+				DMA_BIDIRECTIONAL);
+
+			if (dma_mapping_error(ibmvtpm->dev,
+					      ibmvtpm->rtce_dma_handle)) {
+				kfree(ibmvtpm->rtce_buf);
+				ibmvtpm->rtce_buf = NULL;
+				dev_err(ibmvtpm->dev, "Failed to dma map rtce buffer\n");
+			}
+
+			return;
+		case VTPM_GET_VERSION_RES:
+			ibmvtpm->vtpm_version = crq->data;
+			return;
+		case VTPM_TPM_COMMAND_RES:
+			ibmvtpm->crq_res.valid = crq->valid;
+			ibmvtpm->crq_res.msg = crq->msg;
+			ibmvtpm->crq_res.len = crq->len;
+			ibmvtpm->crq_res.data = crq->data;
+			wake_up_interruptible(&wq);
+			return;
+		default:
+			return;
+		}
+	}
+	return;
+}
+
+/**
+ * ibmvtpm_interrupt -	Interrupt handler
+ * @irq:		irq number to handle
+ * @vtpm_instance:	vtpm that received interrupt
+ *
+ * Returns:
+ *	IRQ_HANDLED
+ **/
+static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
+{
+	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ibmvtpm->lock, flags);
+	vio_disable_interrupts(ibmvtpm->vdev);
+	tasklet_schedule(&ibmvtpm->tasklet);
+	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ibmvtpm_tasklet - Interrupt handler tasklet
+ * @data:	ibm vtpm device struct
+ *
+ * Returns:
+ *	Nothing
+ **/
+static void ibmvtpm_tasklet(void *data)
+{
+	struct ibmvtpm_dev *ibmvtpm = data;
+	struct ibmvtpm_crq *crq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ibmvtpm->lock, flags);
+	while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
+		ibmvtpm_crq_process(crq, ibmvtpm);
+		crq->valid = 0;
+		wmb();
+	}
+
+	vio_enable_interrupts(ibmvtpm->vdev);
+	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+}
+
+/**
+ * tpm_ibmvtpm_probe - ibm vtpm initialize entry point
+ * @vio_dev:	vio device struct
+ * @id:		vio device id struct
+ *
+ * Return value:
+ *	0 - Success
+ *	Non-zero - Failure
+ */
+static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
+				   const struct vio_device_id *id)
+{
+	struct ibmvtpm_dev *ibmvtpm;
+	struct device *dev = &vio_dev->dev;
+	struct ibmvtpm_crq_queue *crq_q;
+	struct tpm_chip *chip;
+	int rc = -ENOMEM, rc1;
+
+	chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
+	if (!chip) {
+		dev_err(dev, "tpm_register_hardware failed\n");
+		return -ENODEV;
+	}
+
+	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
+	if (!ibmvtpm) {
+		dev_err(dev, "kzalloc for ibmvtpm failed\n");
+		goto cleanup;
+	}
+
+	crq_q = &ibmvtpm->crq_queue;
+	crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL);
+	if (!crq_q->crq_addr) {
+		dev_err(dev, "Unable to allocate memory for crq_addr\n");
+		goto cleanup;
+	}
+
+	crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr);
+	ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr,
+						 CRQ_RES_BUF_SIZE,
+						 DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) {
+		dev_err(dev, "dma mapping failed\n");
+		goto cleanup;
+	}
+
+	rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address,
+				ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
+	if (rc == H_RESOURCE)
+		rc = ibmvtpm_reset_crq(ibmvtpm);
+
+	if (rc) {
+		dev_err(dev, "Unable to register CRQ rc=%d\n", rc);
+		goto reg_crq_cleanup;
+	}
+
+	tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet,
+		     (unsigned long)ibmvtpm);
+
+	rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0,
+			 tpm_ibmvtpm_driver_name, ibmvtpm);
+	if (rc) {
+		dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq);
+		goto init_irq_cleanup;
+	}
+
+	rc = vio_enable_interrupts(vio_dev);
+	if (rc) {
+		dev_err(dev, "Error %d enabling interrupts\n", rc);
+		goto init_irq_cleanup;
+	}
+
+	crq_q->index = 0;
+
+	ibmvtpm->dev = dev;
+	ibmvtpm->vdev = vio_dev;
+	chip->vendor.data = (void *)ibmvtpm;
+
+	spin_lock_init(&ibmvtpm->lock);
+	spin_lock_init(&ibmvtpm->rtce_lock);
+
+	rc = ibmvtpm_crq_send_init(ibmvtpm);
+	if (rc)
+		goto init_irq_cleanup;
+
+	rc = ibmvtpm_crq_get_version(ibmvtpm);
+	if (rc)
+		goto init_irq_cleanup;
+
+	rc = ibmvtpm_crq_get_rtce_size(ibmvtpm);
+	if (rc)
+		goto init_irq_cleanup;
+
+	return rc;
+init_irq_cleanup:
+	tasklet_kill(&ibmvtpm->tasklet);
+	do {
+		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
+	} while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1));
+reg_crq_cleanup:
+	dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE,
+			 DMA_BIDIRECTIONAL);
+cleanup:
+	if (ibmvtpm) {
+		if (crq_q->crq_addr)
+			free_page((unsigned long)crq_q->crq_addr);
+		kfree(ibmvtpm);
+	}
+
+	tpm_remove_hardware(dev);
+
+	return rc;
+}
+
+static struct vio_driver ibmvtpm_driver = {
+	.id_table	 = tpm_ibmvtpm_device_table,
+	.probe		 = tpm_ibmvtpm_probe,
+	.remove		 = tpm_ibmvtpm_remove,
+	.get_desired_dma = tpm_ibmvtpm_get_desired_dma,
+	.name		 = tpm_ibmvtpm_driver_name,
+	.pm		 = &tpm_ibmvtpm_pm_ops,
+};
+
+/**
+ * ibmvtpm_module_init - Initialize ibm vtpm module
+ *
+ * Return value:
+ *	0 -Success
+ *	Non-zero - Failure
+ */
+static int __init ibmvtpm_module_init(void)
+{
+	return vio_register_driver(&ibmvtpm_driver);
+}
+
+/**
+ * ibmvtpm_module_exit - Teardown ibm vtpm module
+ *
+ * Return value:
+ *	Nothing
+ */
+static void __exit ibmvtpm_module_exit(void)
+{
+	vio_unregister_driver(&ibmvtpm_driver);
+}
+
+module_init(ibmvtpm_module_init);
+module_exit(ibmvtpm_module_exit);
+
+MODULE_AUTHOR("adlai@us.ibm.com");
+MODULE_DESCRIPTION("IBM vTPM Driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
new file mode 100644
index 0000000..4296eb4
--- /dev/null
+++ b/drivers/char/tpm/tpm_ibmvtpm.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 IBM Corporation
+ *
+ * Author: Ashley Lai <adlai@us.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+
+#ifndef __TPM_IBMVTPM_H__
+#define __TPM_IBMVTPM_H__
+
+/* vTPM Message Format 1 */
+struct ibmvtpm_crq {
+	u8 valid;
+	u8 msg;
+	u16 len;
+	u32 data;
+	u64 reserved;
+} __attribute__((packed, aligned(8)));
+
+struct ibmvtpm_crq_queue {
+	struct ibmvtpm_crq *crq_addr;
+	u32 index;
+	u32 num_entry;
+};
+
+struct ibmvtpm_dev {
+	struct device *dev;
+	struct vio_dev *vdev;
+	struct ibmvtpm_crq_queue crq_queue;
+	dma_addr_t crq_dma_handle;
+	spinlock_t lock;
+	struct tasklet_struct tasklet;
+	u32 rtce_size;
+	void __iomem *rtce_buf;
+	dma_addr_t rtce_dma_handle;
+	spinlock_t rtce_lock;
+	struct ibmvtpm_crq crq_res;
+	u32 vtpm_version;
+};
+
+#define CRQ_RES_BUF_SIZE	PAGE_SIZE
+
+/* Initialize CRQ */
+#define INIT_CRQ_CMD		0xC001000000000000LL /* Init cmd */
+#define INIT_CRQ_COMP_CMD	0xC002000000000000LL /* Init complete cmd */
+#define INIT_CRQ_RES		0x01	/* Init respond */
+#define INIT_CRQ_COMP_RES	0x02	/* Init complete respond */
+#define VALID_INIT_CRQ		0xC0	/* Valid command for init crq */
+
+/* vTPM CRQ response is the message type | 0x80 */
+#define VTPM_MSG_RES		0x80
+#define IBMVTPM_VALID_CMD	0x80
+
+/* vTPM CRQ message types */
+#define VTPM_GET_VERSION			0x01
+#define VTPM_GET_VERSION_RES			(0x01 | VTPM_MSG_RES)
+
+#define VTPM_TPM_COMMAND			0x02
+#define VTPM_TPM_COMMAND_RES			(0x02 | VTPM_MSG_RES)
+
+#define VTPM_GET_RTCE_BUFFER_SIZE		0x03
+#define VTPM_GET_RTCE_BUFFER_SIZE_RES		(0x03 | VTPM_MSG_RES)
+
+#define VTPM_PREPARE_TO_SUSPEND			0x04
+#define VTPM_PREPARE_TO_SUSPEND_RES		(0x04 | VTPM_MSG_RES)
+
+#endif
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-08-22 21:17   ` Ashley Lai
@ 2012-08-22 21:42     ` Kent Yoder
  2012-09-05  3:40       ` Benjamin Herrenschmidt
  2012-09-12 17:49     ` [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup Ashley Lai
  1 sibling, 1 reply; 19+ messages in thread
From: Kent Yoder @ 2012-08-22 21:42 UTC (permalink / raw)
  To: Ashley Lai
  Cc: linux-kernel, linux-security-module, tpmdd-devel, benh,
	linuxppc-dev, rcj, adlai

On Wed, Aug 22, 2012 at 04:17:43PM -0500, Ashley Lai wrote:
> This patch adds a new device driver to support IBM virtual TPM
> (vTPM) for PPC64.  IBM vTPM is supported through the adjunct
> partition with firmware release 740 or higher.  With vTPM
> support, each lpar is able to have its own vTPM without the
> physical TPM hardware.
> 
> This driver provides TPM functionalities by communicating with
> the vTPM adjunct partition through Hypervisor calls (Hcalls)
> and Command/Response Queue (CRQ) commands.

 Thanks Ashley, I'll include this in my next pull request to James.

Kent

> Signed-off-by: Ashley Lai <adlai@us.ibm.com>
> ---
> 
> Oopps... I forgot to remove some invalid comments.  Please use this patch for 1/3.
> 
>  drivers/char/tpm/Kconfig       |    8 +
>  drivers/char/tpm/Makefile      |    1 +
>  drivers/char/tpm/tpm.h         |    1 +
>  drivers/char/tpm/tpm_ibmvtpm.c |  749 ++++++++++++++++++++++++++++++++++++++++
>  drivers/char/tpm/tpm_ibmvtpm.h |   77 ++++
>  5 files changed, 836 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/char/tpm/tpm_ibmvtpm.c
>  create mode 100644 drivers/char/tpm/tpm_ibmvtpm.h
> 
> diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
> index c4aac48..915875e 100644
> --- a/drivers/char/tpm/Kconfig
> +++ b/drivers/char/tpm/Kconfig
> @@ -73,4 +73,12 @@ config TCG_INFINEON
>  	  Further information on this driver and the supported hardware
>  	  can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ 
> 
> +config TCG_IBMVTPM
> +	tristate "IBM VTPM Interface"
> +	depends on PPC64
> +	---help---
> +	  If you have IBM virtual TPM (VTPM) support say Yes and it
> +	  will be accessible from within Linux.  To compile this driver
> +	  as a module, choose M here; the module will be called tpm_ibmvtpm.
> +
>  endif # TCG_TPM
> diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
> index beac52f..547509d 100644
> --- a/drivers/char/tpm/Makefile
> +++ b/drivers/char/tpm/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
>  obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
>  obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
>  obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
> +obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
> diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
> index 645136e..870fde7 100644
> --- a/drivers/char/tpm/tpm.h
> +++ b/drivers/char/tpm/tpm.h
> @@ -100,6 +100,7 @@ struct tpm_vendor_specific {
>  	bool timeout_adjusted;
>  	unsigned long duration[3]; /* jiffies */
>  	bool duration_adjusted;
> +	void *data;
> 
>  	wait_queue_head_t read_queue;
>  	wait_queue_head_t int_queue;
> diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
> new file mode 100644
> index 0000000..efc4ab3
> --- /dev/null
> +++ b/drivers/char/tpm/tpm_ibmvtpm.c
> @@ -0,0 +1,749 @@
> +/*
> + * Copyright (C) 2012 IBM Corporation
> + *
> + * Author: Ashley Lai <adlai@us.ibm.com>
> + *
> + * Maintained by: <tpmdd-devel@lists.sourceforge.net>
> + *
> + * Device driver for TCG/TCPA TPM (trusted platform module).
> + * Specifications at www.trustedcomputinggroup.org
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation, version 2 of the
> + * License.
> + *
> + */
> +
> +#include <linux/dma-mapping.h>
> +#include <linux/dmapool.h>
> +#include <linux/slab.h>
> +#include <asm/vio.h>
> +#include <asm/irq.h>
> +#include <linux/types.h>
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/interrupt.h>
> +#include <linux/wait.h>
> +#include <asm/prom.h>
> +
> +#include "tpm.h"
> +#include "tpm_ibmvtpm.h"
> +
> +static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm";
> +
> +static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = {
> +	{ "IBM,vtpm", "IBM,vtpm"},
> +	{ "", "" }
> +};
> +MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
> +
> +DECLARE_WAIT_QUEUE_HEAD(wq);
> +
> +/**
> + * ibmvtpm_send_crq - Send a CRQ request
> + * @vdev:	vio device struct
> + * @w1:		first word
> + * @w2:		second word
> + *
> + * Return value:
> + *	0 -Sucess
> + *	Non-zero - Failure
> + */
> +static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2)
> +{
> +	return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2);
> +}
> +
> +/**
> + * ibmvtpm_get_data - Retrieve ibm vtpm data
> + * @dev:	device struct
> + *
> + * Return value:
> + *	vtpm device struct
> + */
> +static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev)
> +{
> +	struct tpm_chip *chip = dev_get_drvdata(dev);
> +	if (chip)
> +		return (struct ibmvtpm_dev *)chip->vendor.data;
> +	return NULL;
> +}
> +
> +/**
> + * tpm_ibmvtpm_recv - Receive data after send
> + * @chip:	tpm chip struct
> + * @buf:	buffer to read
> + * count:	size of buffer
> + *
> + * Return value:
> + *	Number of bytes read
> + */
> +static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
> +{
> +	struct ibmvtpm_dev *ibmvtpm;
> +	u16 len;
> +
> +	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
> +
> +	if (!ibmvtpm->rtce_buf) {
> +		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
> +		return 0;
> +	}
> +
> +	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
> +
> +	if (count < ibmvtpm->crq_res.len) {
> +		dev_err(ibmvtpm->dev,
> +			"Invalid size in recv: count=%ld, crq_size=%d\n",
> +			count, ibmvtpm->crq_res.len);
> +		return -EIO;
> +	}
> +
> +	spin_lock(&ibmvtpm->rtce_lock);
> +	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len);
> +	memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len);
> +	ibmvtpm->crq_res.valid = 0;
> +	ibmvtpm->crq_res.msg = 0;
> +	len = ibmvtpm->crq_res.len;
> +	ibmvtpm->crq_res.len = 0;
> +	spin_unlock(&ibmvtpm->rtce_lock);
> +	return len;
> +}
> +
> +/**
> + * tpm_ibmvtpm_send - Send tpm request
> + * @chip:	tpm chip struct
> + * @buf:	buffer contains data to send
> + * count:	size of buffer
> + *
> + * Return value:
> + *	Number of bytes sent
> + */
> +static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
> +{
> +	struct ibmvtpm_dev *ibmvtpm;
> +	struct ibmvtpm_crq crq;
> +	u64 *word = (u64 *) &crq;
> +	int rc;
> +
> +	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
> +
> +	if (!ibmvtpm->rtce_buf) {
> +		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
> +		return 0;
> +	}
> +
> +	if (count > ibmvtpm->rtce_size) {
> +		dev_err(ibmvtpm->dev,
> +			"Invalid size in send: count=%ld, rtce_size=%d\n",
> +			count, ibmvtpm->rtce_size);
> +		return -EIO;
> +	}
> +
> +	spin_lock(&ibmvtpm->rtce_lock);
> +	memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
> +	crq.valid = (u8)IBMVTPM_VALID_CMD;
> +	crq.msg = (u8)VTPM_TPM_COMMAND;
> +	crq.len = (u16)count;
> +	crq.data = ibmvtpm->rtce_dma_handle;
> +
> +	rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]);
> +	if (rc != H_SUCCESS) {
> +		dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
> +		rc = 0;
> +	} else
> +		rc = count;
> +
> +	spin_unlock(&ibmvtpm->rtce_lock);
> +	return rc;
> +}
> +
> +static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
> +{
> +	return;
> +}
> +
> +static u8 tpm_ibmvtpm_status(struct tpm_chip *chip)
> +{
> +	return 0;
> +}
> +
> +/**
> + * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size
> + * @ibmvtpm:	vtpm device struct
> + *
> + * Return value:
> + *	0 - Success
> + *	Non-zero - Failure
> + */
> +static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
> +{
> +	struct ibmvtpm_crq crq;
> +	u64 *buf = (u64 *) &crq;
> +	int rc;
> +
> +	crq.valid = (u8)IBMVTPM_VALID_CMD;
> +	crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE;
> +
> +	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
> +	if (rc != H_SUCCESS)
> +		dev_err(ibmvtpm->dev,
> +			"ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
> +
> +	return rc;
> +}
> +
> +/**
> + * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version
> + *			   - Note that this is vtpm version and not tpm version
> + * @ibmvtpm:	vtpm device struct
> + *
> + * Return value:
> + *	0 - Success
> + *	Non-zero - Failure
> + */
> +static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
> +{
> +	struct ibmvtpm_crq crq;
> +	u64 *buf = (u64 *) &crq;
> +	int rc;
> +
> +	crq.valid = (u8)IBMVTPM_VALID_CMD;
> +	crq.msg = (u8)VTPM_GET_VERSION;
> +
> +	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
> +	if (rc != H_SUCCESS)
> +		dev_err(ibmvtpm->dev,
> +			"ibmvtpm_crq_get_version failed rc=%d\n", rc);
> +
> +	return rc;
> +}
> +
> +/**
> + * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message
> + * @ibmvtpm:	vtpm device struct
> + *
> + * Return value:
> + *	0 - Success
> + *	Non-zero - Failure
> + */
> +static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
> +{
> +	int rc;
> +
> +	rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0);
> +	if (rc != H_SUCCESS)
> +		dev_err(ibmvtpm->dev,
> +			"ibmvtpm_crq_send_init_complete failed rc=%d\n", rc);
> +
> +	return rc;
> +}
> +
> +/**
> + * ibmvtpm_crq_send_init - Send a CRQ initialize message
> + * @ibmvtpm:	vtpm device struct
> + *
> + * Return value:
> + *	0 - Success
> + *	Non-zero - Failure
> + */
> +static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
> +{
> +	int rc;
> +
> +	rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0);
> +	if (rc != H_SUCCESS)
> +		dev_err(ibmvtpm->dev,
> +			"ibmvtpm_crq_send_init failed rc=%d\n", rc);
> +
> +	return rc;
> +}
> +
> +/**
> + * tpm_ibmvtpm_remove - ibm vtpm remove entry point
> + * @vdev:	vio device struct
> + *
> + * Return value:
> + *	0
> + */
> +static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev)
> +{
> +	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
> +	int rc = 0;
> +
> +	free_irq(vdev->irq, ibmvtpm);
> +	tasklet_kill(&ibmvtpm->tasklet);
> +
> +	do {
> +		if (rc)
> +			msleep(100);
> +		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
> +	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
> +
> +	dma_unmap_single(ibmvtpm->dev, ibmvtpm->crq_dma_handle,
> +			 CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL);
> +	free_page((unsigned long)ibmvtpm->crq_queue.crq_addr);
> +
> +	if (ibmvtpm->rtce_buf) {
> +		dma_unmap_single(ibmvtpm->dev, ibmvtpm->rtce_dma_handle,
> +				 ibmvtpm->rtce_size, DMA_BIDIRECTIONAL);
> +		kfree(ibmvtpm->rtce_buf);
> +	}
> +
> +	tpm_remove_hardware(ibmvtpm->dev);
> +
> +	kfree(ibmvtpm);
> +
> +	return 0;
> +}
> +
> +/**
> + * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver
> + * @vdev:	vio device struct
> + *
> + * Return value:
> + *	Number of bytes the driver needs to DMA map
> + */
> +static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
> +{
> +	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
> +	return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
> +}
> +
> +/**
> + * tpm_ibmvtpm_suspend - Suspend
> + * @dev:	device struct
> + *
> + * Return value:
> + *	0
> + */
> +static int tpm_ibmvtpm_suspend(struct device *dev)
> +{
> +	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
> +	struct ibmvtpm_crq crq;
> +	u64 *buf = (u64 *) &crq;
> +	int rc = 0;
> +
> +	crq.valid = (u8)IBMVTPM_VALID_CMD;
> +	crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND;
> +
> +	rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
> +	if (rc != H_SUCCESS)
> +		dev_err(ibmvtpm->dev,
> +			"tpm_ibmvtpm_suspend failed rc=%d\n", rc);
> +
> +	return rc;
> +}
> +
> +/**
> + * ibmvtpm_reset_crq - Reset CRQ
> + * @ibmvtpm:	ibm vtpm struct
> + *
> + * Return value:
> + *	0 - Success
> + *	Non-zero - Failure
> + */
> +static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
> +{
> +	int rc = 0;
> +
> +	do {
> +		if (rc)
> +			msleep(100);
> +		rc = plpar_hcall_norets(H_FREE_CRQ,
> +					ibmvtpm->vdev->unit_address);
> +	} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
> +
> +	memset(ibmvtpm->crq_queue.crq_addr, 0, CRQ_RES_BUF_SIZE);
> +	ibmvtpm->crq_queue.index = 0;
> +
> +	return plpar_hcall_norets(H_REG_CRQ, ibmvtpm->vdev->unit_address,
> +				  ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
> +}
> +
> +/**
> + * tpm_ibmvtpm_resume - Resume from suspend
> + * @dev:	device struct
> + *
> + * Return value:
> + *	0
> + */
> +static int tpm_ibmvtpm_resume(struct device *dev)
> +{
> +	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
> +	unsigned long flags;
> +	int rc = 0;
> +
> +	do {
> +		if (rc)
> +			msleep(100);
> +		rc = plpar_hcall_norets(H_ENABLE_CRQ,
> +					ibmvtpm->vdev->unit_address);
> +	} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
> +
> +	if (rc) {
> +		dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
> +		return rc;
> +	}
> +
> +	spin_lock_irqsave(&ibmvtpm->lock, flags);
> +	vio_disable_interrupts(ibmvtpm->vdev);
> +	tasklet_schedule(&ibmvtpm->tasklet);
> +	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> +
> +	rc = ibmvtpm_crq_send_init(ibmvtpm);
> +	if (rc)
> +		dev_err(dev, "Error send_init rc=%d\n", rc);
> +
> +	return rc;
> +}
> +
> +static const struct file_operations ibmvtpm_ops = {
> +	.owner = THIS_MODULE,
> +	.llseek = no_llseek,
> +	.open = tpm_open,
> +	.read = tpm_read,
> +	.write = tpm_write,
> +	.release = tpm_release,
> +};
> +
> +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
> +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
> +static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL);
> +static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL);
> +static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL);
> +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 *ibmvtpm_attrs[] = {
> +	&dev_attr_pubek.attr,
> +	&dev_attr_pcrs.attr,
> +	&dev_attr_enabled.attr,
> +	&dev_attr_active.attr,
> +	&dev_attr_owned.attr,
> +	&dev_attr_temp_deactivated.attr,
> +	&dev_attr_caps.attr,
> +	&dev_attr_cancel.attr,
> +	&dev_attr_durations.attr,
> +	&dev_attr_timeouts.attr, NULL,
> +};
> +
> +static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs };
> +
> +static const struct tpm_vendor_specific tpm_ibmvtpm = {
> +	.recv = tpm_ibmvtpm_recv,
> +	.send = tpm_ibmvtpm_send,
> +	.cancel = tpm_ibmvtpm_cancel,
> +	.status = tpm_ibmvtpm_status,
> +	.req_complete_mask = 0,
> +	.req_complete_val = 0,
> +	.req_canceled = 0,
> +	.attr_group = &ibmvtpm_attr_grp,
> +	.miscdev = { .fops = &ibmvtpm_ops, },
> +};
> +
> +static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = {
> +	.suspend = tpm_ibmvtpm_suspend,
> +	.resume = tpm_ibmvtpm_resume,
> +};
> +
> +/**
> + * ibmvtpm_crq_get_next - Get next responded crq
> + * @ibmvtpm	vtpm device struct
> + *
> + * Return value:
> + *	vtpm crq pointer
> + */
> +static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
> +{
> +	struct ibmvtpm_crq_queue *crq_q = &ibmvtpm->crq_queue;
> +	struct ibmvtpm_crq *crq = &crq_q->crq_addr[crq_q->index];
> +
> +	if (crq->valid & VTPM_MSG_RES) {
> +		if (++crq_q->index == crq_q->num_entry)
> +			crq_q->index = 0;
> +		rmb();
> +	} else
> +		crq = NULL;
> +	return crq;
> +}
> +
> +/**
> + * ibmvtpm_crq_process - Process responded crq
> + * @crq		crq to be processed
> + * @ibmvtpm	vtpm device struct
> + *
> + * Return value:
> + *	Nothing
> + */
> +static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
> +				struct ibmvtpm_dev *ibmvtpm)
> +{
> +	int rc = 0;
> +
> +	switch (crq->valid) {
> +	case VALID_INIT_CRQ:
> +		switch (crq->msg) {
> +		case INIT_CRQ_RES:
> +			dev_info(ibmvtpm->dev, "CRQ initialized\n");
> +			rc = ibmvtpm_crq_send_init_complete(ibmvtpm);
> +			if (rc)
> +				dev_err(ibmvtpm->dev, "Unable to send CRQ init complete rc=%d\n", rc);
> +			return;
> +		case INIT_CRQ_COMP_RES:
> +			dev_info(ibmvtpm->dev,
> +				 "CRQ initialization completed\n");
> +			return;
> +		default:
> +			dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg);
> +			return;
> +		}
> +		return;
> +	case IBMVTPM_VALID_CMD:
> +		switch (crq->msg) {
> +		case VTPM_GET_RTCE_BUFFER_SIZE_RES:
> +			if (crq->len <= 0) {
> +				dev_err(ibmvtpm->dev, "Invalid rtce size\n");
> +				return;
> +			}
> +			ibmvtpm->rtce_size = crq->len;
> +			ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
> +						    GFP_KERNEL);
> +			if (!ibmvtpm->rtce_buf) {
> +				dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n");
> +				return;
> +			}
> +
> +			ibmvtpm->rtce_dma_handle = dma_map_single(ibmvtpm->dev,
> +				ibmvtpm->rtce_buf, ibmvtpm->rtce_size,
> +				DMA_BIDIRECTIONAL);
> +
> +			if (dma_mapping_error(ibmvtpm->dev,
> +					      ibmvtpm->rtce_dma_handle)) {
> +				kfree(ibmvtpm->rtce_buf);
> +				ibmvtpm->rtce_buf = NULL;
> +				dev_err(ibmvtpm->dev, "Failed to dma map rtce buffer\n");
> +			}
> +
> +			return;
> +		case VTPM_GET_VERSION_RES:
> +			ibmvtpm->vtpm_version = crq->data;
> +			return;
> +		case VTPM_TPM_COMMAND_RES:
> +			ibmvtpm->crq_res.valid = crq->valid;
> +			ibmvtpm->crq_res.msg = crq->msg;
> +			ibmvtpm->crq_res.len = crq->len;
> +			ibmvtpm->crq_res.data = crq->data;
> +			wake_up_interruptible(&wq);
> +			return;
> +		default:
> +			return;
> +		}
> +	}
> +	return;
> +}
> +
> +/**
> + * ibmvtpm_interrupt -	Interrupt handler
> + * @irq:		irq number to handle
> + * @vtpm_instance:	vtpm that received interrupt
> + *
> + * Returns:
> + *	IRQ_HANDLED
> + **/
> +static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
> +{
> +	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&ibmvtpm->lock, flags);
> +	vio_disable_interrupts(ibmvtpm->vdev);
> +	tasklet_schedule(&ibmvtpm->tasklet);
> +	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/**
> + * ibmvtpm_tasklet - Interrupt handler tasklet
> + * @data:	ibm vtpm device struct
> + *
> + * Returns:
> + *	Nothing
> + **/
> +static void ibmvtpm_tasklet(void *data)
> +{
> +	struct ibmvtpm_dev *ibmvtpm = data;
> +	struct ibmvtpm_crq *crq;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&ibmvtpm->lock, flags);
> +	while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
> +		ibmvtpm_crq_process(crq, ibmvtpm);
> +		crq->valid = 0;
> +		wmb();
> +	}
> +
> +	vio_enable_interrupts(ibmvtpm->vdev);
> +	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> +}
> +
> +/**
> + * tpm_ibmvtpm_probe - ibm vtpm initialize entry point
> + * @vio_dev:	vio device struct
> + * @id:		vio device id struct
> + *
> + * Return value:
> + *	0 - Success
> + *	Non-zero - Failure
> + */
> +static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
> +				   const struct vio_device_id *id)
> +{
> +	struct ibmvtpm_dev *ibmvtpm;
> +	struct device *dev = &vio_dev->dev;
> +	struct ibmvtpm_crq_queue *crq_q;
> +	struct tpm_chip *chip;
> +	int rc = -ENOMEM, rc1;
> +
> +	chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
> +	if (!chip) {
> +		dev_err(dev, "tpm_register_hardware failed\n");
> +		return -ENODEV;
> +	}
> +
> +	ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
> +	if (!ibmvtpm) {
> +		dev_err(dev, "kzalloc for ibmvtpm failed\n");
> +		goto cleanup;
> +	}
> +
> +	crq_q = &ibmvtpm->crq_queue;
> +	crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL);
> +	if (!crq_q->crq_addr) {
> +		dev_err(dev, "Unable to allocate memory for crq_addr\n");
> +		goto cleanup;
> +	}
> +
> +	crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr);
> +	ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr,
> +						 CRQ_RES_BUF_SIZE,
> +						 DMA_BIDIRECTIONAL);
> +
> +	if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) {
> +		dev_err(dev, "dma mapping failed\n");
> +		goto cleanup;
> +	}
> +
> +	rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address,
> +				ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
> +	if (rc == H_RESOURCE)
> +		rc = ibmvtpm_reset_crq(ibmvtpm);
> +
> +	if (rc) {
> +		dev_err(dev, "Unable to register CRQ rc=%d\n", rc);
> +		goto reg_crq_cleanup;
> +	}
> +
> +	tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet,
> +		     (unsigned long)ibmvtpm);
> +
> +	rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0,
> +			 tpm_ibmvtpm_driver_name, ibmvtpm);
> +	if (rc) {
> +		dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq);
> +		goto init_irq_cleanup;
> +	}
> +
> +	rc = vio_enable_interrupts(vio_dev);
> +	if (rc) {
> +		dev_err(dev, "Error %d enabling interrupts\n", rc);
> +		goto init_irq_cleanup;
> +	}
> +
> +	crq_q->index = 0;
> +
> +	ibmvtpm->dev = dev;
> +	ibmvtpm->vdev = vio_dev;
> +	chip->vendor.data = (void *)ibmvtpm;
> +
> +	spin_lock_init(&ibmvtpm->lock);
> +	spin_lock_init(&ibmvtpm->rtce_lock);
> +
> +	rc = ibmvtpm_crq_send_init(ibmvtpm);
> +	if (rc)
> +		goto init_irq_cleanup;
> +
> +	rc = ibmvtpm_crq_get_version(ibmvtpm);
> +	if (rc)
> +		goto init_irq_cleanup;
> +
> +	rc = ibmvtpm_crq_get_rtce_size(ibmvtpm);
> +	if (rc)
> +		goto init_irq_cleanup;
> +
> +	return rc;
> +init_irq_cleanup:
> +	tasklet_kill(&ibmvtpm->tasklet);
> +	do {
> +		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
> +	} while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1));
> +reg_crq_cleanup:
> +	dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE,
> +			 DMA_BIDIRECTIONAL);
> +cleanup:
> +	if (ibmvtpm) {
> +		if (crq_q->crq_addr)
> +			free_page((unsigned long)crq_q->crq_addr);
> +		kfree(ibmvtpm);
> +	}
> +
> +	tpm_remove_hardware(dev);
> +
> +	return rc;
> +}
> +
> +static struct vio_driver ibmvtpm_driver = {
> +	.id_table	 = tpm_ibmvtpm_device_table,
> +	.probe		 = tpm_ibmvtpm_probe,
> +	.remove		 = tpm_ibmvtpm_remove,
> +	.get_desired_dma = tpm_ibmvtpm_get_desired_dma,
> +	.name		 = tpm_ibmvtpm_driver_name,
> +	.pm		 = &tpm_ibmvtpm_pm_ops,
> +};
> +
> +/**
> + * ibmvtpm_module_init - Initialize ibm vtpm module
> + *
> + * Return value:
> + *	0 -Success
> + *	Non-zero - Failure
> + */
> +static int __init ibmvtpm_module_init(void)
> +{
> +	return vio_register_driver(&ibmvtpm_driver);
> +}
> +
> +/**
> + * ibmvtpm_module_exit - Teardown ibm vtpm module
> + *
> + * Return value:
> + *	Nothing
> + */
> +static void __exit ibmvtpm_module_exit(void)
> +{
> +	vio_unregister_driver(&ibmvtpm_driver);
> +}
> +
> +module_init(ibmvtpm_module_init);
> +module_exit(ibmvtpm_module_exit);
> +
> +MODULE_AUTHOR("adlai@us.ibm.com");
> +MODULE_DESCRIPTION("IBM vTPM Driver");
> +MODULE_VERSION("1.0");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
> new file mode 100644
> index 0000000..4296eb4
> --- /dev/null
> +++ b/drivers/char/tpm/tpm_ibmvtpm.h
> @@ -0,0 +1,77 @@
> +/*
> + * Copyright (C) 2012 IBM Corporation
> + *
> + * Author: Ashley Lai <adlai@us.ibm.com>
> + *
> + * Maintained by: <tpmdd-devel@lists.sourceforge.net>
> + *
> + * Device driver for TCG/TCPA TPM (trusted platform module).
> + * Specifications at www.trustedcomputinggroup.org
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation, version 2 of the
> + * License.
> + *
> + */
> +
> +#ifndef __TPM_IBMVTPM_H__
> +#define __TPM_IBMVTPM_H__
> +
> +/* vTPM Message Format 1 */
> +struct ibmvtpm_crq {
> +	u8 valid;
> +	u8 msg;
> +	u16 len;
> +	u32 data;
> +	u64 reserved;
> +} __attribute__((packed, aligned(8)));
> +
> +struct ibmvtpm_crq_queue {
> +	struct ibmvtpm_crq *crq_addr;
> +	u32 index;
> +	u32 num_entry;
> +};
> +
> +struct ibmvtpm_dev {
> +	struct device *dev;
> +	struct vio_dev *vdev;
> +	struct ibmvtpm_crq_queue crq_queue;
> +	dma_addr_t crq_dma_handle;
> +	spinlock_t lock;
> +	struct tasklet_struct tasklet;
> +	u32 rtce_size;
> +	void __iomem *rtce_buf;
> +	dma_addr_t rtce_dma_handle;
> +	spinlock_t rtce_lock;
> +	struct ibmvtpm_crq crq_res;
> +	u32 vtpm_version;
> +};
> +
> +#define CRQ_RES_BUF_SIZE	PAGE_SIZE
> +
> +/* Initialize CRQ */
> +#define INIT_CRQ_CMD		0xC001000000000000LL /* Init cmd */
> +#define INIT_CRQ_COMP_CMD	0xC002000000000000LL /* Init complete cmd */
> +#define INIT_CRQ_RES		0x01	/* Init respond */
> +#define INIT_CRQ_COMP_RES	0x02	/* Init complete respond */
> +#define VALID_INIT_CRQ		0xC0	/* Valid command for init crq */
> +
> +/* vTPM CRQ response is the message type | 0x80 */
> +#define VTPM_MSG_RES		0x80
> +#define IBMVTPM_VALID_CMD	0x80
> +
> +/* vTPM CRQ message types */
> +#define VTPM_GET_VERSION			0x01
> +#define VTPM_GET_VERSION_RES			(0x01 | VTPM_MSG_RES)
> +
> +#define VTPM_TPM_COMMAND			0x02
> +#define VTPM_TPM_COMMAND_RES			(0x02 | VTPM_MSG_RES)
> +
> +#define VTPM_GET_RTCE_BUFFER_SIZE		0x03
> +#define VTPM_GET_RTCE_BUFFER_SIZE_RES		(0x03 | VTPM_MSG_RES)
> +
> +#define VTPM_PREPARE_TO_SUSPEND			0x04
> +#define VTPM_PREPARE_TO_SUSPEND_RES		(0x04 | VTPM_MSG_RES)
> +
> +#endif
> -- 
> 1.7.1
> 
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-08-22 21:42     ` Kent Yoder
@ 2012-09-05  3:40       ` Benjamin Herrenschmidt
  2012-09-05 15:46         ` Kent Yoder
  2012-09-05 17:25         ` Ashley Lai
  0 siblings, 2 replies; 19+ messages in thread
From: Benjamin Herrenschmidt @ 2012-09-05  3:40 UTC (permalink / raw)
  To: Kent Yoder
  Cc: Ashley Lai, linux-kernel, linux-security-module, tpmdd-devel,
	linuxppc-dev, rcj, adlai

On Wed, 2012-08-22 at 16:42 -0500, Kent Yoder wrote:
> On Wed, Aug 22, 2012 at 04:17:43PM -0500, Ashley Lai wrote:
> > This patch adds a new device driver to support IBM virtual TPM
> > (vTPM) for PPC64.  IBM vTPM is supported through the adjunct
> > partition with firmware release 740 or higher.  With vTPM
> > support, each lpar is able to have its own vTPM without the
> > physical TPM hardware.
> > 
> > This driver provides TPM functionalities by communicating with
> > the vTPM adjunct partition through Hypervisor calls (Hcalls)
> > and Command/Response Queue (CRQ) commands.
> 
>  Thanks Ashley, I'll include this in my next pull request to James.

Oh ? I was about to put it in the powerpc tree ... But yeah, I notice
there's a change to tpm.h so it probably should be at least acked by the
TPM folks. As for the subsequent patches, they are powerpc specific so I
can add them, I don't think there's a strict dependency, is there ?

Now, while having a look at the driver, I found a few things that I'm
not sure I'm happy with:

Mainly:

> > + */
> > +static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
> > +{
> > +	struct ibmvtpm_dev *ibmvtpm;
> > +	u16 len;
> > +
> > +	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
> > +
> > +	if (!ibmvtpm->rtce_buf) {
> > +		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
> > +		return 0;
> > +	}
> > +
> > +	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
> > +
> > +	if (count < ibmvtpm->crq_res.len) {

That doesn't look right. The "other side" as far as I can tell is:

> > +		case VTPM_TPM_COMMAND_RES:
> > +			ibmvtpm->crq_res.valid = crq->valid;
> > +			ibmvtpm->crq_res.msg = crq->msg;
> > +			ibmvtpm->crq_res.len = crq->len;
> > +			ibmvtpm->crq_res.data = crq->data;
> > +			wake_up_interruptible(&wq);

That looks racy to me. At the very least it should be doing:

			ibmvtpm->crq_res.data = crq->data;
			smp_wmb();
			ibmvtpm->crq_res.len = crq->len;

IE. Ensure that "len" is written last, and possibly have an
corresponding smp_rmb() after wait_event_interruptible() in the receive
case.

Also, I dislike having a global symbol called "wq". You also don't seem
to have any synchronization on access to that wq, can't you end up with
several clients trying to send messages & wait for responses getting all
mixed up ? You might need to make sure that at least you do a
wake_up_interruptible_all() to ensure you wake them all up (inefficient
but works). Unless you can track per-client ?

Or is the above TPM layer making sure only one command/response happens
at a given point in time ?

You also do an interruptible wait but don't seem to be checking for
signals (and not testing the result from wait_event_interruptible which
might be returning -ERESTARTSYS in this case).

That all sound a bit wrong to me ...
> > +static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
> > +{
> > +	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
> > +	unsigned long flags;
> > +
> > +	spin_lock_irqsave(&ibmvtpm->lock, flags);
> > +	vio_disable_interrupts(ibmvtpm->vdev);
> > +	tasklet_schedule(&ibmvtpm->tasklet);
> > +	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> > +
> > +	return IRQ_HANDLED;
> > +}

Tasklets ? We still use those things ? That's softirq iirc, do you
really need to offload ? I mean, it allows to limit the amount of time
an interrupt is disabled, but that's only useful if you assume you'll
have quite a lot of traffic here, is that the case ?

You might be actually increasing latency here in favor of throughput, is
that what you are aiming for ? Also keep in mind that
vio_disable/enable_interrupt() being an hcall, it can have significant
overhead. So again, only worth it if you're going to process a bulk of
data at a time.

Cheers,
Ben.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-09-05  3:40       ` Benjamin Herrenschmidt
@ 2012-09-05 15:46         ` Kent Yoder
  2012-09-05 21:11           ` Benjamin Herrenschmidt
  2012-09-05 17:25         ` Ashley Lai
  1 sibling, 1 reply; 19+ messages in thread
From: Kent Yoder @ 2012-09-05 15:46 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Ashley Lai, linux-kernel, linux-security-module, tpmdd-devel,
	linuxppc-dev, rcj, adlai

On Wed, Sep 05, 2012 at 01:40:07PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2012-08-22 at 16:42 -0500, Kent Yoder wrote:
> > On Wed, Aug 22, 2012 at 04:17:43PM -0500, Ashley Lai wrote:
> > > This patch adds a new device driver to support IBM virtual TPM
> > > (vTPM) for PPC64.  IBM vTPM is supported through the adjunct
> > > partition with firmware release 740 or higher.  With vTPM
> > > support, each lpar is able to have its own vTPM without the
> > > physical TPM hardware.
> > > 
> > > This driver provides TPM functionalities by communicating with
> > > the vTPM adjunct partition through Hypervisor calls (Hcalls)
> > > and Command/Response Queue (CRQ) commands.
> > 
> >  Thanks Ashley, I'll include this in my next pull request to James.
> 
> Oh ? I was about to put it in the powerpc tree ... But yeah, I notice
> there's a change to tpm.h so it probably should be at least acked by the
> TPM folks. As for the subsequent patches, they are powerpc specific so I
> can add them, I don't think there's a strict dependency, is there ?

  James did accept my pull request, so these are already in
security-next...

Kent


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-09-05  3:40       ` Benjamin Herrenschmidt
  2012-09-05 15:46         ` Kent Yoder
@ 2012-09-05 17:25         ` Ashley Lai
  1 sibling, 0 replies; 19+ messages in thread
From: Ashley Lai @ 2012-09-05 17:25 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Kent Yoder, linux-kernel, linux-security-module, tpmdd-devel,
	linuxppc-dev, rcj, adlai

Hi Ben.,

Thank you so much for the comments.  Please see my response below.

> > > + */
> > > +static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
> > > +{
> > > +	struct ibmvtpm_dev *ibmvtpm;
> > > +	u16 len;
> > > +
> > > +	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
> > > +
> > > +	if (!ibmvtpm->rtce_buf) {
> > > +		dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
> > > +		return 0;
> > > +	}
> > > +
> > > +	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
> > > +
> > > +	if (count < ibmvtpm->crq_res.len) {
> 
> That doesn't look right. The "other side" as far as I can tell is:
> 
> > > +		case VTPM_TPM_COMMAND_RES:
> > > +			ibmvtpm->crq_res.valid = crq->valid;
> > > +			ibmvtpm->crq_res.msg = crq->msg;
> > > +			ibmvtpm->crq_res.len = crq->len;
> > > +			ibmvtpm->crq_res.data = crq->data;
> > > +			wake_up_interruptible(&wq);
> 
> That looks racy to me. At the very least it should be doing:
> 
> 			ibmvtpm->crq_res.data = crq->data;
> 			smp_wmb();
> 			ibmvtpm->crq_res.len = crq->len;
> 
> IE. Ensure that "len" is written last, and possibly have an
> corresponding smp_rmb() after wait_event_interruptible() in the receive
> case.

Good catch. I agreed len should be written last and adding memory
barrier is a good idea.

> 
> Also, I dislike having a global symbol called "wq". You also don't seem
> to have any synchronization on access to that wq, can't you end up with
> several clients trying to send messages & wait for responses getting all
> mixed up ? You might need to make sure that at least you do a
> wake_up_interruptible_all() to ensure you wake them all up (inefficient
> but works). Unless you can track per-client ?

The TPM layer above allows only one request at any given point in time.
Therefore we don't need to wake_up_interruptible_all().  I can move wq
to the private structure.

> 
> Or is the above TPM layer making sure only one command/response happens
> at a given point in time ?

You are right.  See above.
> 
> You also do an interruptible wait but don't seem to be checking for
> signals (and not testing the result from wait_event_interruptible which
> might be returning -ERESTARTSYS in this case).
> 
Good point.  I will check for signal in the next version.

> That all sound a bit wrong to me ...
> > > +static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
> > > +{
> > > +	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
> > > +	unsigned long flags;
> > > +
> > > +	spin_lock_irqsave(&ibmvtpm->lock, flags);
> > > +	vio_disable_interrupts(ibmvtpm->vdev);
> > > +	tasklet_schedule(&ibmvtpm->tasklet);
> > > +	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> 
> Tasklets ? We still use those things ? That's softirq iirc, do you
> really need to offload ? I mean, it allows to limit the amount of time
> an interrupt is disabled, but that's only useful if you assume you'll
> have quite a lot of traffic here, is that the case ?
> 
> You might be actually increasing latency here in favor of throughput, is
> that what you are aiming for ? Also keep in mind that
> vio_disable/enable_interrupt() being an hcall, it can have significant
> overhead. So again, only worth it if you're going to process a bulk of
> data at a time.

My original thought was to have the bottom half process the crq data
while the top half can service another request.  There is some work in
processing crq data but not that bad. You are right the
vio_disable/enable_interrupt() can have significant overhead.  I will
remove tasklet in the next version.

> 
> Cheers,
> Ben.
> 
> 

Thanks,
--Ashley Lai



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-09-05 15:46         ` Kent Yoder
@ 2012-09-05 21:11           ` Benjamin Herrenschmidt
  2012-09-07 17:38             ` Kent Yoder
  0 siblings, 1 reply; 19+ messages in thread
From: Benjamin Herrenschmidt @ 2012-09-05 21:11 UTC (permalink / raw)
  To: Kent Yoder
  Cc: Ashley Lai, linux-kernel, linux-security-module, tpmdd-devel,
	linuxppc-dev, rcj, adlai

On Wed, 2012-09-05 at 10:46 -0500, Kent Yoder wrote:
> On Wed, Sep 05, 2012 at 01:40:07PM +1000, Benjamin Herrenschmidt wrote:
> > On Wed, 2012-08-22 at 16:42 -0500, Kent Yoder wrote:
> > > On Wed, Aug 22, 2012 at 04:17:43PM -0500, Ashley Lai wrote:
> > > > This patch adds a new device driver to support IBM virtual TPM
> > > > (vTPM) for PPC64.  IBM vTPM is supported through the adjunct
> > > > partition with firmware release 740 or higher.  With vTPM
> > > > support, each lpar is able to have its own vTPM without the
> > > > physical TPM hardware.
> > > > 
> > > > This driver provides TPM functionalities by communicating with
> > > > the vTPM adjunct partition through Hypervisor calls (Hcalls)
> > > > and Command/Response Queue (CRQ) commands.
> > > 
> > >  Thanks Ashley, I'll include this in my next pull request to James.
> > 
> > Oh ? I was about to put it in the powerpc tree ... But yeah, I notice
> > there's a change to tpm.h so it probably should be at least acked by the
> > TPM folks. As for the subsequent patches, they are powerpc specific so I
> > can add them, I don't think there's a strict dependency, is there ?
> 
>   James did accept my pull request, so these are already in
> security-next...

For the driver itself, it's not a big issue (though I did found issue
while reviewing it so it will need another round of updates). For the
code that changes arch/powerpc, especially prom_init.c, that stuff must
at the very least be acked by me (or the acting powerpc person if I'm
away) if it's going to go via a different tree.

Cheers,
Ben.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-09-05 21:11           ` Benjamin Herrenschmidt
@ 2012-09-07 17:38             ` Kent Yoder
  2012-09-12  3:16               ` James Morris
  0 siblings, 1 reply; 19+ messages in thread
From: Kent Yoder @ 2012-09-07 17:38 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Ashley Lai, linux-kernel, linux-security-module, tpmdd-devel,
	linuxppc-dev, rcj, adlai, James Morris

> >   James did accept my pull request, so these are already in
> > security-next...
> 
> For the driver itself, it's not a big issue (though I did found issue
> while reviewing it so it will need another round of updates). For the
> code that changes arch/powerpc, especially prom_init.c, that stuff must
> at the very least be acked by me (or the acting powerpc person if I'm
> away) if it's going to go via a different tree.

  Sorry about that.  Hopefully there won't be any changes there and we
can amend with your ack.

  As for the driver updates, I'd hate to see everyone else's code in the
pull request get delayed yet again.  James, will it be ok to apply the
update on top of security-next?

Thanks,
Kent

> Cheers,
> Ben.
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM
  2012-09-07 17:38             ` Kent Yoder
@ 2012-09-12  3:16               ` James Morris
  0 siblings, 0 replies; 19+ messages in thread
From: James Morris @ 2012-09-12  3:16 UTC (permalink / raw)
  To: Kent Yoder
  Cc: Benjamin Herrenschmidt, Ashley Lai, linux-kernel,
	linux-security-module, tpmdd-devel, linuxppc-dev, rcj, adlai

On Fri, 7 Sep 2012, Kent Yoder wrote:

> > >   James did accept my pull request, so these are already in
> > > security-next...
> > 
> > For the driver itself, it's not a big issue (though I did found issue
> > while reviewing it so it will need another round of updates). For the
> > code that changes arch/powerpc, especially prom_init.c, that stuff must
> > at the very least be acked by me (or the acting powerpc person if I'm
> > away) if it's going to go via a different tree.
> 
>   Sorry about that.  Hopefully there won't be any changes there and we
> can amend with your ack.
> 
>   As for the driver updates, I'd hate to see everyone else's code in the
> pull request get delayed yet again.  James, will it be ok to apply the
> update on top of security-next?

I guess?

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup
  2012-08-22 21:17   ` Ashley Lai
  2012-08-22 21:42     ` Kent Yoder
@ 2012-09-12 17:49     ` Ashley Lai
  2012-09-24  2:26       ` James Morris
  1 sibling, 1 reply; 19+ messages in thread
From: Ashley Lai @ 2012-09-12 17:49 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, tpmdd-devel, benh, linuxppc-dev, rcj, key,
	jmorris, adlai, adlai

This patch removed the tasklet and moved the wait queue into the
private structure.  It also cleaned up the response CRQ path.

Signed-off-by: Ashley Lai <adlai@us.ibm.com>
---
James,

This patch is based on your "next" branch.
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git

Thanks,
Ashley Lai
---
 drivers/char/tpm/tpm_ibmvtpm.c | 81 +++++++++++++++---------------------------
 drivers/char/tpm/tpm_ibmvtpm.h |  5 ++-
 2 files changed, 30 insertions(+), 56 deletions(-)

diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
index efc4ab3..88a95ea 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.c
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -38,8 +38,6 @@ static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = {
 };
 MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
 
-DECLARE_WAIT_QUEUE_HEAD(wq);
-
 /**
  * ibmvtpm_send_crq - Send a CRQ request
  * @vdev:	vio device struct
@@ -83,6 +81,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
 	struct ibmvtpm_dev *ibmvtpm;
 	u16 len;
+	int sig;
 
 	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
 
@@ -91,22 +90,23 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 		return 0;
 	}
 
-	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
+	sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0);
+	if (sig)
+		return -EINTR;
+
+	len = ibmvtpm->res_len;
 
-	if (count < ibmvtpm->crq_res.len) {
+	if (count < len) {
 		dev_err(ibmvtpm->dev,
 			"Invalid size in recv: count=%ld, crq_size=%d\n",
-			count, ibmvtpm->crq_res.len);
+			count, len);
 		return -EIO;
 	}
 
 	spin_lock(&ibmvtpm->rtce_lock);
-	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len);
-	memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len);
-	ibmvtpm->crq_res.valid = 0;
-	ibmvtpm->crq_res.msg = 0;
-	len = ibmvtpm->crq_res.len;
-	ibmvtpm->crq_res.len = 0;
+	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, len);
+	memset(ibmvtpm->rtce_buf, 0, len);
+	ibmvtpm->res_len = 0;
 	spin_unlock(&ibmvtpm->rtce_lock);
 	return len;
 }
@@ -273,7 +273,6 @@ static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev)
 	int rc = 0;
 
 	free_irq(vdev->irq, ibmvtpm);
-	tasklet_kill(&ibmvtpm->tasklet);
 
 	do {
 		if (rc)
@@ -372,7 +371,6 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
 static int tpm_ibmvtpm_resume(struct device *dev)
 {
 	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
-	unsigned long flags;
 	int rc = 0;
 
 	do {
@@ -387,10 +385,11 @@ static int tpm_ibmvtpm_resume(struct device *dev)
 		return rc;
 	}
 
-	spin_lock_irqsave(&ibmvtpm->lock, flags);
-	vio_disable_interrupts(ibmvtpm->vdev);
-	tasklet_schedule(&ibmvtpm->tasklet);
-	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+	rc = vio_enable_interrupts(ibmvtpm->vdev);
+	if (rc) {
+		dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
+		return rc;
+	}
 
 	rc = ibmvtpm_crq_send_init(ibmvtpm);
 	if (rc)
@@ -467,7 +466,7 @@ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
 	if (crq->valid & VTPM_MSG_RES) {
 		if (++crq_q->index == crq_q->num_entry)
 			crq_q->index = 0;
-		rmb();
+		smp_rmb();
 	} else
 		crq = NULL;
 	return crq;
@@ -535,11 +534,9 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
 			ibmvtpm->vtpm_version = crq->data;
 			return;
 		case VTPM_TPM_COMMAND_RES:
-			ibmvtpm->crq_res.valid = crq->valid;
-			ibmvtpm->crq_res.msg = crq->msg;
-			ibmvtpm->crq_res.len = crq->len;
-			ibmvtpm->crq_res.data = crq->data;
-			wake_up_interruptible(&wq);
+			/* len of the data in rtce buffer */
+			ibmvtpm->res_len = crq->len;
+			wake_up_interruptible(&ibmvtpm->wq);
 			return;
 		default:
 			return;
@@ -559,38 +556,19 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
 static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
 {
 	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
-	unsigned long flags;
-
-	spin_lock_irqsave(&ibmvtpm->lock, flags);
-	vio_disable_interrupts(ibmvtpm->vdev);
-	tasklet_schedule(&ibmvtpm->tasklet);
-	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
-
-	return IRQ_HANDLED;
-}
-
-/**
- * ibmvtpm_tasklet - Interrupt handler tasklet
- * @data:	ibm vtpm device struct
- *
- * Returns:
- *	Nothing
- **/
-static void ibmvtpm_tasklet(void *data)
-{
-	struct ibmvtpm_dev *ibmvtpm = data;
 	struct ibmvtpm_crq *crq;
-	unsigned long flags;
 
-	spin_lock_irqsave(&ibmvtpm->lock, flags);
+	/* while loop is needed for initial setup (get version and
+	 * get rtce_size). There should be only one tpm request at any
+	 * given time.
+	 */
 	while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
 		ibmvtpm_crq_process(crq, ibmvtpm);
 		crq->valid = 0;
-		wmb();
+		smp_wmb();
 	}
 
-	vio_enable_interrupts(ibmvtpm->vdev);
-	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
+	return IRQ_HANDLED;
 }
 
 /**
@@ -650,9 +628,6 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 		goto reg_crq_cleanup;
 	}
 
-	tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet,
-		     (unsigned long)ibmvtpm);
-
 	rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0,
 			 tpm_ibmvtpm_driver_name, ibmvtpm);
 	if (rc) {
@@ -666,13 +641,14 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 		goto init_irq_cleanup;
 	}
 
+	init_waitqueue_head(&ibmvtpm->wq);
+
 	crq_q->index = 0;
 
 	ibmvtpm->dev = dev;
 	ibmvtpm->vdev = vio_dev;
 	chip->vendor.data = (void *)ibmvtpm;
 
-	spin_lock_init(&ibmvtpm->lock);
 	spin_lock_init(&ibmvtpm->rtce_lock);
 
 	rc = ibmvtpm_crq_send_init(ibmvtpm);
@@ -689,7 +665,6 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
 
 	return rc;
 init_irq_cleanup:
-	tasklet_kill(&ibmvtpm->tasklet);
 	do {
 		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
 	} while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1));
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
index 4296eb4..bd82a79 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.h
+++ b/drivers/char/tpm/tpm_ibmvtpm.h
@@ -38,13 +38,12 @@ struct ibmvtpm_dev {
 	struct vio_dev *vdev;
 	struct ibmvtpm_crq_queue crq_queue;
 	dma_addr_t crq_dma_handle;
-	spinlock_t lock;
-	struct tasklet_struct tasklet;
 	u32 rtce_size;
 	void __iomem *rtce_buf;
 	dma_addr_t rtce_dma_handle;
 	spinlock_t rtce_lock;
-	struct ibmvtpm_crq crq_res;
+	wait_queue_head_t wq;
+	u16 res_len;
 	u32 vtpm_version;
 };
 
-- 
1.7.11.2



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup
  2012-09-12 17:49     ` [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup Ashley Lai
@ 2012-09-24  2:26       ` James Morris
  2012-09-24 14:10         ` key
  0 siblings, 1 reply; 19+ messages in thread
From: James Morris @ 2012-09-24  2:26 UTC (permalink / raw)
  To: Ashley Lai
  Cc: linux-kernel, linux-security-module, tpmdd-devel, benh,
	linuxppc-dev, rcj, key, adlai

On Wed, 12 Sep 2012, Ashley Lai wrote:

> This patch removed the tasklet and moved the wait queue into the
> private structure.  It also cleaned up the response CRQ path.
> 
> Signed-off-by: Ashley Lai <adlai@us.ibm.com>


Kent: any comment on this?  You should probably push this to me via your 
tree.


> ---
> James,
> 
> This patch is based on your "next" branch.
> git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
> 
> Thanks,
> Ashley Lai
> ---
>  drivers/char/tpm/tpm_ibmvtpm.c | 81 +++++++++++++++---------------------------
>  drivers/char/tpm/tpm_ibmvtpm.h |  5 ++-
>  2 files changed, 30 insertions(+), 56 deletions(-)
> 
> diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
> index efc4ab3..88a95ea 100644
> --- a/drivers/char/tpm/tpm_ibmvtpm.c
> +++ b/drivers/char/tpm/tpm_ibmvtpm.c
> @@ -38,8 +38,6 @@ static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = {
>  };
>  MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
>  
> -DECLARE_WAIT_QUEUE_HEAD(wq);
> -
>  /**
>   * ibmvtpm_send_crq - Send a CRQ request
>   * @vdev:	vio device struct
> @@ -83,6 +81,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
>  {
>  	struct ibmvtpm_dev *ibmvtpm;
>  	u16 len;
> +	int sig;
>  
>  	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
>  
> @@ -91,22 +90,23 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
>  		return 0;
>  	}
>  
> -	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
> +	sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0);
> +	if (sig)
> +		return -EINTR;
> +
> +	len = ibmvtpm->res_len;
>  
> -	if (count < ibmvtpm->crq_res.len) {
> +	if (count < len) {
>  		dev_err(ibmvtpm->dev,
>  			"Invalid size in recv: count=%ld, crq_size=%d\n",
> -			count, ibmvtpm->crq_res.len);
> +			count, len);
>  		return -EIO;
>  	}
>  
>  	spin_lock(&ibmvtpm->rtce_lock);
> -	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len);
> -	memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len);
> -	ibmvtpm->crq_res.valid = 0;
> -	ibmvtpm->crq_res.msg = 0;
> -	len = ibmvtpm->crq_res.len;
> -	ibmvtpm->crq_res.len = 0;
> +	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, len);
> +	memset(ibmvtpm->rtce_buf, 0, len);
> +	ibmvtpm->res_len = 0;
>  	spin_unlock(&ibmvtpm->rtce_lock);
>  	return len;
>  }
> @@ -273,7 +273,6 @@ static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev)
>  	int rc = 0;
>  
>  	free_irq(vdev->irq, ibmvtpm);
> -	tasklet_kill(&ibmvtpm->tasklet);
>  
>  	do {
>  		if (rc)
> @@ -372,7 +371,6 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
>  static int tpm_ibmvtpm_resume(struct device *dev)
>  {
>  	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
> -	unsigned long flags;
>  	int rc = 0;
>  
>  	do {
> @@ -387,10 +385,11 @@ static int tpm_ibmvtpm_resume(struct device *dev)
>  		return rc;
>  	}
>  
> -	spin_lock_irqsave(&ibmvtpm->lock, flags);
> -	vio_disable_interrupts(ibmvtpm->vdev);
> -	tasklet_schedule(&ibmvtpm->tasklet);
> -	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> +	rc = vio_enable_interrupts(ibmvtpm->vdev);
> +	if (rc) {
> +		dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
> +		return rc;
> +	}
>  
>  	rc = ibmvtpm_crq_send_init(ibmvtpm);
>  	if (rc)
> @@ -467,7 +466,7 @@ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
>  	if (crq->valid & VTPM_MSG_RES) {
>  		if (++crq_q->index == crq_q->num_entry)
>  			crq_q->index = 0;
> -		rmb();
> +		smp_rmb();
>  	} else
>  		crq = NULL;
>  	return crq;
> @@ -535,11 +534,9 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
>  			ibmvtpm->vtpm_version = crq->data;
>  			return;
>  		case VTPM_TPM_COMMAND_RES:
> -			ibmvtpm->crq_res.valid = crq->valid;
> -			ibmvtpm->crq_res.msg = crq->msg;
> -			ibmvtpm->crq_res.len = crq->len;
> -			ibmvtpm->crq_res.data = crq->data;
> -			wake_up_interruptible(&wq);
> +			/* len of the data in rtce buffer */
> +			ibmvtpm->res_len = crq->len;
> +			wake_up_interruptible(&ibmvtpm->wq);
>  			return;
>  		default:
>  			return;
> @@ -559,38 +556,19 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
>  static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
>  {
>  	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&ibmvtpm->lock, flags);
> -	vio_disable_interrupts(ibmvtpm->vdev);
> -	tasklet_schedule(&ibmvtpm->tasklet);
> -	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> -
> -	return IRQ_HANDLED;
> -}
> -
> -/**
> - * ibmvtpm_tasklet - Interrupt handler tasklet
> - * @data:	ibm vtpm device struct
> - *
> - * Returns:
> - *	Nothing
> - **/
> -static void ibmvtpm_tasklet(void *data)
> -{
> -	struct ibmvtpm_dev *ibmvtpm = data;
>  	struct ibmvtpm_crq *crq;
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&ibmvtpm->lock, flags);
> +	/* while loop is needed for initial setup (get version and
> +	 * get rtce_size). There should be only one tpm request at any
> +	 * given time.
> +	 */
>  	while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
>  		ibmvtpm_crq_process(crq, ibmvtpm);
>  		crq->valid = 0;
> -		wmb();
> +		smp_wmb();
>  	}
>  
> -	vio_enable_interrupts(ibmvtpm->vdev);
> -	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> +	return IRQ_HANDLED;
>  }
>  
>  /**
> @@ -650,9 +628,6 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
>  		goto reg_crq_cleanup;
>  	}
>  
> -	tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet,
> -		     (unsigned long)ibmvtpm);
> -
>  	rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0,
>  			 tpm_ibmvtpm_driver_name, ibmvtpm);
>  	if (rc) {
> @@ -666,13 +641,14 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
>  		goto init_irq_cleanup;
>  	}
>  
> +	init_waitqueue_head(&ibmvtpm->wq);
> +
>  	crq_q->index = 0;
>  
>  	ibmvtpm->dev = dev;
>  	ibmvtpm->vdev = vio_dev;
>  	chip->vendor.data = (void *)ibmvtpm;
>  
> -	spin_lock_init(&ibmvtpm->lock);
>  	spin_lock_init(&ibmvtpm->rtce_lock);
>  
>  	rc = ibmvtpm_crq_send_init(ibmvtpm);
> @@ -689,7 +665,6 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
>  
>  	return rc;
>  init_irq_cleanup:
> -	tasklet_kill(&ibmvtpm->tasklet);
>  	do {
>  		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
>  	} while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1));
> diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
> index 4296eb4..bd82a79 100644
> --- a/drivers/char/tpm/tpm_ibmvtpm.h
> +++ b/drivers/char/tpm/tpm_ibmvtpm.h
> @@ -38,13 +38,12 @@ struct ibmvtpm_dev {
>  	struct vio_dev *vdev;
>  	struct ibmvtpm_crq_queue crq_queue;
>  	dma_addr_t crq_dma_handle;
> -	spinlock_t lock;
> -	struct tasklet_struct tasklet;
>  	u32 rtce_size;
>  	void __iomem *rtce_buf;
>  	dma_addr_t rtce_dma_handle;
>  	spinlock_t rtce_lock;
> -	struct ibmvtpm_crq crq_res;
> +	wait_queue_head_t wq;
> +	u16 res_len;
>  	u32 vtpm_version;
>  };
>  
> -- 
> 1.7.11.2
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

-- 
James Morris
<jmorris@namei.org>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup
  2012-09-24  2:26       ` James Morris
@ 2012-09-24 14:10         ` key
  2012-09-24 15:48           ` key
  0 siblings, 1 reply; 19+ messages in thread
From: key @ 2012-09-24 14:10 UTC (permalink / raw)
  To: James Morris
  Cc: Ashley Lai, linux-kernel, linux-security-module, tpmdd-devel,
	benh, linuxppc-dev, rcj, key, adlai

On Mon, Sep 24, 2012 at 12:26:05PM +1000, James Morris wrote:
> On Wed, 12 Sep 2012, Ashley Lai wrote:
> 
> > This patch removed the tasklet and moved the wait queue into the
> > private structure.  It also cleaned up the response CRQ path.
> > 
> > Signed-off-by: Ashley Lai <adlai@us.ibm.com>
> 
> 
> Kent: any comment on this?  You should probably push this to me via your 
> tree.

  Oh, I thought we were waiting on Ben. This looks good to me, I'll get
this to you today.

  Kent

> 
> 
> > ---
> > James,
> > 
> > This patch is based on your "next" branch.
> > git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security.git
> > 
> > Thanks,
> > Ashley Lai
> > ---
> >  drivers/char/tpm/tpm_ibmvtpm.c | 81 +++++++++++++++---------------------------
> >  drivers/char/tpm/tpm_ibmvtpm.h |  5 ++-
> >  2 files changed, 30 insertions(+), 56 deletions(-)
> > 
> > diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
> > index efc4ab3..88a95ea 100644
> > --- a/drivers/char/tpm/tpm_ibmvtpm.c
> > +++ b/drivers/char/tpm/tpm_ibmvtpm.c
> > @@ -38,8 +38,6 @@ static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = {
> >  };
> >  MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
> >  
> > -DECLARE_WAIT_QUEUE_HEAD(wq);
> > -
> >  /**
> >   * ibmvtpm_send_crq - Send a CRQ request
> >   * @vdev:	vio device struct
> > @@ -83,6 +81,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
> >  {
> >  	struct ibmvtpm_dev *ibmvtpm;
> >  	u16 len;
> > +	int sig;
> >  
> >  	ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
> >  
> > @@ -91,22 +90,23 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
> >  		return 0;
> >  	}
> >  
> > -	wait_event_interruptible(wq, ibmvtpm->crq_res.len != 0);
> > +	sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0);
> > +	if (sig)
> > +		return -EINTR;
> > +
> > +	len = ibmvtpm->res_len;
> >  
> > -	if (count < ibmvtpm->crq_res.len) {
> > +	if (count < len) {
> >  		dev_err(ibmvtpm->dev,
> >  			"Invalid size in recv: count=%ld, crq_size=%d\n",
> > -			count, ibmvtpm->crq_res.len);
> > +			count, len);
> >  		return -EIO;
> >  	}
> >  
> >  	spin_lock(&ibmvtpm->rtce_lock);
> > -	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, ibmvtpm->crq_res.len);
> > -	memset(ibmvtpm->rtce_buf, 0, ibmvtpm->crq_res.len);
> > -	ibmvtpm->crq_res.valid = 0;
> > -	ibmvtpm->crq_res.msg = 0;
> > -	len = ibmvtpm->crq_res.len;
> > -	ibmvtpm->crq_res.len = 0;
> > +	memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, len);
> > +	memset(ibmvtpm->rtce_buf, 0, len);
> > +	ibmvtpm->res_len = 0;
> >  	spin_unlock(&ibmvtpm->rtce_lock);
> >  	return len;
> >  }
> > @@ -273,7 +273,6 @@ static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev)
> >  	int rc = 0;
> >  
> >  	free_irq(vdev->irq, ibmvtpm);
> > -	tasklet_kill(&ibmvtpm->tasklet);
> >  
> >  	do {
> >  		if (rc)
> > @@ -372,7 +371,6 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
> >  static int tpm_ibmvtpm_resume(struct device *dev)
> >  {
> >  	struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev);
> > -	unsigned long flags;
> >  	int rc = 0;
> >  
> >  	do {
> > @@ -387,10 +385,11 @@ static int tpm_ibmvtpm_resume(struct device *dev)
> >  		return rc;
> >  	}
> >  
> > -	spin_lock_irqsave(&ibmvtpm->lock, flags);
> > -	vio_disable_interrupts(ibmvtpm->vdev);
> > -	tasklet_schedule(&ibmvtpm->tasklet);
> > -	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> > +	rc = vio_enable_interrupts(ibmvtpm->vdev);
> > +	if (rc) {
> > +		dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
> > +		return rc;
> > +	}
> >  
> >  	rc = ibmvtpm_crq_send_init(ibmvtpm);
> >  	if (rc)
> > @@ -467,7 +466,7 @@ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm)
> >  	if (crq->valid & VTPM_MSG_RES) {
> >  		if (++crq_q->index == crq_q->num_entry)
> >  			crq_q->index = 0;
> > -		rmb();
> > +		smp_rmb();
> >  	} else
> >  		crq = NULL;
> >  	return crq;
> > @@ -535,11 +534,9 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
> >  			ibmvtpm->vtpm_version = crq->data;
> >  			return;
> >  		case VTPM_TPM_COMMAND_RES:
> > -			ibmvtpm->crq_res.valid = crq->valid;
> > -			ibmvtpm->crq_res.msg = crq->msg;
> > -			ibmvtpm->crq_res.len = crq->len;
> > -			ibmvtpm->crq_res.data = crq->data;
> > -			wake_up_interruptible(&wq);
> > +			/* len of the data in rtce buffer */
> > +			ibmvtpm->res_len = crq->len;
> > +			wake_up_interruptible(&ibmvtpm->wq);
> >  			return;
> >  		default:
> >  			return;
> > @@ -559,38 +556,19 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
> >  static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
> >  {
> >  	struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance;
> > -	unsigned long flags;
> > -
> > -	spin_lock_irqsave(&ibmvtpm->lock, flags);
> > -	vio_disable_interrupts(ibmvtpm->vdev);
> > -	tasklet_schedule(&ibmvtpm->tasklet);
> > -	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> > -
> > -	return IRQ_HANDLED;
> > -}
> > -
> > -/**
> > - * ibmvtpm_tasklet - Interrupt handler tasklet
> > - * @data:	ibm vtpm device struct
> > - *
> > - * Returns:
> > - *	Nothing
> > - **/
> > -static void ibmvtpm_tasklet(void *data)
> > -{
> > -	struct ibmvtpm_dev *ibmvtpm = data;
> >  	struct ibmvtpm_crq *crq;
> > -	unsigned long flags;
> >  
> > -	spin_lock_irqsave(&ibmvtpm->lock, flags);
> > +	/* while loop is needed for initial setup (get version and
> > +	 * get rtce_size). There should be only one tpm request at any
> > +	 * given time.
> > +	 */
> >  	while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
> >  		ibmvtpm_crq_process(crq, ibmvtpm);
> >  		crq->valid = 0;
> > -		wmb();
> > +		smp_wmb();
> >  	}
> >  
> > -	vio_enable_interrupts(ibmvtpm->vdev);
> > -	spin_unlock_irqrestore(&ibmvtpm->lock, flags);
> > +	return IRQ_HANDLED;
> >  }
> >  
> >  /**
> > @@ -650,9 +628,6 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
> >  		goto reg_crq_cleanup;
> >  	}
> >  
> > -	tasklet_init(&ibmvtpm->tasklet, (void *)ibmvtpm_tasklet,
> > -		     (unsigned long)ibmvtpm);
> > -
> >  	rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0,
> >  			 tpm_ibmvtpm_driver_name, ibmvtpm);
> >  	if (rc) {
> > @@ -666,13 +641,14 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
> >  		goto init_irq_cleanup;
> >  	}
> >  
> > +	init_waitqueue_head(&ibmvtpm->wq);
> > +
> >  	crq_q->index = 0;
> >  
> >  	ibmvtpm->dev = dev;
> >  	ibmvtpm->vdev = vio_dev;
> >  	chip->vendor.data = (void *)ibmvtpm;
> >  
> > -	spin_lock_init(&ibmvtpm->lock);
> >  	spin_lock_init(&ibmvtpm->rtce_lock);
> >  
> >  	rc = ibmvtpm_crq_send_init(ibmvtpm);
> > @@ -689,7 +665,6 @@ static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
> >  
> >  	return rc;
> >  init_irq_cleanup:
> > -	tasklet_kill(&ibmvtpm->tasklet);
> >  	do {
> >  		rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
> >  	} while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1));
> > diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
> > index 4296eb4..bd82a79 100644
> > --- a/drivers/char/tpm/tpm_ibmvtpm.h
> > +++ b/drivers/char/tpm/tpm_ibmvtpm.h
> > @@ -38,13 +38,12 @@ struct ibmvtpm_dev {
> >  	struct vio_dev *vdev;
> >  	struct ibmvtpm_crq_queue crq_queue;
> >  	dma_addr_t crq_dma_handle;
> > -	spinlock_t lock;
> > -	struct tasklet_struct tasklet;
> >  	u32 rtce_size;
> >  	void __iomem *rtce_buf;
> >  	dma_addr_t rtce_dma_handle;
> >  	spinlock_t rtce_lock;
> > -	struct ibmvtpm_crq crq_res;
> > +	wait_queue_head_t wq;
> > +	u16 res_len;
> >  	u32 vtpm_version;
> >  };
> >  
> > -- 
> > 1.7.11.2
> > 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> > 
> 
> -- 
> James Morris
> <jmorris@namei.org>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup
  2012-09-24 14:10         ` key
@ 2012-09-24 15:48           ` key
  2012-09-26 13:55             ` key
  0 siblings, 1 reply; 19+ messages in thread
From: key @ 2012-09-24 15:48 UTC (permalink / raw)
  To: key
  Cc: James Morris, Ashley Lai, linux-kernel, linux-security-module,
	tpmdd-devel, benh, linuxppc-dev, rcj, adlai

On Mon, Sep 24, 2012 at 09:10:41AM -0500, key@linux.vnet.ibm.com wrote:
> On Mon, Sep 24, 2012 at 12:26:05PM +1000, James Morris wrote:
> > On Wed, 12 Sep 2012, Ashley Lai wrote:
> > 
> > > This patch removed the tasklet and moved the wait queue into the
> > > private structure.  It also cleaned up the response CRQ path.
> > > 
> > > Signed-off-by: Ashley Lai <adlai@us.ibm.com>
> > 
> > 
> > Kent: any comment on this?  You should probably push this to me via your 
> > tree.
> 
>   Oh, I thought we were waiting on Ben. This looks good to me, I'll get
> this to you today.

  Ashley tells me Ben's review is in the works, so I'll send once we
have it.

Kent

> 
>   Kent
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup
  2012-09-24 15:48           ` key
@ 2012-09-26 13:55             ` key
  2012-09-27 14:46               ` Ashley Lai
  0 siblings, 1 reply; 19+ messages in thread
From: key @ 2012-09-26 13:55 UTC (permalink / raw)
  To: benh
  Cc: James Morris, Ashley Lai, linux-kernel, linux-security-module,
	tpmdd-devel, linuxppc-dev, rcj, adlai, key

On Mon, Sep 24, 2012 at 10:48:21AM -0500, key@linux.vnet.ibm.com wrote:
> On Mon, Sep 24, 2012 at 09:10:41AM -0500, key@linux.vnet.ibm.com wrote:
> > On Mon, Sep 24, 2012 at 12:26:05PM +1000, James Morris wrote:
> > > On Wed, 12 Sep 2012, Ashley Lai wrote:
> > > 
> > > > This patch removed the tasklet and moved the wait queue into the
> > > > private structure.  It also cleaned up the response CRQ path.
> > > > 
> > > > Signed-off-by: Ashley Lai <adlai@us.ibm.com>
> > > 
> > > 
> > > Kent: any comment on this?  You should probably push this to me via your 
> > > tree.
> > 
> >   Oh, I thought we were waiting on Ben. This looks good to me, I'll get
> > this to you today.
> 
>   Ashley tells me Ben's review is in the works, so I'll send once we
> have it.

  Ben - any status here?

Kent

> 
> Kent
> 
> > 
> >   Kent
> > 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup
  2012-09-26 13:55             ` key
@ 2012-09-27 14:46               ` Ashley Lai
  0 siblings, 0 replies; 19+ messages in thread
From: Ashley Lai @ 2012-09-27 14:46 UTC (permalink / raw)
  To: key
  Cc: benh, James Morris, linux-kernel, linux-security-module,
	tpmdd-devel, linuxppc-dev, rcj, adlai

On Wed, 2012-09-26 at 08:55 -0500, key@linux.vnet.ibm.com wrote:
> On Mon, Sep 24, 2012 at 10:48:21AM -0500, key@linux.vnet.ibm.com wrote:
> > On Mon, Sep 24, 2012 at 09:10:41AM -0500, key@linux.vnet.ibm.com wrote:
> > > On Mon, Sep 24, 2012 at 12:26:05PM +1000, James Morris wrote:
> > > > On Wed, 12 Sep 2012, Ashley Lai wrote:
> > > > 
> > > > > This patch removed the tasklet and moved the wait queue into the
> > > > > private structure.  It also cleaned up the response CRQ path.
> > > > > 
> > > > > Signed-off-by: Ashley Lai <adlai@us.ibm.com>
> > > > 
> > > > 
> > > > Kent: any comment on this?  You should probably push this to me via your 
> > > > tree.
> > > 
> > >   Oh, I thought we were waiting on Ben. This looks good to me, I'll get
> > > this to you today.
> > 
> >   Ashley tells me Ben's review is in the works, so I'll send once we
> > have it.
> 
>   Ben - any status here?
> 
> Kent

Hi Ben,

Would you review the patch before the weekend?  If you are busy and not
able to review the patch this week, we will pull the patch into James's
tree next week.  I can resolve any additional comments you may have in a
different patch.

Thanks,
--Ashley Lai

> 
> > 
> > Kent
> > 
> > > 
> > >   Kent
> > > 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> > 



^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2012-09-27 14:44 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-14 23:23 [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Ashley Lai
2012-08-14 23:34 ` [PATCH V3 1/3] drivers/char/tpm: Add new device driver to support IBM vTPM Ashley Lai
2012-08-22 21:17   ` Ashley Lai
2012-08-22 21:42     ` Kent Yoder
2012-09-05  3:40       ` Benjamin Herrenschmidt
2012-09-05 15:46         ` Kent Yoder
2012-09-05 21:11           ` Benjamin Herrenschmidt
2012-09-07 17:38             ` Kent Yoder
2012-09-12  3:16               ` James Morris
2012-09-05 17:25         ` Ashley Lai
2012-09-12 17:49     ` [PATCH 1/1] drivers/char/tpm: remove tasklet and cleanup Ashley Lai
2012-09-24  2:26       ` James Morris
2012-09-24 14:10         ` key
2012-09-24 15:48           ` key
2012-09-26 13:55             ` key
2012-09-27 14:46               ` Ashley Lai
2012-08-14 23:34 ` [PATCH V3 2/3] PPC64: Add support for instantiating SML from Open Firmware Ashley Lai
2012-08-14 23:35 ` [PATCH V3 3/3] drivers/char/tpm: Add securityfs support for event log Ashley Lai
2012-08-15 19:59 ` [PATCH V3 0/3] tpm: Add new vTPM device driver for PPC64 Kent Yoder

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).