提交 8cc748aa 编写于 作者: L Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security layer updates from James Morris:
 "Highlights:

   - Smack adds secmark support for Netfilter
   - /proc/keys is now mandatory if CONFIG_KEYS=y
   - TPM gets its own device class
   - Added TPM 2.0 support
   - Smack file hook rework (all Smack users should review this!)"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (64 commits)
  cipso: don't use IPCB() to locate the CIPSO IP option
  SELinux: fix error code in policydb_init()
  selinux: add security in-core xattr support for pstore and debugfs
  selinux: quiet the filesystem labeling behavior message
  selinux: Remove unused function avc_sidcmp()
  ima: /proc/keys is now mandatory
  Smack: Repair netfilter dependency
  X.509: silence asn1 compiler debug output
  X.509: shut up about included cert for silent build
  KEYS: Make /proc/keys unconditional if CONFIG_KEYS=y
  MAINTAINERS: email update
  tpm/tpm_tis: Add missing ifdef CONFIG_ACPI for pnp_acpi_device
  smack: fix possible use after frees in task_security() callers
  smack: Add missing logging in bidirectional UDS connect check
  Smack: secmark support for netfilter
  Smack: Rework file hooks
  tpm: fix format string error in tpm-chip.c
  char/tpm/tpm_crb: fix build error
  smack: Fix a bidirectional UDS connect check typo
  smack: introduce a special case for tmpfs in smack_d_instantiate()
  ...
What: /sys/class/misc/tpmX/device/
What: /sys/class/tpm/tpmX/device/
Date: April 2005
KernelVersion: 2.6.12
Contact: tpmdd-devel@lists.sf.net
......@@ -6,7 +6,7 @@ Description: The device/ directory under a specific TPM instance exposes
the properties of that TPM chip
What: /sys/class/misc/tpmX/device/active
What: /sys/class/tpm/tpmX/device/active
Date: April 2006
KernelVersion: 2.6.17
Contact: tpmdd-devel@lists.sf.net
......@@ -18,7 +18,7 @@ Description: The "active" property prints a '1' if the TPM chip is accepting
section 17 for more information on which commands are
available.
What: /sys/class/misc/tpmX/device/cancel
What: /sys/class/tpm/tpmX/device/cancel
Date: June 2005
KernelVersion: 2.6.13
Contact: tpmdd-devel@lists.sf.net
......@@ -26,7 +26,7 @@ Description: The "cancel" property allows you to cancel the currently
pending TPM command. Writing any value to cancel will call the
TPM vendor specific cancel operation.
What: /sys/class/misc/tpmX/device/caps
What: /sys/class/tpm/tpmX/device/caps
Date: April 2005
KernelVersion: 2.6.12
Contact: tpmdd-devel@lists.sf.net
......@@ -43,7 +43,7 @@ Description: The "caps" property contains TPM manufacturer and version info.
the chip supports. Firmware version is that of the chip and
is manufacturer specific.
What: /sys/class/misc/tpmX/device/durations
What: /sys/class/tpm/tpmX/device/durations
Date: March 2011
KernelVersion: 3.1
Contact: tpmdd-devel@lists.sf.net
......@@ -66,7 +66,7 @@ Description: The "durations" property shows the 3 vendor-specific values
scaled to be displayed in usecs. In this case "[adjusted]"
will be displayed in place of "[original]".
What: /sys/class/misc/tpmX/device/enabled
What: /sys/class/tpm/tpmX/device/enabled
Date: April 2006
KernelVersion: 2.6.17
Contact: tpmdd-devel@lists.sf.net
......@@ -75,7 +75,7 @@ Description: The "enabled" property prints a '1' if the TPM chip is enabled,
may be visible but produce a '0' after some operation that
disables the TPM.
What: /sys/class/misc/tpmX/device/owned
What: /sys/class/tpm/tpmX/device/owned
Date: April 2006
KernelVersion: 2.6.17
Contact: tpmdd-devel@lists.sf.net
......@@ -83,7 +83,7 @@ Description: The "owned" property produces a '1' if the TPM_TakeOwnership
ordinal has been executed successfully in the chip. A '0'
indicates that ownership hasn't been taken.
What: /sys/class/misc/tpmX/device/pcrs
What: /sys/class/tpm/tpmX/device/pcrs
Date: April 2005
KernelVersion: 2.6.12
Contact: tpmdd-devel@lists.sf.net
......@@ -106,7 +106,7 @@ Description: The "pcrs" property will dump the current value of all Platform
1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes
long. Use the "caps" property to determine TPM version.
What: /sys/class/misc/tpmX/device/pubek
What: /sys/class/tpm/tpmX/device/pubek
Date: April 2005
KernelVersion: 2.6.12
Contact: tpmdd-devel@lists.sf.net
......@@ -158,7 +158,7 @@ Description: The "pubek" property will return the TPM's public endorsement
Modulus Length: 256 (bytes)
Modulus: The 256 byte Endorsement Key modulus
What: /sys/class/misc/tpmX/device/temp_deactivated
What: /sys/class/tpm/tpmX/device/temp_deactivated
Date: April 2006
KernelVersion: 2.6.17
Contact: tpmdd-devel@lists.sf.net
......@@ -167,7 +167,7 @@ Description: The "temp_deactivated" property returns a '1' if the chip has
cycle. Whether a warm boot (reboot) will clear a TPM chip
from a temp_deactivated state is platform specific.
What: /sys/class/misc/tpmX/device/timeouts
What: /sys/class/tpm/tpmX/device/timeouts
Date: March 2011
KernelVersion: 3.1
Contact: tpmdd-devel@lists.sf.net
......
* STMicroelectronics SAS. ST33ZP24 TPM SoC
Required properties:
- compatible: Should be "st,st33zp24-i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
Optional ST33ZP24 Properties:
- interrupt-parent: phandle for the interrupt gpio controller
- interrupts: GPIO interrupt to which the chip is connected
- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state.
If set, power must be present when the platform is going into sleep/hibernate mode.
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2):
&i2c2 {
status = "okay";
st33zp24: st33zp24@13 {
compatible = "st,st33zp24-i2c";
reg = <0x13>;
clock-frequency = <400000>;
interrupt-parent = <&gpio5>;
interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>;
};
};
......@@ -323,8 +323,6 @@ about the status of the key service:
U Under construction by callback to userspace
N Negative key
This file must be enabled at kernel configuration time as it allows anyone
to list the keys database.
(*) /proc/key-users
......
......@@ -4917,7 +4917,7 @@ F: drivers/ipack/
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <zohar@linux.vnet.ibm.com>
M: Dmitry Kasatkin <d.kasatkin@samsung.com>
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
L: linux-ima-devel@lists.sourceforge.net
L: linux-ima-user@lists.sourceforge.net
L: linux-security-module@vger.kernel.org
......@@ -9817,13 +9817,21 @@ F: drivers/media/pci/tw68/
TPM DEVICE DRIVER
M: Peter Huewe <peterhuewe@gmx.de>
M: Ashley Lai <ashley@ashleylai.com>
M: Marcel Selhorst <tpmdd@selhorst.net>
W: http://tpmdd.sourceforge.net
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
Q: git git://github.com/PeterHuewe/linux-tpmdd.git
T: https://github.com/PeterHuewe/linux-tpmdd
S: Maintained
F: drivers/char/tpm/
TPM IBM_VTPM DEVICE DRIVER
M: Ashley Lai <ashleydlai@gmail.com>
W: http://tpmdd.sourceforge.net
L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
F: drivers/char/tpm/tpm_ibmvtpm*
TRACING
M: Steven Rostedt <rostedt@goodmis.org>
M: Ingo Molnar <mingo@redhat.com>
......
......@@ -100,15 +100,15 @@ config TCG_IBMVTPM
will be accessible from within Linux. To compile this driver
as a module, choose M here; the module will be called tpm_ibmvtpm.
config TCG_ST33_I2C
tristate "STMicroelectronics ST33 I2C TPM"
config TCG_TIS_I2C_ST33
tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)"
depends on I2C
depends on GPIOLIB
---help---
If you have a TPM security chip from STMicroelectronics working with
an I2C bus 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_stm_st33_i2c.
called tpm_i2c_stm_st33.
config TCG_XEN
tristate "XEN TPM Interface"
......@@ -122,4 +122,13 @@ config TCG_XEN
To compile this driver as a module, choose M here; the module
will be called xen-tpmfront.
config TCG_CRB
tristate "TPM 2.0 CRB Interface"
depends on X86 && ACPI
---help---
If you have a TPM security chip that is compliant with the
TCG CRB 2.0 TPM specification 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_crb.
endif # TCG_TPM
......@@ -2,7 +2,7 @@
# Makefile for the kernel tpm device drivers.
#
obj-$(CONFIG_TCG_TPM) += tpm.o
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o
ifdef CONFIG_ACPI
......@@ -20,5 +20,6 @@ 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
obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o
obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
obj-$(CONFIG_TCG_CRB) += tpm_crb.o
/*
* Copyright (C) 2004 IBM Corporation
* Copyright (C) 2014 Intel Corporation
*
* Authors:
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
* Leendert van Doorn <leendert@watson.ibm.com>
* Dave Safford <safford@watson.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* TPM chip management routines.
*
* 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/poll.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/freezer.h>
#include <linux/major.h>
#include "tpm.h"
#include "tpm_eventlog.h"
static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
static LIST_HEAD(tpm_chip_list);
static DEFINE_SPINLOCK(driver_lock);
struct class *tpm_class;
dev_t tpm_devt;
/*
* tpm_chip_find_get - return tpm_chip for a given chip number
* @chip_num the device number for the chip
*/
struct tpm_chip *tpm_chip_find_get(int chip_num)
{
struct tpm_chip *pos, *chip = NULL;
rcu_read_lock();
list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
continue;
if (try_module_get(pos->pdev->driver->owner)) {
chip = pos;
break;
}
}
rcu_read_unlock();
return chip;
}
/**
* tpm_dev_release() - free chip memory and the device number
* @dev: the character device for the TPM chip
*
* This is used as the release function for the character device.
*/
static void tpm_dev_release(struct device *dev)
{
struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
spin_lock(&driver_lock);
clear_bit(chip->dev_num, dev_mask);
spin_unlock(&driver_lock);
kfree(chip);
}
/**
* tpmm_chip_alloc() - allocate a new struct tpm_chip instance
* @dev: device to which the chip is associated
* @ops: struct tpm_class_ops instance
*
* Allocates a new struct tpm_chip instance and assigns a free
* device number for it. Caller does not have to worry about
* freeing the allocated resources. When the devices is removed
* devres calls tpmm_chip_remove() to do the job.
*/
struct tpm_chip *tpmm_chip_alloc(struct device *dev,
const struct tpm_class_ops *ops)
{
struct tpm_chip *chip;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return ERR_PTR(-ENOMEM);
mutex_init(&chip->tpm_mutex);
INIT_LIST_HEAD(&chip->list);
chip->ops = ops;
spin_lock(&driver_lock);
chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
spin_unlock(&driver_lock);
if (chip->dev_num >= TPM_NUM_DEVICES) {
dev_err(dev, "No available tpm device numbers\n");
kfree(chip);
return ERR_PTR(-ENOMEM);
}
set_bit(chip->dev_num, dev_mask);
scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num);
chip->pdev = dev;
dev_set_drvdata(dev, chip);
chip->dev.class = tpm_class;
chip->dev.release = tpm_dev_release;
chip->dev.parent = chip->pdev;
if (chip->dev_num == 0)
chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
else
chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
dev_set_name(&chip->dev, "%s", chip->devname);
device_initialize(&chip->dev);
chip->cdev.owner = chip->pdev->driver->owner;
cdev_init(&chip->cdev, &tpm_fops);
return chip;
}
EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
static int tpm_dev_add_device(struct tpm_chip *chip)
{
int rc;
rc = device_add(&chip->dev);
if (rc) {
dev_err(&chip->dev,
"unable to device_register() %s, major %d, minor %d, err=%d\n",
chip->devname, MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
return rc;
}
rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
if (rc) {
dev_err(&chip->dev,
"unable to cdev_add() %s, major %d, minor %d, err=%d\n",
chip->devname, MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
device_unregister(&chip->dev);
return rc;
}
return rc;
}
static void tpm_dev_del_device(struct tpm_chip *chip)
{
cdev_del(&chip->cdev);
device_unregister(&chip->dev);
}
/*
* tpm_chip_register() - create a character device for the TPM chip
* @chip: TPM chip to use.
*
* Creates a character device for the TPM chip and adds sysfs interfaces for
* the device, PPI and TCPA. As the last step this function adds the
* chip to the list of TPM chips available for use.
*
* NOTE: This function should be only called after the chip initialization
* is complete.
*
* Called from tpm_<specific>.c probe function only for devices
* the driver has determined it should claim. Prior to calling
* this function the specific probe function has called pci_enable_device
* upon errant exit from this function specific probe function should call
* pci_disable_device
*/
int tpm_chip_register(struct tpm_chip *chip)
{
int rc;
rc = tpm_dev_add_device(chip);
if (rc)
return rc;
/* Populate sysfs for TPM1 devices. */
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
rc = tpm_sysfs_add_device(chip);
if (rc)
goto del_misc;
rc = tpm_add_ppi(chip);
if (rc)
goto del_sysfs;
chip->bios_dir = tpm_bios_log_setup(chip->devname);
}
/* Make the chip available. */
spin_lock(&driver_lock);
list_add_rcu(&chip->list, &tpm_chip_list);
spin_unlock(&driver_lock);
chip->flags |= TPM_CHIP_FLAG_REGISTERED;
return 0;
del_sysfs:
tpm_sysfs_del_device(chip);
del_misc:
tpm_dev_del_device(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_chip_register);
/*
* tpm_chip_unregister() - release the TPM driver
* @chip: TPM chip to use.
*
* Takes the chip first away from the list of available TPM chips and then
* cleans up all the resources reserved by tpm_chip_register().
*
* NOTE: This function should be only called before deinitializing chip
* resources.
*/
void tpm_chip_unregister(struct tpm_chip *chip)
{
if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED))
return;
spin_lock(&driver_lock);
list_del_rcu(&chip->list);
spin_unlock(&driver_lock);
synchronize_rcu();
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
if (chip->bios_dir)
tpm_bios_log_teardown(chip->bios_dir);
tpm_remove_ppi(chip);
tpm_sysfs_del_device(chip);
}
tpm_dev_del_device(chip);
}
EXPORT_SYMBOL_GPL(tpm_chip_unregister);
......@@ -17,7 +17,6 @@
* License.
*
*/
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "tpm.h"
......@@ -54,16 +53,15 @@ static void timeout_work(struct work_struct *work)
static int tpm_open(struct inode *inode, struct file *file)
{
struct miscdevice *misc = file->private_data;
struct tpm_chip *chip = container_of(misc, struct tpm_chip,
vendor.miscdev);
struct tpm_chip *chip =
container_of(inode->i_cdev, struct tpm_chip, cdev);
struct file_priv *priv;
/* It's assured that the chip will be opened just once,
* by the check of is_open variable, which is protected
* by driver_lock. */
if (test_and_set_bit(0, &chip->is_open)) {
dev_dbg(chip->dev, "Another process owns this TPM\n");
dev_dbg(chip->pdev, "Another process owns this TPM\n");
return -EBUSY;
}
......@@ -81,7 +79,7 @@ static int tpm_open(struct inode *inode, struct file *file)
INIT_WORK(&priv->work, timeout_work);
file->private_data = priv;
get_device(chip->dev);
get_device(chip->pdev);
return 0;
}
......@@ -168,12 +166,12 @@ static int tpm_release(struct inode *inode, struct file *file)
file->private_data = NULL;
atomic_set(&priv->data_pending, 0);
clear_bit(0, &priv->chip->is_open);
put_device(priv->chip->dev);
put_device(priv->chip->pdev);
kfree(priv);
return 0;
}
static const struct file_operations tpm_fops = {
const struct file_operations tpm_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
......@@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = {
.release = tpm_release,
};
int tpm_dev_add_device(struct tpm_chip *chip)
{
int rc;
chip->vendor.miscdev.fops = &tpm_fops;
if (chip->dev_num == 0)
chip->vendor.miscdev.minor = TPM_MINOR;
else
chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
chip->vendor.miscdev.name = chip->devname;
chip->vendor.miscdev.parent = chip->dev;
rc = misc_register(&chip->vendor.miscdev);
if (rc) {
chip->vendor.miscdev.name = NULL;
dev_err(chip->dev,
"unable to misc_register %s, minor %d err=%d\n",
chip->vendor.miscdev.name,
chip->vendor.miscdev.minor, rc);
}
return rc;
}
void tpm_dev_del_device(struct tpm_chip *chip)
{
if (chip->vendor.miscdev.name)
misc_deregister(&chip->vendor.miscdev);
}
/*
* Copyright (C) 2004 IBM Corporation
* Copyright (C) 2014 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
......@@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
MODULE_PARM_DESC(suspend_pcr,
"PCR to use for dummy writes to faciltate flush on suspend.");
static LIST_HEAD(tpm_chip_list);
static DEFINE_SPINLOCK(driver_lock);
static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result. The ordinal
......@@ -346,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
if (count == 0)
return -ENODATA;
if (count > bufsiz) {
dev_err(chip->dev,
dev_err(chip->pdev,
"invalid count value %x %zx\n", count, bufsiz);
return -E2BIG;
}
......@@ -355,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
rc = chip->ops->send(chip, (u8 *) buf, count);
if (rc < 0) {
dev_err(chip->dev,
dev_err(chip->pdev,
"tpm_transmit: tpm_send: error %zd\n", rc);
goto out;
}
......@@ -363,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
if (chip->vendor.irq)
goto out_recv;
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
else
stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
do {
u8 status = chip->ops->status(chip);
if ((status & chip->ops->req_complete_mask) ==
......@@ -371,7 +371,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
goto out_recv;
if (chip->ops->req_canceled(chip, status)) {
dev_err(chip->dev, "Operation Canceled\n");
dev_err(chip->pdev, "Operation Canceled\n");
rc = -ECANCELED;
goto out;
}
......@@ -381,14 +381,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
} while (time_before(jiffies, stop));
chip->ops->cancel(chip);
dev_err(chip->dev, "Operation Timed out\n");
dev_err(chip->pdev, "Operation Timed out\n");
rc = -ETIME;
goto out;
out_recv:
rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
if (rc < 0)
dev_err(chip->dev,
dev_err(chip->pdev,
"tpm_transmit: tpm_recv: error %zd\n", rc);
out:
mutex_unlock(&chip->tpm_mutex);
......@@ -398,9 +398,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
#define TPM_DIGEST_SIZE 20
#define TPM_RET_CODE_IDX 6
static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
int len, const char *desc)
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
int len, const char *desc)
{
struct tpm_output_header *header;
int err;
len = tpm_transmit(chip, (u8 *) cmd, len);
......@@ -409,9 +410,12 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
else if (len < TPM_HEADER_SIZE)
return -EFAULT;
err = be32_to_cpu(cmd->header.out.return_code);
header = cmd;
err = be32_to_cpu(header->return_code);
if (err != 0 && desc)
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err,
desc);
return err;
}
......@@ -448,7 +452,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = subcap_id;
}
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
if (!rc)
*cap = tpm_cmd.params.getcap_out.cap;
return rc;
......@@ -464,8 +468,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the timeouts");
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the timeouts");
}
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
......@@ -483,9 +487,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
{
struct tpm_cmd_t start_cmd;
start_cmd.header.in = tpm_startup_header;
start_cmd.params.startup_in.startup_type = startup_type;
return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to start the TPM");
return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to start the TPM");
}
int tpm_get_timeouts(struct tpm_chip *chip)
......@@ -500,12 +505,12 @@ int tpm_get_timeouts(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
if (rc == TPM_ERR_INVALID_POSTINIT) {
/* The TPM is not started, we are the first to talk to it.
Execute a startup command. */
dev_info(chip->dev, "Issuing TPM_STARTUP");
dev_info(chip->pdev, "Issuing TPM_STARTUP");
if (tpm_startup(chip, TPM_ST_CLEAR))
return rc;
......@@ -513,11 +518,11 @@ int tpm_get_timeouts(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
NULL);
}
if (rc) {
dev_err(chip->dev,
dev_err(chip->pdev,
"A TPM error (%zd) occurred attempting to determine the timeouts\n",
rc);
goto duration;
......@@ -556,7 +561,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
/* Report adjusted timeouts */
if (chip->vendor.timeout_adjusted) {
dev_info(chip->dev,
dev_info(chip->pdev,
HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
old_timeout[0], new_timeout[0],
old_timeout[1], new_timeout[1],
......@@ -575,8 +580,8 @@ int tpm_get_timeouts(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the durations");
rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the durations");
if (rc)
return rc;
......@@ -603,7 +608,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
chip->vendor.duration[TPM_MEDIUM] *= 1000;
chip->vendor.duration[TPM_LONG] *= 1000;
chip->vendor.duration_adjusted = true;
dev_info(chip->dev, "Adjusting TPM timeout parameters.");
dev_info(chip->pdev, "Adjusting TPM timeout parameters.");
}
return 0;
}
......@@ -631,32 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
struct tpm_cmd_t cmd;
cmd.header.in = continue_selftest_header;
rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
"continue selftest");
rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
"continue selftest");
return rc;
}
/*
* tpm_chip_find_get - return tpm_chip for given chip number
*/
static struct tpm_chip *tpm_chip_find_get(int chip_num)
{
struct tpm_chip *pos, *chip = NULL;
rcu_read_lock();
list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
continue;
if (try_module_get(pos->dev->driver->owner)) {
chip = pos;
break;
}
}
rcu_read_unlock();
return chip;
}
#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
#define READ_PCR_RESULT_SIZE 30
static struct tpm_input_header pcrread_header = {
......@@ -672,8 +656,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
cmd.header.in = pcrread_header;
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
"attempting to read a pcr value");
rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
"attempting to read a pcr value");
if (rc == 0)
memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
......@@ -700,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
chip = tpm_chip_find_get(chip_num);
if (chip == NULL)
return -ENODEV;
rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
else
rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
tpm_chip_put(chip);
return rc;
}
......@@ -734,11 +721,17 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
if (chip == NULL)
return -ENODEV;
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
rc = tpm2_pcr_extend(chip, pcr_idx, hash);
tpm_chip_put(chip);
return rc;
}
cmd.header.in = pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
"attempting extend a PCR value");
rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
"attempting extend a PCR value");
tpm_chip_put(chip);
return rc;
......@@ -781,7 +774,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
* around 300ms while the self test is ongoing, keep trying
* until the self test duration expires. */
if (rc == -ETIME) {
dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test");
dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test");
msleep(delay_msec);
continue;
}
......@@ -791,7 +784,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
rc = be32_to_cpu(cmd.header.out.return_code);
if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
dev_info(chip->dev,
dev_info(chip->pdev,
"TPM is disabled/deactivated (0x%X)\n", rc);
/* TPM is disabled and/or deactivated; driver can
* proceed and TPM does handle commands for
......@@ -817,7 +810,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
if (chip == NULL)
return -ENODEV;
rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
tpm_chip_put(chip);
return rc;
......@@ -884,30 +877,6 @@ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
}
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
void tpm_remove_hardware(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip == NULL) {
dev_err(dev, "No device data found\n");
return;
}
spin_lock(&driver_lock);
list_del_rcu(&chip->list);
spin_unlock(&driver_lock);
synchronize_rcu();
tpm_dev_del_device(chip);
tpm_sysfs_del_device(chip);
tpm_remove_ppi(&dev->kobj);
tpm_bios_log_teardown(chip->bios_dir);
/* write it this way to be explicit (chip->dev == dev) */
put_device(chip->dev);
}
EXPORT_SYMBOL_GPL(tpm_remove_hardware);
#define TPM_ORD_SAVESTATE cpu_to_be32(152)
#define SAVESTATE_RESULT_SIZE 10
......@@ -932,20 +901,23 @@ int tpm_pm_suspend(struct device *dev)
if (chip == NULL)
return -ENODEV;
if (chip->flags & TPM_CHIP_FLAG_TPM2)
return tpm2_shutdown(chip, TPM2_SU_CLEAR);
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr) {
cmd.header.in = pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
TPM_DIGEST_SIZE);
rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
"extending dummy pcr before suspend");
rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
"extending dummy pcr before suspend");
}
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
cmd.header.in = savestate_header;
rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
/*
* If the TPM indicates that it is too busy to respond to
......@@ -963,10 +935,10 @@ int tpm_pm_suspend(struct device *dev)
}
if (rc)
dev_err(chip->dev,
dev_err(chip->pdev,
"Error (%d) sending savestate before suspend\n", rc);
else if (try > 0)
dev_warn(chip->dev, "TPM savestate took %dms\n",
dev_warn(chip->pdev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
return rc;
......@@ -1018,11 +990,17 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
if (chip == NULL)
return -ENODEV;
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
err = tpm2_get_random(chip, out, max);
tpm_chip_put(chip);
return err;
}
do {
tpm_cmd.header.in = tpm_getrandom_header;
tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
err = transmit_cmd(chip, &tpm_cmd,
err = tpm_transmit_cmd(chip, &tpm_cmd,
TPM_GETRANDOM_RESULT_SIZE + num_bytes,
"attempting get random");
if (err)
......@@ -1041,103 +1019,34 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
}
EXPORT_SYMBOL_GPL(tpm_get_random);
/* In case vendor provided release function, call it too.*/
void tpm_dev_vendor_release(struct tpm_chip *chip)
static int __init tpm_init(void)
{
if (!chip)
return;
clear_bit(chip->dev_num, dev_mask);
}
EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
/*
* Once all references to platform device are down to 0,
* release all allocated structures.
*/
static void tpm_dev_release(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
int rc;
if (!chip)
return;
tpm_class = class_create(THIS_MODULE, "tpm");
if (IS_ERR(tpm_class)) {
pr_err("couldn't create tpm class\n");
return PTR_ERR(tpm_class);
}
tpm_dev_vendor_release(chip);
rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
if (rc < 0) {
pr_err("tpm: failed to allocate char dev region\n");
class_destroy(tpm_class);
return rc;
}
chip->release(dev);
kfree(chip);
return 0;
}
/*
* Called from tpm_<specific>.c probe function only for devices
* the driver has determined it should claim. Prior to calling
* this function the specific probe function has called pci_enable_device
* upon errant exit from this function specific probe function should call
* pci_disable_device
*/
struct tpm_chip *tpm_register_hardware(struct device *dev,
const struct tpm_class_ops *ops)
static void __exit tpm_exit(void)
{
struct tpm_chip *chip;
/* Driver specific per-device data */
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return NULL;
mutex_init(&chip->tpm_mutex);
INIT_LIST_HEAD(&chip->list);
chip->ops = ops;
chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
if (chip->dev_num >= TPM_NUM_DEVICES) {
dev_err(dev, "No available tpm device numbers\n");
goto out_free;
}
set_bit(chip->dev_num, dev_mask);
scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
chip->dev_num);
chip->dev = get_device(dev);
chip->release = dev->release;
dev->release = tpm_dev_release;
dev_set_drvdata(dev, chip);
if (tpm_dev_add_device(chip))
goto put_device;
if (tpm_sysfs_add_device(chip))
goto del_misc;
if (tpm_add_ppi(&dev->kobj))
goto del_sysfs;
chip->bios_dir = tpm_bios_log_setup(chip->devname);
/* Make chip available */
spin_lock(&driver_lock);
list_add_rcu(&chip->list, &tpm_chip_list);
spin_unlock(&driver_lock);
return chip;
del_sysfs:
tpm_sysfs_del_device(chip);
del_misc:
tpm_dev_del_device(chip);
put_device:
put_device(chip->dev);
out_free:
kfree(chip);
return NULL;
class_destroy(tpm_class);
unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
}
EXPORT_SYMBOL_GPL(tpm_register_hardware);
subsys_initcall(tpm_init);
module_exit(tpm_exit);
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
MODULE_DESCRIPTION("TPM Driver");
......
......@@ -20,25 +20,6 @@
#include <linux/device.h>
#include "tpm.h"
/* XXX for now this helper is duplicated in tpm-interface.c */
static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
int len, const char *desc)
{
int err;
len = tpm_transmit(chip, (u8 *) cmd, len);
if (len < 0)
return len;
else if (len < TPM_HEADER_SIZE)
return -EFAULT;
err = be32_to_cpu(cmd->header.out.return_code);
if (err != 0 && desc)
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
return err;
}
#define READ_PUBEK_RESULT_SIZE 314
#define TPM_ORD_READPUBEK cpu_to_be32(124)
static struct tpm_input_header tpm_readpubek_header = {
......@@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
struct tpm_chip *chip = dev_get_drvdata(dev);
tpm_cmd.header.in = tpm_readpubek_header;
err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
"attempting to read the PUBEK");
err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
"attempting to read the PUBEK");
if (err)
goto out;
......@@ -303,16 +284,16 @@ static const struct attribute_group tpm_dev_group = {
int tpm_sysfs_add_device(struct tpm_chip *chip)
{
int err;
err = sysfs_create_group(&chip->dev->kobj,
err = sysfs_create_group(&chip->pdev->kobj,
&tpm_dev_group);
if (err)
dev_err(chip->dev,
dev_err(chip->pdev,
"failed to create sysfs attributes, %d\n", err);
return err;
}
void tpm_sysfs_del_device(struct tpm_chip *chip)
{
sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group);
sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
}
......@@ -10,23 +10,24 @@
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
* 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/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/tpm.h>
#include <linux/acpi.h>
#include <linux/cdev.h>
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
......@@ -61,6 +62,59 @@ enum tpm_duration {
#define TPM_ERR_INVALID_POSTINIT 38
#define TPM_HEADER_SIZE 10
enum tpm2_const {
TPM2_PLATFORM_PCR = 24,
TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
TPM2_TIMEOUT_A = 750,
TPM2_TIMEOUT_B = 2000,
TPM2_TIMEOUT_C = 200,
TPM2_TIMEOUT_D = 30,
TPM2_DURATION_SHORT = 20,
TPM2_DURATION_MEDIUM = 750,
TPM2_DURATION_LONG = 2000,
};
enum tpm2_structures {
TPM2_ST_NO_SESSIONS = 0x8001,
TPM2_ST_SESSIONS = 0x8002,
};
enum tpm2_return_codes {
TPM2_RC_INITIALIZE = 0x0100,
TPM2_RC_TESTING = 0x090A,
TPM2_RC_DISABLED = 0x0120,
};
enum tpm2_algorithms {
TPM2_ALG_SHA1 = 0x0004,
};
enum tpm2_command_codes {
TPM2_CC_FIRST = 0x011F,
TPM2_CC_SELF_TEST = 0x0143,
TPM2_CC_STARTUP = 0x0144,
TPM2_CC_SHUTDOWN = 0x0145,
TPM2_CC_GET_CAPABILITY = 0x017A,
TPM2_CC_GET_RANDOM = 0x017B,
TPM2_CC_PCR_READ = 0x017E,
TPM2_CC_PCR_EXTEND = 0x0182,
TPM2_CC_LAST = 0x018F,
};
enum tpm2_permanent_handles {
TPM2_RS_PW = 0x40000009,
};
enum tpm2_capabilities {
TPM2_CAP_TPM_PROPERTIES = 6,
};
enum tpm2_startup_types {
TPM2_SU_CLEAR = 0x0000,
TPM2_SU_STATE = 0x0001,
};
struct tpm_chip;
struct tpm_vendor_specific {
......@@ -73,7 +127,6 @@ struct tpm_vendor_specific {
int region_size;
int have_region;
struct miscdevice miscdev;
struct list_head list;
int locality;
unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
......@@ -88,15 +141,27 @@ struct tpm_vendor_specific {
u16 manufacturer_id;
};
#define TPM_VPRIV(c) (c)->vendor.priv
#define TPM_VPRIV(c) ((c)->vendor.priv)
#define TPM_VID_INTEL 0x8086
#define TPM_VID_WINBOND 0x1050
#define TPM_VID_STM 0x104A
#define TPM_PPI_VERSION_LEN 3
enum tpm_chip_flags {
TPM_CHIP_FLAG_REGISTERED = BIT(0),
TPM_CHIP_FLAG_PPI = BIT(1),
TPM_CHIP_FLAG_TPM2 = BIT(2),
};
struct tpm_chip {
struct device *dev; /* Device stuff */
struct device *pdev; /* Device stuff */
struct device dev;
struct cdev cdev;
const struct tpm_class_ops *ops;
unsigned int flags;
int dev_num; /* /dev/tpm# */
char devname[7];
......@@ -109,15 +174,19 @@ struct tpm_chip {
struct dentry **bios_dir;
#ifdef CONFIG_ACPI
acpi_handle acpi_dev_handle;
char ppi_version[TPM_PPI_VERSION_LEN + 1];
#endif /* CONFIG_ACPI */
struct list_head list;
void (*release) (struct device *);
};
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
static inline void tpm_chip_put(struct tpm_chip *chip)
{
module_put(chip->dev->driver->owner);
module_put(chip->pdev->driver->owner);
}
static inline int tpm_read_index(int base, int index)
......@@ -313,40 +382,57 @@ struct tpm_cmd_t {
tpm_cmd_params params;
} __packed;
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
extern struct class *tpm_class;
extern dev_t tpm_devt;
extern const struct file_operations tpm_fops;
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
size_t bufsiz);
ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
const char *desc);
extern int tpm_get_timeouts(struct tpm_chip *);
extern void tpm_gen_interrupt(struct tpm_chip *);
extern int tpm_do_selftest(struct tpm_chip *);
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
extern struct tpm_chip* tpm_register_hardware(struct device *,
const struct tpm_class_ops *ops);
extern void tpm_dev_vendor_release(struct tpm_chip *);
extern void tpm_remove_hardware(struct device *);
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 *, bool);
int tpm_dev_add_device(struct tpm_chip *chip);
void tpm_dev_del_device(struct tpm_chip *chip);
struct tpm_chip *tpm_chip_find_get(int chip_num);
extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
const struct tpm_class_ops *ops);
extern int tpm_chip_register(struct tpm_chip *chip);
extern void tpm_chip_unregister(struct tpm_chip *chip);
int tpm_sysfs_add_device(struct tpm_chip *chip);
void tpm_sysfs_del_device(struct tpm_chip *chip);
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
#ifdef CONFIG_ACPI
extern int tpm_add_ppi(struct kobject *);
extern void tpm_remove_ppi(struct kobject *);
extern int tpm_add_ppi(struct tpm_chip *chip);
extern void tpm_remove_ppi(struct tpm_chip *chip);
#else
static inline int tpm_add_ppi(struct kobject *parent)
static inline int tpm_add_ppi(struct tpm_chip *chip)
{
return 0;
}
static inline void tpm_remove_ppi(struct kobject *parent)
static inline void tpm_remove_ppi(struct tpm_chip *chip)
{
}
#endif
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
u32 *value, const char *desc);
extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type);
extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32);
extern int tpm2_do_selftest(struct tpm_chip *chip);
extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet);
/*
* Copyright (C) 2014 Intel Corporation
*
* Authors:
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* This file contains TPM2 protocol implementations of the commands
* used by the kernel internally.
*
* 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 "tpm.h"
struct tpm2_startup_in {
__be16 startup_type;
} __packed;
struct tpm2_self_test_in {
u8 full_test;
} __packed;
struct tpm2_pcr_read_in {
__be32 pcr_selects_cnt;
__be16 hash_alg;
u8 pcr_select_size;
u8 pcr_select[TPM2_PCR_SELECT_MIN];
} __packed;
struct tpm2_pcr_read_out {
__be32 update_cnt;
__be32 pcr_selects_cnt;
__be16 hash_alg;
u8 pcr_select_size;
u8 pcr_select[TPM2_PCR_SELECT_MIN];
__be32 digests_cnt;
__be16 digest_size;
u8 digest[TPM_DIGEST_SIZE];
} __packed;
struct tpm2_null_auth_area {
__be32 handle;
__be16 nonce_size;
u8 attributes;
__be16 auth_size;
} __packed;
struct tpm2_pcr_extend_in {
__be32 pcr_idx;
__be32 auth_area_size;
struct tpm2_null_auth_area auth_area;
__be32 digest_cnt;
__be16 hash_alg;
u8 digest[TPM_DIGEST_SIZE];
} __packed;
struct tpm2_get_tpm_pt_in {
__be32 cap_id;
__be32 property_id;
__be32 property_cnt;
} __packed;
struct tpm2_get_tpm_pt_out {
u8 more_data;
__be32 subcap_id;
__be32 property_cnt;
__be32 property_id;
__be32 value;
} __packed;
struct tpm2_get_random_in {
__be16 size;
} __packed;
struct tpm2_get_random_out {
__be16 size;
u8 buffer[TPM_MAX_RNG_DATA];
} __packed;
union tpm2_cmd_params {
struct tpm2_startup_in startup_in;
struct tpm2_self_test_in selftest_in;
struct tpm2_pcr_read_in pcrread_in;
struct tpm2_pcr_read_out pcrread_out;
struct tpm2_pcr_extend_in pcrextend_in;
struct tpm2_get_tpm_pt_in get_tpm_pt_in;
struct tpm2_get_tpm_pt_out get_tpm_pt_out;
struct tpm2_get_random_in getrandom_in;
struct tpm2_get_random_out getrandom_out;
};
struct tpm2_cmd {
tpm_cmd_header header;
union tpm2_cmd_params params;
} __packed;
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result. The values
* of the SHORT, MEDIUM, and LONG durations are taken from the
* PC Client Profile (PTP) specification.
*/
static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
TPM_UNDEFINED, /* 11F */
TPM_UNDEFINED, /* 120 */
TPM_LONG, /* 121 */
TPM_UNDEFINED, /* 122 */
TPM_UNDEFINED, /* 123 */
TPM_UNDEFINED, /* 124 */
TPM_UNDEFINED, /* 125 */
TPM_UNDEFINED, /* 126 */
TPM_UNDEFINED, /* 127 */
TPM_UNDEFINED, /* 128 */
TPM_LONG, /* 129 */
TPM_UNDEFINED, /* 12a */
TPM_UNDEFINED, /* 12b */
TPM_UNDEFINED, /* 12c */
TPM_UNDEFINED, /* 12d */
TPM_UNDEFINED, /* 12e */
TPM_UNDEFINED, /* 12f */
TPM_UNDEFINED, /* 130 */
TPM_UNDEFINED, /* 131 */
TPM_UNDEFINED, /* 132 */
TPM_UNDEFINED, /* 133 */
TPM_UNDEFINED, /* 134 */
TPM_UNDEFINED, /* 135 */
TPM_UNDEFINED, /* 136 */
TPM_UNDEFINED, /* 137 */
TPM_UNDEFINED, /* 138 */
TPM_UNDEFINED, /* 139 */
TPM_UNDEFINED, /* 13a */
TPM_UNDEFINED, /* 13b */
TPM_UNDEFINED, /* 13c */
TPM_UNDEFINED, /* 13d */
TPM_MEDIUM, /* 13e */
TPM_UNDEFINED, /* 13f */
TPM_UNDEFINED, /* 140 */
TPM_UNDEFINED, /* 141 */
TPM_UNDEFINED, /* 142 */
TPM_LONG, /* 143 */
TPM_MEDIUM, /* 144 */
TPM_UNDEFINED, /* 145 */
TPM_UNDEFINED, /* 146 */
TPM_UNDEFINED, /* 147 */
TPM_UNDEFINED, /* 148 */
TPM_UNDEFINED, /* 149 */
TPM_UNDEFINED, /* 14a */
TPM_UNDEFINED, /* 14b */
TPM_UNDEFINED, /* 14c */
TPM_UNDEFINED, /* 14d */
TPM_LONG, /* 14e */
TPM_UNDEFINED, /* 14f */
TPM_UNDEFINED, /* 150 */
TPM_UNDEFINED, /* 151 */
TPM_UNDEFINED, /* 152 */
TPM_UNDEFINED, /* 153 */
TPM_UNDEFINED, /* 154 */
TPM_UNDEFINED, /* 155 */
TPM_UNDEFINED, /* 156 */
TPM_UNDEFINED, /* 157 */
TPM_UNDEFINED, /* 158 */
TPM_UNDEFINED, /* 159 */
TPM_UNDEFINED, /* 15a */
TPM_UNDEFINED, /* 15b */
TPM_MEDIUM, /* 15c */
TPM_UNDEFINED, /* 15d */
TPM_UNDEFINED, /* 15e */
TPM_UNDEFINED, /* 15f */
TPM_UNDEFINED, /* 160 */
TPM_UNDEFINED, /* 161 */
TPM_UNDEFINED, /* 162 */
TPM_UNDEFINED, /* 163 */
TPM_UNDEFINED, /* 164 */
TPM_UNDEFINED, /* 165 */
TPM_UNDEFINED, /* 166 */
TPM_UNDEFINED, /* 167 */
TPM_UNDEFINED, /* 168 */
TPM_UNDEFINED, /* 169 */
TPM_UNDEFINED, /* 16a */
TPM_UNDEFINED, /* 16b */
TPM_UNDEFINED, /* 16c */
TPM_UNDEFINED, /* 16d */
TPM_UNDEFINED, /* 16e */
TPM_UNDEFINED, /* 16f */
TPM_UNDEFINED, /* 170 */
TPM_UNDEFINED, /* 171 */
TPM_UNDEFINED, /* 172 */
TPM_UNDEFINED, /* 173 */
TPM_UNDEFINED, /* 174 */
TPM_UNDEFINED, /* 175 */
TPM_UNDEFINED, /* 176 */
TPM_LONG, /* 177 */
TPM_UNDEFINED, /* 178 */
TPM_UNDEFINED, /* 179 */
TPM_MEDIUM, /* 17a */
TPM_LONG, /* 17b */
TPM_UNDEFINED, /* 17c */
TPM_UNDEFINED, /* 17d */
TPM_UNDEFINED, /* 17e */
TPM_UNDEFINED, /* 17f */
TPM_UNDEFINED, /* 180 */
TPM_UNDEFINED, /* 181 */
TPM_MEDIUM, /* 182 */
TPM_UNDEFINED, /* 183 */
TPM_UNDEFINED, /* 184 */
TPM_MEDIUM, /* 185 */
TPM_MEDIUM, /* 186 */
TPM_UNDEFINED, /* 187 */
TPM_UNDEFINED, /* 188 */
TPM_UNDEFINED, /* 189 */
TPM_UNDEFINED, /* 18a */
TPM_UNDEFINED, /* 18b */
TPM_UNDEFINED, /* 18c */
TPM_UNDEFINED, /* 18d */
TPM_UNDEFINED, /* 18e */
TPM_UNDEFINED /* 18f */
};
#define TPM2_PCR_READ_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_pcr_read_in))
static const struct tpm_input_header tpm2_pcrread_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE),
.ordinal = cpu_to_be32(TPM2_CC_PCR_READ)
};
/**
* tpm2_pcr_read() - read a PCR value
* @chip: TPM chip to use.
* @pcr_idx: index of the PCR to read.
* @ref_buf: buffer to store the resulting hash,
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
{
int rc;
struct tpm2_cmd cmd;
u8 *buf;
if (pcr_idx >= TPM2_PLATFORM_PCR)
return -EINVAL;
cmd.header.in = tpm2_pcrread_header;
cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
memset(cmd.params.pcrread_in.pcr_select, 0,
sizeof(cmd.params.pcrread_in.pcr_select));
cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"attempting to read a pcr value");
if (rc == 0) {
buf = cmd.params.pcrread_out.digest;
memcpy(res_buf, buf, TPM_DIGEST_SIZE);
}
return rc;
}
#define TPM2_GET_PCREXTEND_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_pcr_extend_in))
static const struct tpm_input_header tpm2_pcrextend_header = {
.tag = cpu_to_be16(TPM2_ST_SESSIONS),
.length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE),
.ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
};
/**
* tpm2_pcr_extend() - extend a PCR value
* @chip: TPM chip to use.
* @pcr_idx: index of the PCR.
* @hash: hash value to use for the extend operation.
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
{
struct tpm2_cmd cmd;
int rc;
cmd.header.in = tpm2_pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
cmd.params.pcrextend_in.auth_area_size =
cpu_to_be32(sizeof(struct tpm2_null_auth_area));
cmd.params.pcrextend_in.auth_area.handle =
cpu_to_be32(TPM2_RS_PW);
cmd.params.pcrextend_in.auth_area.nonce_size = 0;
cmd.params.pcrextend_in.auth_area.attributes = 0;
cmd.params.pcrextend_in.auth_area.auth_size = 0;
cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1);
cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"attempting extend a PCR value");
return rc;
}
#define TPM2_GETRANDOM_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_get_random_in))
static const struct tpm_input_header tpm2_getrandom_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE),
.ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM)
};
/**
* tpm2_get_random() - get random bytes from the TPM RNG
* @chip: TPM chip to use
* @out: destination buffer for the random bytes
* @max: the max number of bytes to write to @out
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
{
struct tpm2_cmd cmd;
u32 recd;
u32 num_bytes;
int err;
int total = 0;
int retries = 5;
u8 *dest = out;
num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer));
if (!out || !num_bytes ||
max > sizeof(cmd.params.getrandom_out.buffer))
return -EINVAL;
do {
cmd.header.in = tpm2_getrandom_header;
cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"attempting get random");
if (err)
break;
recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size),
num_bytes);
memcpy(dest, cmd.params.getrandom_out.buffer, recd);
dest += recd;
total += recd;
num_bytes -= recd;
} while (retries-- && total < max);
return total ? total : -EIO;
}
#define TPM2_GET_TPM_PT_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_get_tpm_pt_in))
static const struct tpm_input_header tpm2_get_tpm_pt_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE),
.ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
};
/**
* tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
* @chip: TPM chip to use.
* @property_id: property ID.
* @value: output variable.
* @desc: passed to tpm_transmit_cmd()
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
const char *desc)
{
struct tpm2_cmd cmd;
int rc;
cmd.header.in = tpm2_get_tpm_pt_header;
cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc);
if (!rc)
*value = cmd.params.get_tpm_pt_out.value;
return rc;
}
#define TPM2_STARTUP_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_startup_in))
static const struct tpm_input_header tpm2_startup_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_STARTUP_IN_SIZE),
.ordinal = cpu_to_be32(TPM2_CC_STARTUP)
};
/**
* tpm2_startup() - send startup command to the TPM chip
* @chip: TPM chip to use.
* @startup_type startup type. The value is either
* TPM_SU_CLEAR or TPM_SU_STATE.
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
{
struct tpm2_cmd cmd;
cmd.header.in = tpm2_startup_header;
cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"attempting to start the TPM");
}
EXPORT_SYMBOL_GPL(tpm2_startup);
#define TPM2_SHUTDOWN_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_startup_in))
static const struct tpm_input_header tpm2_shutdown_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE),
.ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN)
};
/**
* tpm2_shutdown() - send shutdown command to the TPM chip
* @chip: TPM chip to use.
* @shutdown_type shutdown type. The value is either
* TPM_SU_CLEAR or TPM_SU_STATE.
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{
struct tpm2_cmd cmd;
cmd.header.in = tpm2_shutdown_header;
cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"stopping the TPM");
}
EXPORT_SYMBOL_GPL(tpm2_shutdown);
/*
* tpm2_calc_ordinal_duration() - maximum duration for a command
* @chip: TPM chip to use.
* @ordinal: command code number.
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
{
int index = TPM_UNDEFINED;
int duration = 0;
if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST)
index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST];
if (index != TPM_UNDEFINED)
duration = chip->vendor.duration[index];
if (duration <= 0)
duration = 2 * 60 * HZ;
return duration;
}
EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
#define TPM2_SELF_TEST_IN_SIZE \
(sizeof(struct tpm_input_header) + \
sizeof(struct tpm2_self_test_in))
static const struct tpm_input_header tpm2_selftest_header = {
.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
.length = cpu_to_be32(TPM2_SELF_TEST_IN_SIZE),
.ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
};
/**
* tpm2_continue_selftest() - start a self test
* @chip: TPM chip to use
* @full: test all commands instead of testing only those that were not
* previously tested.
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
{
int rc;
struct tpm2_cmd cmd;
cmd.header.in = tpm2_selftest_header;
cmd.params.selftest_in.full_test = full;
rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE,
"continue selftest");
/* At least some prototype chips seem to give RC_TESTING error
* immediately. This is a workaround for that.
*/
if (rc == TPM2_RC_TESTING) {
dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n");
rc = 0;
}
return rc;
}
/**
* tpm2_do_selftest() - run a full self test
* @chip: TPM chip to use
*
* During the self test TPM2 commands return with the error code RC_TESTING.
* Waiting is done by issuing PCR read until it executes successfully.
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
int tpm2_do_selftest(struct tpm_chip *chip)
{
int rc;
unsigned int loops;
unsigned int delay_msec = 100;
unsigned long duration;
struct tpm2_cmd cmd;
int i;
duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
loops = jiffies_to_msecs(duration) / delay_msec;
rc = tpm2_start_selftest(chip, true);
if (rc)
return rc;
for (i = 0; i < loops; i++) {
/* Attempt to read a PCR value */
cmd.header.in = tpm2_pcrread_header;
cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
cmd.params.pcrread_in.pcr_select[0] = 0x01;
cmd.params.pcrread_in.pcr_select[1] = 0x00;
cmd.params.pcrread_in.pcr_select[2] = 0x00;
rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL);
if (rc < 0)
break;
rc = be32_to_cpu(cmd.header.out.return_code);
if (rc != TPM2_RC_TESTING)
break;
msleep(delay_msec);
}
return rc;
}
EXPORT_SYMBOL_GPL(tpm2_do_selftest);
/**
* tpm2_gen_interrupt() - generate an interrupt
* @chip: TPM chip to use
* @quiet: surpress the error message
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/
int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet)
{
const char *desc = NULL;
u32 dummy;
if (!quiet)
desc = "attempting to generate an interrupt";
return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc);
}
EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);
......@@ -49,7 +49,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
for (i = 0; i < 6; i++) {
status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev, "error reading header\n");
dev_err(chip->pdev, "error reading header\n");
return -EIO;
}
*buf++ = ioread8(chip->vendor.iobase);
......@@ -60,12 +60,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
size = be32_to_cpu(*native_size);
if (count < size) {
dev_err(chip->dev,
dev_err(chip->pdev,
"Recv size(%d) less than available space\n", size);
for (; i < size; i++) { /* clear the waiting data anyway */
status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev, "error reading data\n");
dev_err(chip->pdev, "error reading data\n");
return -EIO;
}
}
......@@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
for (; i < size; i++) {
status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev, "error reading data\n");
dev_err(chip->pdev, "error reading data\n");
return -EIO;
}
*buf++ = ioread8(chip->vendor.iobase);
......@@ -86,7 +86,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
status = ioread8(chip->vendor.iobase + 1);
if (status & ATML_STATUS_DATA_AVAIL) {
dev_err(chip->dev, "data available is stuck\n");
dev_err(chip->pdev, "data available is stuck\n");
return -EIO;
}
......@@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
{
int i;
dev_dbg(chip->dev, "tpm_atml_send:\n");
dev_dbg(chip->pdev, "tpm_atml_send:\n");
for (i = 0; i < count; i++) {
dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
dev_dbg(chip->pdev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
iowrite8(buf[i], chip->vendor.iobase);
}
......@@ -138,11 +138,11 @@ static void atml_plat_remove(void)
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
if (chip) {
tpm_chip_unregister(chip);
if (chip->vendor.have_region)
atmel_release_region(chip->vendor.base,
chip->vendor.region_size);
atmel_put_base_addr(chip->vendor.iobase);
tpm_remove_hardware(chip->dev);
platform_device_unregister(pdev);
}
}
......@@ -183,8 +183,9 @@ static int __init init_atmel(void)
goto err_rel_reg;
}
if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
rc = -ENODEV;
chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
if (IS_ERR(chip)) {
rc = PTR_ERR(chip);
goto err_unreg_dev;
}
......@@ -193,6 +194,10 @@ static int __init init_atmel(void)
chip->vendor.have_region = have_region;
chip->vendor.region_size = region_size;
rc = tpm_chip_register(chip);
if (rc)
goto err_unreg_dev;
return 0;
err_unreg_dev:
......
/*
* Copyright (C) 2014 Intel Corporation
*
* Authors:
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* This device driver implements the TPM interface as defined in
* the TCG CRB 2.0 TPM specification.
*
* 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/acpi.h>
#include <linux/highmem.h>
#include <linux/rculist.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "tpm.h"
#define ACPI_SIG_TPM2 "TPM2"
static const u8 CRB_ACPI_START_UUID[] = {
/* 0000 */ 0xAB, 0x6C, 0xBF, 0x6B, 0x63, 0x54, 0x14, 0x47,
/* 0008 */ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4
};
enum crb_defaults {
CRB_ACPI_START_REVISION_ID = 1,
CRB_ACPI_START_INDEX = 1,
};
enum crb_start_method {
CRB_SM_ACPI_START = 2,
CRB_SM_CRB = 7,
CRB_SM_CRB_WITH_ACPI_START = 8,
};
struct acpi_tpm2 {
struct acpi_table_header hdr;
u16 platform_class;
u16 reserved;
u64 control_area_pa;
u32 start_method;
} __packed;
enum crb_ca_request {
CRB_CA_REQ_GO_IDLE = BIT(0),
CRB_CA_REQ_CMD_READY = BIT(1),
};
enum crb_ca_status {
CRB_CA_STS_ERROR = BIT(0),
CRB_CA_STS_TPM_IDLE = BIT(1),
};
enum crb_start {
CRB_START_INVOKE = BIT(0),
};
enum crb_cancel {
CRB_CANCEL_INVOKE = BIT(0),
};
struct crb_control_area {
u32 req;
u32 sts;
u32 cancel;
u32 start;
u32 int_enable;
u32 int_sts;
u32 cmd_size;
u64 cmd_pa;
u32 rsp_size;
u64 rsp_pa;
} __packed;
enum crb_status {
CRB_STS_COMPLETE = BIT(0),
};
enum crb_flags {
CRB_FL_ACPI_START = BIT(0),
CRB_FL_CRB_START = BIT(1),
};
struct crb_priv {
unsigned int flags;
struct crb_control_area __iomem *cca;
u8 __iomem *cmd;
u8 __iomem *rsp;
};
#ifdef CONFIG_PM_SLEEP
static int crb_resume(struct device *dev)
{
int rc;
struct tpm_chip *chip = dev_get_drvdata(dev);
rc = tpm2_shutdown(chip, TPM2_SU_STATE);
if (!rc)
rc = tpm2_do_selftest(chip);
return rc;
}
#endif
static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume);
static u8 crb_status(struct tpm_chip *chip)
{
struct crb_priv *priv = chip->vendor.priv;
u8 sts = 0;
if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) !=
CRB_START_INVOKE)
sts |= CRB_STS_COMPLETE;
return sts;
}
static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct crb_priv *priv = chip->vendor.priv;
unsigned int expected;
/* sanity check */
if (count < 6)
return -EIO;
if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR)
return -EIO;
memcpy_fromio(buf, priv->rsp, 6);
expected = be32_to_cpup((__be32 *) &buf[2]);
if (expected > count)
return -EIO;
memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
return expected;
}
static int crb_do_acpi_start(struct tpm_chip *chip)
{
union acpi_object *obj;
int rc;
obj = acpi_evaluate_dsm(chip->acpi_dev_handle,
CRB_ACPI_START_UUID,
CRB_ACPI_START_REVISION_ID,
CRB_ACPI_START_INDEX,
NULL);
if (!obj)
return -ENXIO;
rc = obj->integer.value == 0 ? 0 : -ENXIO;
ACPI_FREE(obj);
return rc;
}
static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
struct crb_priv *priv = chip->vendor.priv;
int rc = 0;
if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) {
dev_err(&chip->dev,
"invalid command count value %x %zx\n",
(unsigned int) len,
(size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size)));
return -E2BIG;
}
memcpy_toio(priv->cmd, buf, len);
/* Make sure that cmd is populated before issuing start. */
wmb();
if (priv->flags & CRB_FL_CRB_START)
iowrite32(cpu_to_le32(CRB_START_INVOKE), &priv->cca->start);
if (priv->flags & CRB_FL_ACPI_START)
rc = crb_do_acpi_start(chip);
return rc;
}
static void crb_cancel(struct tpm_chip *chip)
{
struct crb_priv *priv = chip->vendor.priv;
iowrite32(cpu_to_le32(CRB_CANCEL_INVOKE), &priv->cca->cancel);
/* Make sure that cmd is populated before issuing cancel. */
wmb();
if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
dev_err(&chip->dev, "ACPI Start failed\n");
iowrite32(0, &priv->cca->cancel);
}
static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
{
struct crb_priv *priv = chip->vendor.priv;
u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel));
return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
}
static const struct tpm_class_ops tpm_crb = {
.status = crb_status,
.recv = crb_recv,
.send = crb_send,
.cancel = crb_cancel,
.req_canceled = crb_req_canceled,
.req_complete_mask = CRB_STS_COMPLETE,
.req_complete_val = CRB_STS_COMPLETE,
};
static int crb_acpi_add(struct acpi_device *device)
{
struct tpm_chip *chip;
struct acpi_tpm2 *buf;
struct crb_priv *priv;
struct device *dev = &device->dev;
acpi_status status;
u32 sm;
u64 pa;
int rc;
chip = tpmm_chip_alloc(dev, &tpm_crb);
if (IS_ERR(chip))
return PTR_ERR(chip);
chip->flags = TPM_CHIP_FLAG_TPM2;
status = acpi_get_table(ACPI_SIG_TPM2, 1,
(struct acpi_table_header **) &buf);
if (ACPI_FAILURE(status)) {
dev_err(dev, "failed to get TPM2 ACPI table\n");
return -ENODEV;
}
if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
dev_err(dev, "TPM2 ACPI table has wrong size");
return -EINVAL;
}
priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv),
GFP_KERNEL);
if (!priv) {
dev_err(dev, "failed to devm_kzalloc for private data\n");
return -ENOMEM;
}
sm = le32_to_cpu(buf->start_method);
/* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
* report only ACPI start but in practice seems to require both
* ACPI start and CRB start.
*/
if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START ||
!strcmp(acpi_device_hid(device), "MSFT0101"))
priv->flags |= CRB_FL_CRB_START;
if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
priv->flags |= CRB_FL_ACPI_START;
priv->cca = (struct crb_control_area __iomem *)
devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
if (!priv->cca) {
dev_err(dev, "ioremap of the control area failed\n");
return -ENOMEM;
}
memcpy_fromio(&pa, &priv->cca->cmd_pa, 8);
pa = le64_to_cpu(pa);
priv->cmd = devm_ioremap_nocache(dev, le64_to_cpu(pa),
ioread32(&priv->cca->cmd_size));
if (!priv->cmd) {
dev_err(dev, "ioremap of the command buffer failed\n");
return -ENOMEM;
}
memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
pa = le64_to_cpu(pa);
priv->rsp = devm_ioremap_nocache(dev, le64_to_cpu(pa),
ioread32(&priv->cca->rsp_size));
if (!priv->rsp) {
dev_err(dev, "ioremap of the response buffer failed\n");
return -ENOMEM;
}
chip->vendor.priv = priv;
/* Default timeouts and durations */
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
chip->vendor.duration[TPM_SHORT] =
msecs_to_jiffies(TPM2_DURATION_SHORT);
chip->vendor.duration[TPM_MEDIUM] =
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
chip->vendor.duration[TPM_LONG] =
msecs_to_jiffies(TPM2_DURATION_LONG);
chip->acpi_dev_handle = device->handle;
rc = tpm2_do_selftest(chip);
if (rc)
return rc;
return tpm_chip_register(chip);
}
static int crb_acpi_remove(struct acpi_device *device)
{
struct device *dev = &device->dev;
struct tpm_chip *chip = dev_get_drvdata(dev);
tpm_chip_unregister(chip);
return 0;
}
static struct acpi_device_id crb_device_ids[] = {
{"MSFT0101", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, crb_device_ids);
static struct acpi_driver crb_acpi_driver = {
.name = "tpm_crb",
.ids = crb_device_ids,
.ops = {
.add = crb_acpi_add,
.remove = crb_acpi_remove,
},
.drv = {
.pm = &crb_pm,
},
};
module_acpi_driver(crb_acpi_driver);
MODULE_AUTHOR("Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>");
MODULE_DESCRIPTION("TPM2 Driver");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
......@@ -52,7 +52,7 @@ struct priv_data {
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
struct priv_data *priv = chip->vendor.priv;
struct i2c_client *client = to_i2c_client(chip->dev);
struct i2c_client *client = to_i2c_client(chip->pdev);
s32 status;
priv->len = 0;
......@@ -62,7 +62,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
status = i2c_master_send(client, buf, len);
dev_dbg(chip->dev,
dev_dbg(chip->pdev,
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
(int)min_t(size_t, 64, len), buf, len, status);
return status;
......@@ -71,7 +71,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct priv_data *priv = chip->vendor.priv;
struct i2c_client *client = to_i2c_client(chip->dev);
struct i2c_client *client = to_i2c_client(chip->pdev);
struct tpm_output_header *hdr =
(struct tpm_output_header *)priv->buffer;
u32 expected_len;
......@@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
return -ENOMEM;
if (priv->len >= expected_len) {
dev_dbg(chip->dev,
dev_dbg(chip->pdev,
"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
(int)min_t(size_t, 64, expected_len), buf, count,
expected_len);
......@@ -97,7 +97,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
}
rc = i2c_master_recv(client, buf, expected_len);
dev_dbg(chip->dev,
dev_dbg(chip->pdev,
"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
(int)min_t(size_t, 64, expected_len), buf, count,
expected_len);
......@@ -106,13 +106,13 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
static void i2c_atmel_cancel(struct tpm_chip *chip)
{
dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported");
dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported");
}
static u8 i2c_atmel_read_status(struct tpm_chip *chip)
{
struct priv_data *priv = chip->vendor.priv;
struct i2c_client *client = to_i2c_client(chip->dev);
struct i2c_client *client = to_i2c_client(chip->pdev);
int rc;
/* The TPM fails the I2C read until it is ready, so we do the entire
......@@ -125,7 +125,7 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip)
/* Once the TPM has completed the command the command remains readable
* until another command is issued. */
rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
dev_dbg(chip->dev,
dev_dbg(chip->pdev,
"%s: sts=%d", __func__, rc);
if (rc <= 0)
return 0;
......@@ -153,21 +153,20 @@ static const struct tpm_class_ops i2c_atmel = {
static int i2c_atmel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc;
struct tpm_chip *chip;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
chip = tpm_register_hardware(dev, &i2c_atmel);
if (!chip) {
dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
return -ENODEV;
}
chip = tpmm_chip_alloc(dev, &i2c_atmel);
if (IS_ERR(chip))
return PTR_ERR(chip);
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
GFP_KERNEL);
if (!chip->vendor.priv)
return -ENOMEM;
/* Default timeouts */
chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
......@@ -179,33 +178,20 @@ static int i2c_atmel_probe(struct i2c_client *client,
/* There is no known way to probe for this device, and all version
* information seems to be read via TPM commands. Thus we rely on the
* TPM startup process in the common code to detect the device. */
if (tpm_get_timeouts(chip)) {
rc = -ENODEV;
goto out_err;
}
if (tpm_do_selftest(chip)) {
rc = -ENODEV;
goto out_err;
}
if (tpm_get_timeouts(chip))
return -ENODEV;
return 0;
if (tpm_do_selftest(chip))
return -ENODEV;
out_err:
tpm_dev_vendor_release(chip);
tpm_remove_hardware(chip->dev);
return rc;
return tpm_chip_register(chip);
}
static int i2c_atmel_remove(struct i2c_client *client)
{
struct device *dev = &(client->dev);
struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip)
tpm_dev_vendor_release(chip);
tpm_remove_hardware(dev);
kfree(chip);
tpm_chip_unregister(chip);
return 0;
}
......
......@@ -446,7 +446,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
/* read first 10 bytes, including tag, paramsize, and result */
size = recv_data(chip, buf, TPM_HEADER_SIZE);
if (size < TPM_HEADER_SIZE) {
dev_err(chip->dev, "Unable to read header\n");
dev_err(chip->pdev, "Unable to read header\n");
goto out;
}
......@@ -459,14 +459,14 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
size += recv_data(chip, &buf[TPM_HEADER_SIZE],
expected - TPM_HEADER_SIZE);
if (size < expected) {
dev_err(chip->dev, "Unable to read remainder of result\n");
dev_err(chip->pdev, "Unable to read remainder of result\n");
size = -ETIME;
goto out;
}
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
dev_err(chip->dev, "Error left over data\n");
dev_err(chip->pdev, "Error left over data\n");
size = -EIO;
goto out;
}
......@@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
int rc = 0;
struct tpm_chip *chip;
chip = tpm_register_hardware(dev, &tpm_tis_i2c);
if (!chip) {
dev_err(dev, "could not register hardware\n");
rc = -ENODEV;
goto out_err;
}
chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
if (IS_ERR(chip))
return PTR_ERR(chip);
/* Disable interrupts */
chip->vendor.irq = 0;
......@@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
if (request_locality(chip, 0) != 0) {
dev_err(dev, "could not request locality\n");
rc = -ENODEV;
goto out_vendor;
goto out_err;
}
/* read four bytes from DID_VID register */
......@@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev)
tpm_get_timeouts(chip);
tpm_do_selftest(chip);
return 0;
return tpm_chip_register(chip);
out_release:
release_locality(chip, chip->vendor.locality, 1);
out_vendor:
/* close file handles */
tpm_dev_vendor_release(chip);
/* remove hardware */
tpm_remove_hardware(chip->dev);
/* reset these pointers, otherwise we oops */
chip->dev->release = NULL;
chip->release = NULL;
tpm_dev.client = NULL;
out_err:
return rc;
......@@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
static int tpm_tis_i2c_remove(struct i2c_client *client)
{
struct tpm_chip *chip = tpm_dev.chip;
release_locality(chip, chip->vendor.locality, 1);
/* close file handles */
tpm_dev_vendor_release(chip);
/* remove hardware */
tpm_remove_hardware(chip->dev);
/* reset these pointers, otherwise we oops */
chip->dev->release = NULL;
chip->release = NULL;
tpm_chip_unregister(chip);
release_locality(chip, chip->vendor.locality, 1);
tpm_dev.client = NULL;
return 0;
......
......@@ -96,13 +96,13 @@ static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size,
/* read TPM_STS register */
static u8 i2c_nuvoton_read_status(struct tpm_chip *chip)
{
struct i2c_client *client = to_i2c_client(chip->dev);
struct i2c_client *client = to_i2c_client(chip->pdev);
s32 status;
u8 data;
status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
if (status <= 0) {
dev_err(chip->dev, "%s() error return %d\n", __func__,
dev_err(chip->pdev, "%s() error return %d\n", __func__,
status);
data = TPM_STS_ERR_VAL;
}
......@@ -127,13 +127,13 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data)
/* write commandReady to TPM_STS register */
static void i2c_nuvoton_ready(struct tpm_chip *chip)
{
struct i2c_client *client = to_i2c_client(chip->dev);
struct i2c_client *client = to_i2c_client(chip->pdev);
s32 status;
/* this causes the current command to be aborted */
status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
if (status < 0)
dev_err(chip->dev,
dev_err(chip->pdev,
"%s() fail to write TPM_STS.commandReady\n", __func__);
}
......@@ -212,7 +212,7 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value,
return 0;
} while (time_before(jiffies, stop));
}
dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
value);
return -ETIMEDOUT;
}
......@@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
&chip->vendor.read_queue) == 0) {
burst_count = i2c_nuvoton_get_burstcount(client, chip);
if (burst_count < 0) {
dev_err(chip->dev,
dev_err(chip->pdev,
"%s() fail to read burstCount=%d\n", __func__,
burst_count);
return -EIO;
......@@ -249,12 +249,12 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R,
bytes2read, &buf[size]);
if (rc < 0) {
dev_err(chip->dev,
dev_err(chip->pdev,
"%s() fail on i2c_nuvoton_read_buf()=%d\n",
__func__, rc);
return -EIO;
}
dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read);
dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read);
size += bytes2read;
}
......@@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
/* Read TPM command results */
static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct device *dev = chip->dev;
struct device *dev = chip->pdev;
struct i2c_client *client = to_i2c_client(dev);
s32 rc;
int expected, status, burst_count, retries, size = 0;
......@@ -334,7 +334,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
break;
}
i2c_nuvoton_ready(chip);
dev_dbg(chip->dev, "%s() -> %d\n", __func__, size);
dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size);
return size;
}
......@@ -347,7 +347,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
*/
static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
struct device *dev = chip->dev;
struct device *dev = chip->pdev;
struct i2c_client *client = to_i2c_client(dev);
u32 ordinal;
size_t count = 0;
......@@ -530,14 +530,15 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
(u8) (vid >> 16), (u8) (vid >> 24));
chip = tpm_register_hardware(dev, &tpm_i2c);
if (!chip) {
dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
return -ENODEV;
}
chip = tpmm_chip_alloc(dev, &tpm_i2c);
if (IS_ERR(chip))
return PTR_ERR(chip);
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
GFP_KERNEL);
if (!chip->vendor.priv)
return -ENOMEM;
init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue);
......@@ -559,7 +560,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
rc = devm_request_irq(dev, chip->vendor.irq,
i2c_nuvoton_int_handler,
IRQF_TRIGGER_LOW,
chip->vendor.miscdev.name,
chip->devname,
chip);
if (rc) {
dev_err(dev, "%s() Unable to request irq: %d for use\n",
......@@ -584,7 +585,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
TPM_DATA_FIFO_W,
1, (u8 *) (&rc));
if (rc < 0)
goto out_err;
return rc;
/* TPM_STS <- 0x40 (commandReady) */
i2c_nuvoton_ready(chip);
} else {
......@@ -594,45 +595,29 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
* only TPM_STS_VALID should be set
*/
if (i2c_nuvoton_read_status(chip) !=
TPM_STS_VALID) {
rc = -EIO;
goto out_err;
}
TPM_STS_VALID)
return -EIO;
}
}
}
if (tpm_get_timeouts(chip)) {
rc = -ENODEV;
goto out_err;
}
if (tpm_do_selftest(chip)) {
rc = -ENODEV;
goto out_err;
}
if (tpm_get_timeouts(chip))
return -ENODEV;
return 0;
if (tpm_do_selftest(chip))
return -ENODEV;
out_err:
tpm_dev_vendor_release(chip);
tpm_remove_hardware(chip->dev);
return rc;
return tpm_chip_register(chip);
}
static int i2c_nuvoton_remove(struct i2c_client *client)
{
struct device *dev = &(client->dev);
struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip)
tpm_dev_vendor_release(chip);
tpm_remove_hardware(dev);
kfree(chip);
tpm_chip_unregister(chip);
return 0;
}
static const struct i2c_device_id i2c_nuvoton_id[] = {
{I2C_DRIVER_NAME, 0},
{}
......
此差异已折叠。
/*
* Copyright (C) 2012 IBM Corporation
*
* Author: Ashley Lai <adlai@us.ibm.com>
* Author: Ashley Lai <ashleydlai@gmail.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
......@@ -270,8 +270,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
{
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
int rc = 0;
tpm_chip_unregister(chip);
free_irq(vdev->irq, ibmvtpm);
do {
......@@ -290,8 +293,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
kfree(ibmvtpm->rtce_buf);
}
tpm_remove_hardware(ibmvtpm->dev);
kfree(ibmvtpm);
return 0;
......@@ -307,6 +308,14 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
{
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
/* ibmvtpm initializes at probe time, so the data we are
* asking for may not be set yet. Estimate that 4K required
* for TCE-mapped buffer in addition to CRQ.
*/
if (!ibmvtpm)
return CRQ_RES_BUF_SIZE + PAGE_SIZE;
return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
}
......@@ -555,11 +564,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
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;
}
chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
if (IS_ERR(chip))
return PTR_ERR(chip);
ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
if (!ibmvtpm) {
......@@ -629,7 +636,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
if (rc)
goto init_irq_cleanup;
return rc;
return tpm_chip_register(chip);
init_irq_cleanup:
do {
rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
......@@ -644,8 +651,6 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
kfree(ibmvtpm);
}
tpm_remove_hardware(dev);
return rc;
}
......
/*
* Copyright (C) 2012 IBM Corporation
*
* Author: Ashley Lai <adlai@us.ibm.com>
* Author: Ashley Lai <ashleydlai@gmail.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
......
......@@ -195,9 +195,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
}
if (i == TPM_MAX_TRIES) { /* timeout occurs */
if (wait_for_bit == STAT_XFE)
dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n");
dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n");
if (wait_for_bit == STAT_RDA)
dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n");
dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n");
return -EIO;
}
return 0;
......@@ -220,7 +220,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
static void tpm_wtx(struct tpm_chip *chip)
{
number_of_wtx++;
dev_info(chip->dev, "Granting WTX (%02d / %02d)\n",
dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n",
number_of_wtx, TPM_MAX_WTX_PACKAGES);
wait_and_send(chip, TPM_VL_VER);
wait_and_send(chip, TPM_CTRL_WTX);
......@@ -231,7 +231,7 @@ static void tpm_wtx(struct tpm_chip *chip)
static void tpm_wtx_abort(struct tpm_chip *chip)
{
dev_info(chip->dev, "Aborting WTX\n");
dev_info(chip->pdev, "Aborting WTX\n");
wait_and_send(chip, TPM_VL_VER);
wait_and_send(chip, TPM_CTRL_WTX_ABORT);
wait_and_send(chip, 0x00);
......@@ -257,7 +257,7 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
}
if (buf[0] != TPM_VL_VER) {
dev_err(chip->dev,
dev_err(chip->pdev,
"Wrong transport protocol implementation!\n");
return -EIO;
}
......@@ -272,7 +272,7 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
}
if ((size == 0x6D00) && (buf[1] == 0x80)) {
dev_err(chip->dev, "Error handling on vendor layer!\n");
dev_err(chip->pdev, "Error handling on vendor layer!\n");
return -EIO;
}
......@@ -284,7 +284,7 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
}
if (buf[1] == TPM_CTRL_WTX) {
dev_info(chip->dev, "WTX-package received\n");
dev_info(chip->pdev, "WTX-package received\n");
if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
tpm_wtx(chip);
goto recv_begin;
......@@ -295,14 +295,14 @@ static int tpm_inf_recv(struct tpm_chip *chip, u8 * buf, size_t count)
}
if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
dev_info(chip->dev, "WTX-abort acknowledged\n");
dev_info(chip->pdev, "WTX-abort acknowledged\n");
return size;
}
if (buf[1] == TPM_CTRL_ERROR) {
dev_err(chip->dev, "ERROR-package received:\n");
dev_err(chip->pdev, "ERROR-package received:\n");
if (buf[4] == TPM_INF_NAK)
dev_err(chip->dev,
dev_err(chip->pdev,
"-> Negative acknowledgement"
" - retransmit command!\n");
return -EIO;
......@@ -321,7 +321,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
ret = empty_fifo(chip, 1);
if (ret) {
dev_err(chip->dev, "Timeout while clearing FIFO\n");
dev_err(chip->pdev, "Timeout while clearing FIFO\n");
return -EIO;
}
......@@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
vendorid[0], vendorid[1],
productid[0], productid[1], chipname);
if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
if (IS_ERR(chip)) {
rc = PTR_ERR(chip);
goto err_release_region;
}
rc = tpm_chip_register(chip);
if (rc)
goto err_release_region;
return 0;
......@@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
{
struct tpm_chip *chip = pnp_get_drvdata(dev);
if (chip) {
if (tpm_dev.iotype == TPM_INF_IO_PORT) {
release_region(tpm_dev.data_regs, tpm_dev.data_size);
release_region(tpm_dev.config_port,
tpm_dev.config_size);
} else {
iounmap(tpm_dev.mem_base);
release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
}
tpm_dev_vendor_release(chip);
tpm_remove_hardware(chip->dev);
tpm_chip_unregister(chip);
if (tpm_dev.iotype == TPM_INF_IO_PORT) {
release_region(tpm_dev.data_regs, tpm_dev.data_size);
release_region(tpm_dev.config_port,
tpm_dev.config_size);
} else {
iounmap(tpm_dev.mem_base);
release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
}
}
......
......@@ -113,7 +113,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
}
while (time_before(jiffies, stop));
dev_info(chip->dev, "wait for ready failed\n");
dev_info(chip->pdev, "wait for ready failed\n");
return -EBUSY;
}
......@@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
return -EIO;
if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
dev_err(chip->dev, "F0 timeout\n");
dev_err(chip->pdev, "F0 timeout\n");
return -EIO;
}
if ((data =
inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
dev_err(chip->dev, "not in normal mode (0x%x)\n",
dev_err(chip->pdev, "not in normal mode (0x%x)\n",
data);
return -EIO;
}
......@@ -143,7 +143,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
for (p = buffer; p < &buffer[count]; p++) {
if (wait_for_stat
(chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
dev_err(chip->dev,
dev_err(chip->pdev,
"OBF timeout (while reading data)\n");
return -EIO;
}
......@@ -154,11 +154,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
if ((data & NSC_STATUS_F0) == 0 &&
(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
dev_err(chip->dev, "F0 not set\n");
dev_err(chip->pdev, "F0 not set\n");
return -EIO;
}
if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
dev_err(chip->dev,
dev_err(chip->pdev,
"expected end of command(0x%x)\n", data);
return -EIO;
}
......@@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
return -EIO;
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
dev_err(chip->dev, "IBF timeout\n");
dev_err(chip->pdev, "IBF timeout\n");
return -EIO;
}
outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
dev_err(chip->dev, "IBR timeout\n");
dev_err(chip->pdev, "IBR timeout\n");
return -EIO;
}
for (i = 0; i < count; i++) {
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
dev_err(chip->dev,
dev_err(chip->pdev,
"IBF timeout (while writing data)\n");
return -EIO;
}
......@@ -209,7 +209,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
}
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
dev_err(chip->dev, "IBF timeout\n");
dev_err(chip->pdev, "IBF timeout\n");
return -EIO;
}
outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
......@@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
static void tpm_nsc_remove(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
if ( chip ) {
release_region(chip->vendor.base, 2);
tpm_remove_hardware(chip->dev);
}
tpm_chip_unregister(chip);
release_region(chip->vendor.base, 2);
}
static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
......@@ -307,11 +306,16 @@ static int __init init_nsc(void)
goto err_del_dev;
}
if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
if (IS_ERR(chip)) {
rc = -ENODEV;
goto err_rel_reg;
}
rc = tpm_chip_register(chip);
if (rc)
goto err_rel_reg;
dev_dbg(&pdev->dev, "NSC TPM detected\n");
dev_dbg(&pdev->dev,
"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
......
/*
* Copyright 2012 IBM Corporation
*
* Author: Ashley Lai <adlai@us.ibm.com>
* Author: Ashley Lai <ashleydlai@gmail.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
......
/*
* Copyright (C) 2012-2014 Intel Corporation
*
* Authors:
* Xiaoyan Zhang <xiaoyan.zhang@intel.com>
* Jiang Liu <jiang.liu@linux.intel.com>
* Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* This file contains implementation of the sysfs interface for PPI.
*
* 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/acpi.h>
#include "tpm.h"
......@@ -12,7 +31,6 @@
#define PPI_TPM_REQ_MAX 22
#define PPI_VS_REQ_START 128
#define PPI_VS_REQ_END 255
#define PPI_VERSION_LEN 3
static const u8 tpm_ppi_uuid[] = {
0xA6, 0xFA, 0xDD, 0x3D,
......@@ -22,45 +40,22 @@ static const u8 tpm_ppi_uuid[] = {
0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
};
static char tpm_ppi_version[PPI_VERSION_LEN + 1];
static acpi_handle tpm_ppi_handle;
static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
void **return_value)
{
union acpi_object *obj;
if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
1 << TPM_PPI_FN_VERSION))
return AE_OK;
/* Cache version string */
obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
NULL, ACPI_TYPE_STRING);
if (obj) {
strlcpy(tpm_ppi_version, obj->string.pointer,
PPI_VERSION_LEN + 1);
ACPI_FREE(obj);
}
*return_value = handle;
return AE_CTRL_TERMINATE;
}
static inline union acpi_object *
tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
union acpi_object *argv4)
{
BUG_ON(!tpm_ppi_handle);
return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID, func, argv4, type);
BUG_ON(!ppi_handle);
return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID,
func, argv4, type);
}
static ssize_t tpm_show_ppi_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);
struct tpm_chip *chip = dev_get_drvdata(dev);
return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
}
static ssize_t tpm_show_ppi_request(struct device *dev,
......@@ -68,8 +63,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
{
ssize_t size = -EINVAL;
union acpi_object *obj;
struct tpm_chip *chip = dev_get_drvdata(dev);
obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
ACPI_TYPE_PACKAGE, NULL);
if (!obj)
return -ENXIO;
......@@ -103,14 +100,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
int func = TPM_PPI_FN_SUBREQ;
union acpi_object *obj, tmp;
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
struct tpm_chip *chip = dev_get_drvdata(dev);
/*
* the function to submit TPM operation request to pre-os environment
* is updated with function index from SUBREQ to SUBREQ2 since PPI
* version 1.1
*/
if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
1 << TPM_PPI_FN_SUBREQ2))
if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
func = TPM_PPI_FN_SUBREQ2;
/*
......@@ -119,7 +117,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
* string/package type. For PPI version 1.0 and 1.1, use buffer type
* for compatibility, and use package type since 1.2 according to spec.
*/
if (strcmp(tpm_ppi_version, "1.2") < 0) {
if (strcmp(chip->ppi_version, "1.2") < 0) {
if (sscanf(buf, "%d", &req) != 1)
return -EINVAL;
argv4.type = ACPI_TYPE_BUFFER;
......@@ -131,7 +129,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
return -EINVAL;
}
obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
&argv4);
if (!obj) {
return -ENXIO;
} else {
......@@ -157,6 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
.buffer.length = 0,
.buffer.pointer = NULL
};
struct tpm_chip *chip = dev_get_drvdata(dev);
static char *info[] = {
"None",
......@@ -171,9 +171,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
* compatibility, define params[3].type as buffer, if PPI version < 1.2
*/
if (strcmp(tpm_ppi_version, "1.2") < 0)
if (strcmp(chip->ppi_version, "1.2") < 0)
obj = &tmp;
obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
ACPI_TYPE_INTEGER, obj);
if (!obj) {
return -ENXIO;
} else {
......@@ -196,8 +197,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
acpi_status status = -EINVAL;
union acpi_object *obj, *ret_obj;
u64 req, res;
struct tpm_chip *chip = dev_get_drvdata(dev);
obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
ACPI_TYPE_PACKAGE, NULL);
if (!obj)
return -ENXIO;
......@@ -248,7 +251,8 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
return status;
}
static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
u32 end)
{
int i;
u32 ret;
......@@ -264,14 +268,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
"User not required",
};
if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
1 << TPM_PPI_FN_GETOPR))
return -EPERM;
tmp.integer.type = ACPI_TYPE_INTEGER;
for (i = start; i <= end; i++) {
tmp.integer.value = i;
obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
ACPI_TYPE_INTEGER, &argv);
if (!obj) {
return -ENOMEM;
} else {
......@@ -291,14 +296,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX);
struct tpm_chip *chip = dev_get_drvdata(dev);
return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
PPI_TPM_REQ_MAX);
}
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END);
struct tpm_chip *chip = dev_get_drvdata(dev);
return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
PPI_VS_REQ_END);
}
static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
......@@ -323,16 +334,38 @@ static struct attribute_group ppi_attr_grp = {
.attrs = ppi_attrs
};
int tpm_add_ppi(struct kobject *parent)
int tpm_add_ppi(struct tpm_chip *chip)
{
/* Cache TPM ACPI handle and version string */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
ppi_callback, NULL, NULL, &tpm_ppi_handle);
return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0;
union acpi_object *obj;
int rc;
if (!chip->acpi_dev_handle)
return 0;
if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
return 0;
/* Cache PPI version string. */
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
NULL, ACPI_TYPE_STRING);
if (obj) {
strlcpy(chip->ppi_version, obj->string.pointer,
sizeof(chip->ppi_version));
ACPI_FREE(obj);
}
rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp);
if (!rc)
chip->flags |= TPM_CHIP_FLAG_PPI;
return rc;
}
void tpm_remove_ppi(struct kobject *parent)
void tpm_remove_ppi(struct tpm_chip *chip)
{
if (tpm_ppi_handle)
sysfs_remove_group(parent, &ppi_attr_grp);
if (chip->flags & TPM_CHIP_FLAG_PPI)
sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp);
}
/*
* Copyright (C) 2005, 2006 IBM Corporation
* Copyright (C) 2014 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
......@@ -64,19 +65,30 @@ enum tis_defaults {
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
};
/* Some timeout values are needed before it is known whether the chip is
* TPM 1.0 or TPM 2.0.
*/
#define TIS_TIMEOUT_A_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
#define TIS_TIMEOUT_B_MAX max(TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
#define TIS_TIMEOUT_C_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
#define TIS_TIMEOUT_D_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
#define TPM_STS(l) (0x0018 | ((l) << 12))
#define TPM_STS3(l) (0x001b | ((l) << 12))
#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
#define TPM_RID(l) (0x0F04 | ((l) << 12))
static LIST_HEAD(tis_chips);
static DEFINE_MUTEX(tis_lock);
struct priv_data {
bool irq_tested;
};
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
static int is_itpm(struct pnp_dev *dev)
......@@ -241,7 +253,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
/* read first 10 bytes, including tag, paramsize, and result */
if ((size =
recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
dev_err(chip->dev, "Unable to read header\n");
dev_err(chip->pdev, "Unable to read header\n");
goto out;
}
......@@ -254,7 +266,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
if ((size +=
recv_data(chip, &buf[TPM_HEADER_SIZE],
expected - TPM_HEADER_SIZE)) < expected) {
dev_err(chip->dev, "Unable to read remainder of result\n");
dev_err(chip->pdev, "Unable to read remainder of result\n");
size = -ETIME;
goto out;
}
......@@ -263,7 +275,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
dev_err(chip->dev, "Error left over data\n");
dev_err(chip->pdev, "Error left over data\n");
size = -EIO;
goto out;
}
......@@ -338,15 +350,31 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
return rc;
}
static void disable_interrupts(struct tpm_chip *chip)
{
u32 intmask;
intmask =
ioread32(chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
intmask &= ~TPM_GLOBAL_INT_ENABLE;
iowrite32(intmask,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
free_irq(chip->vendor.irq, chip);
chip->vendor.irq = 0;
}
/*
* If interrupts are used (signaled by an irq set in the vendor structure)
* tpm.c can skip polling for the data to be available as the interrupt is
* waited for here
*/
static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
{
int rc;
u32 ordinal;
unsigned long dur;
rc = tpm_tis_send_data(chip, buf, len);
if (rc < 0)
......@@ -358,9 +386,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (chip->vendor.irq) {
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
if (chip->flags & TPM_CHIP_FLAG_TPM2)
dur = tpm2_calc_ordinal_duration(chip, ordinal);
else
dur = tpm_calc_ordinal_duration(chip, ordinal);
if (wait_for_tpm_stat
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
tpm_calc_ordinal_duration(chip, ordinal),
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
&chip->vendor.read_queue, false) < 0) {
rc = -ETIME;
goto out_err;
......@@ -373,6 +406,30 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
return rc;
}
static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
int rc, irq;
struct priv_data *priv = chip->vendor.priv;
if (!chip->vendor.irq || priv->irq_tested)
return tpm_tis_send_main(chip, buf, len);
/* Verify receipt of the expected IRQ */
irq = chip->vendor.irq;
chip->vendor.irq = 0;
rc = tpm_tis_send_main(chip, buf, len);
chip->vendor.irq = irq;
if (!priv->irq_tested)
msleep(1);
if (!priv->irq_tested) {
disable_interrupts(chip);
dev_err(chip->pdev,
FW_BUG "TPM interrupt not working, polling instead\n");
}
priv->irq_tested = true;
return rc;
}
struct tis_vendor_timeout_override {
u32 did_vid;
unsigned long timeout_us[4];
......@@ -436,7 +493,7 @@ static int probe_itpm(struct tpm_chip *chip)
rc = tpm_tis_send_data(chip, cmd_getticks, len);
if (rc == 0) {
dev_info(chip->dev, "Detected an iTPM.\n");
dev_info(chip->pdev, "Detected an iTPM.\n");
rc = 1;
} else
rc = -EFAULT;
......@@ -505,6 +562,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
if (interrupt == 0)
return IRQ_NONE;
((struct priv_data *)chip->vendor.priv)->irq_tested = true;
if (interrupt & TPM_INTF_DATA_AVAIL_INT)
wake_up_interruptible(&chip->vendor.read_queue);
if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
......@@ -528,27 +586,48 @@ static bool interrupts = true;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
static int tpm_tis_init(struct device *dev, resource_size_t start,
resource_size_t len, unsigned int irq)
static void tpm_tis_remove(struct tpm_chip *chip)
{
iowrite32(~TPM_GLOBAL_INT_ENABLE &
ioread32(chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.
locality)),
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
release_locality(chip, chip->vendor.locality, 1);
}
static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
resource_size_t start, resource_size_t len,
unsigned int irq)
{
u32 vendor, intfcaps, intmask;
int rc, i, irq_s, irq_e, probe;
struct tpm_chip *chip;
struct priv_data *priv;
if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
chip->vendor.iobase = ioremap(start, len);
if (!chip->vendor.iobase) {
rc = -EIO;
goto out_err;
}
chip = tpmm_chip_alloc(dev, &tpm_tis);
if (IS_ERR(chip))
return PTR_ERR(chip);
chip->vendor.priv = priv;
#ifdef CONFIG_ACPI
chip->acpi_dev_handle = acpi_dev_handle;
#endif
chip->vendor.iobase = devm_ioremap(dev, start, len);
if (!chip->vendor.iobase)
return -EIO;
/* Default timeouts */
chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
/* Maximum timeouts */
chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX;
chip->vendor.timeout_b = TIS_TIMEOUT_B_MAX;
chip->vendor.timeout_c = TIS_TIMEOUT_C_MAX;
chip->vendor.timeout_d = TIS_TIMEOUT_D_MAX;
if (wait_startup(chip, 0) != 0) {
rc = -ENODEV;
......@@ -560,11 +639,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
goto out_err;
}
/* Every TPM 2.x command has a higher ordinal than TPM 1.x commands.
* Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x.
*/
rc = tpm2_gen_interrupt(chip, true);
if (rc == 0 || rc == TPM2_RC_INITIALIZE)
chip->flags |= TPM_CHIP_FLAG_TPM2;
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
chip->vendor.manufacturer_id = vendor;
dev_info(dev,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
(chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
if (!itpm) {
......@@ -605,19 +691,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
dev_dbg(dev, "\tData Avail Int Support\n");
/* get the timeouts before testing for irqs */
if (tpm_get_timeouts(chip)) {
dev_err(dev, "Could not get TPM timeouts and durations\n");
rc = -ENODEV;
goto out_err;
}
if (tpm_do_selftest(chip)) {
dev_err(dev, "TPM self test failed\n");
rc = -ENODEV;
goto out_err;
}
/* INTERRUPT Setup */
init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue);
......@@ -649,10 +722,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
iowrite8(i, chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
if (request_irq
(i, tis_int_probe, IRQF_SHARED,
chip->vendor.miscdev.name, chip) != 0) {
dev_info(chip->dev,
if (devm_request_irq
(dev, i, tis_int_probe, IRQF_SHARED,
chip->devname, chip) != 0) {
dev_info(chip->pdev,
"Unable to request irq: %d for probe\n",
i);
continue;
......@@ -673,7 +746,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
chip->vendor.probed_irq = 0;
/* Generate Interrupts */
tpm_gen_interrupt(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_gen_interrupt(chip, false);
else
tpm_gen_interrupt(chip);
chip->vendor.irq = chip->vendor.probed_irq;
......@@ -690,17 +766,16 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
iowrite32(intmask,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
free_irq(i, chip);
}
}
if (chip->vendor.irq) {
iowrite8(chip->vendor.irq,
chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
if (request_irq
(chip->vendor.irq, tis_int_handler, IRQF_SHARED,
chip->vendor.miscdev.name, chip) != 0) {
dev_info(chip->dev,
if (devm_request_irq
(dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
chip->devname, chip) != 0) {
dev_info(chip->pdev,
"Unable to request irq: %d for use\n",
chip->vendor.irq);
chip->vendor.irq = 0;
......@@ -719,17 +794,49 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
}
}
INIT_LIST_HEAD(&chip->vendor.list);
mutex_lock(&tis_lock);
list_add(&chip->vendor.list, &tis_chips);
mutex_unlock(&tis_lock);
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
chip->vendor.duration[TPM_SHORT] =
msecs_to_jiffies(TPM2_DURATION_SHORT);
chip->vendor.duration[TPM_MEDIUM] =
msecs_to_jiffies(TPM2_DURATION_MEDIUM);
chip->vendor.duration[TPM_LONG] =
msecs_to_jiffies(TPM2_DURATION_LONG);
rc = tpm2_do_selftest(chip);
if (rc == TPM2_RC_INITIALIZE) {
dev_warn(dev, "Firmware has not started TPM\n");
rc = tpm2_startup(chip, TPM2_SU_CLEAR);
if (!rc)
rc = tpm2_do_selftest(chip);
}
if (rc) {
dev_err(dev, "TPM self test failed\n");
if (rc > 0)
rc = -ENODEV;
goto out_err;
}
} else {
if (tpm_get_timeouts(chip)) {
dev_err(dev, "Could not get TPM timeouts and durations\n");
rc = -ENODEV;
goto out_err;
}
return 0;
if (tpm_do_selftest(chip)) {
dev_err(dev, "TPM self test failed\n");
rc = -ENODEV;
goto out_err;
}
}
return tpm_chip_register(chip);
out_err:
if (chip->vendor.iobase)
iounmap(chip->vendor.iobase);
tpm_remove_hardware(chip->dev);
tpm_tis_remove(chip);
return rc;
}
......@@ -758,14 +865,23 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
static int tpm_tis_resume(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
int ret;
int ret = 0;
if (chip->vendor.irq)
tpm_tis_reenable_interrupts(chip);
ret = tpm_pm_resume(dev);
if (!ret)
tpm_do_selftest(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
/* NOP if firmware properly does this. */
tpm2_startup(chip, TPM2_SU_STATE);
ret = tpm2_shutdown(chip, TPM2_SU_STATE);
if (!ret)
ret = tpm2_do_selftest(chip);
} else {
ret = tpm_pm_resume(dev);
if (!ret)
tpm_do_selftest(chip);
}
return ret;
}
......@@ -779,6 +895,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
{
resource_size_t start, len;
unsigned int irq = 0;
acpi_handle acpi_dev_handle = NULL;
start = pnp_mem_start(pnp_dev, 0);
len = pnp_mem_len(pnp_dev, 0);
......@@ -791,7 +908,12 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
if (is_itpm(pnp_dev))
itpm = true;
return tpm_tis_init(&pnp_dev->dev, start, len, irq);
#ifdef CONFIG_ACPI
if (pnp_acpi_device(pnp_dev))
acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
#endif
return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq);
}
static struct pnp_device_id tpm_pnp_tbl[] = {
......@@ -811,13 +933,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
static void tpm_tis_pnp_remove(struct pnp_dev *dev)
{
struct tpm_chip *chip = pnp_get_drvdata(dev);
tpm_dev_vendor_release(chip);
kfree(chip);
tpm_chip_unregister(chip);
tpm_tis_remove(chip);
}
static struct pnp_driver tis_pnp_driver = {
.name = "tpm_tis",
.id_table = tpm_pnp_tbl,
......@@ -836,7 +955,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
static struct platform_driver tis_drv = {
.driver = {
.name = "tpm_tis",
.name = "tpm_tis",
.pm = &tpm_tis_pm,
},
};
......@@ -862,7 +981,7 @@ static int __init init_tis(void)
rc = PTR_ERR(pdev);
goto err_dev;
}
rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0);
rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0);
if (rc)
goto err_init;
return 0;
......@@ -875,31 +994,16 @@ static int __init init_tis(void)
static void __exit cleanup_tis(void)
{
struct tpm_vendor_specific *i, *j;
struct tpm_chip *chip;
mutex_lock(&tis_lock);
list_for_each_entry_safe(i, j, &tis_chips, list) {
chip = to_tpm_chip(i);
tpm_remove_hardware(chip->dev);
iowrite32(~TPM_GLOBAL_INT_ENABLE &
ioread32(chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.
locality)),
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
release_locality(chip, chip->vendor.locality, 1);
if (chip->vendor.irq)
free_irq(chip->vendor.irq, chip);
iounmap(i->iobase);
list_del(&i->list);
}
mutex_unlock(&tis_lock);
#ifdef CONFIG_PNP
if (!force) {
pnp_unregister_driver(&tis_pnp_driver);
return;
}
#endif
chip = dev_get_drvdata(&pdev->dev);
tpm_chip_unregister(chip);
tpm_tis_remove(chip);
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
}
......
......@@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv)
{
struct tpm_chip *chip;
chip = tpm_register_hardware(dev, &tpm_vtpm);
if (!chip)
return -ENODEV;
chip = tpmm_chip_alloc(dev, &tpm_vtpm);
if (IS_ERR(chip))
return PTR_ERR(chip);
init_waitqueue_head(&chip->vendor.read_queue);
......@@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
{
struct tpm_private *priv;
struct tpm_chip *chip;
int rv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
......@@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
rv = setup_ring(dev, priv);
if (rv) {
tpm_remove_hardware(&dev->dev);
chip = dev_get_drvdata(&dev->dev);
tpm_chip_unregister(chip);
ring_free(priv);
return rv;
}
tpm_get_timeouts(priv->chip);
return rv;
return tpm_chip_register(priv->chip);
}
static int tpmfront_remove(struct xenbus_device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
struct tpm_private *priv = TPM_VPRIV(chip);
tpm_remove_hardware(&dev->dev);
tpm_chip_unregister(chip);
ring_free(priv);
TPM_VPRIV(chip) = NULL;
return 0;
......
......@@ -12,9 +12,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* STMicroelectronics version 1.2.0, Copyright (C) 2010
* STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
......@@ -23,39 +22,18 @@
*
* @Author: Christophe RICARD tpmsupport@st.com
*
* @File: stm_st33_tpm_i2c.h
* @File: stm_st33_tpm.h
*
* @Date: 09/15/2010
*/
#ifndef __STM_ST33_TPM_I2C_MAIN_H__
#define __STM_ST33_TPM_I2C_MAIN_H__
#ifndef __STM_ST33_TPM_H__
#define __STM_ST33_TPM_H__
#define TPM_ACCESS (0x0)
#define TPM_STS (0x18)
#define TPM_HASH_END (0x20)
#define TPM_DATA_FIFO (0x24)
#define TPM_HASH_DATA (0x24)
#define TPM_HASH_START (0x28)
#define TPM_INTF_CAPABILITY (0x14)
#define TPM_INT_STATUS (0x10)
#define TPM_INT_ENABLE (0x08)
#define TPM_DUMMY_BYTE 0xAA
#define TPM_WRITE_DIRECTION 0x80
#define TPM_HEADER_SIZE 10
#define TPM_BUFSIZE 2048
#define LOCALITY0 0
#define TPM_ST33_I2C "st33zp24_i2c"
#define TPM_ST33_I2C "st33zp24-i2c"
#define TPM_ST33_SPI "st33zp24-spi"
struct st33zp24_platform_data {
int io_serirq;
int io_lpcpd;
struct i2c_client *client;
u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
struct completion irq_detection;
struct mutex lock;
};
#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
#endif /* __STM_ST33_TPM_H__ */
......@@ -120,13 +120,6 @@ extern int cipso_v4_rbm_optfmt;
extern int cipso_v4_rbm_strictvalid;
#endif
/*
* Helper Functions
*/
#define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0)
#define CIPSO_V4_OPTPTR(x) (skb_network_header(x) + IPCB(x)->opt.cipso)
/*
* DOI List Functions
*/
......@@ -190,7 +183,7 @@ static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
#ifdef CONFIG_NETLABEL
void cipso_v4_cache_invalidate(void);
int cipso_v4_cache_add(const struct sk_buff *skb,
int cipso_v4_cache_add(const unsigned char *cipso_ptr,
const struct netlbl_lsm_secattr *secattr);
#else
static inline void cipso_v4_cache_invalidate(void)
......@@ -198,7 +191,7 @@ static inline void cipso_v4_cache_invalidate(void)
return;
}
static inline int cipso_v4_cache_add(const struct sk_buff *skb,
static inline int cipso_v4_cache_add(const unsigned char *cipso_ptr,
const struct netlbl_lsm_secattr *secattr)
{
return 0;
......@@ -211,6 +204,8 @@ static inline int cipso_v4_cache_add(const struct sk_buff *skb,
#ifdef CONFIG_NETLABEL
void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
int cipso_v4_getattr(const unsigned char *cipso,
struct netlbl_lsm_secattr *secattr);
int cipso_v4_sock_setattr(struct sock *sk,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr);
......@@ -226,6 +221,7 @@ int cipso_v4_skbuff_setattr(struct sk_buff *skb,
int cipso_v4_skbuff_delattr(struct sk_buff *skb);
int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
struct netlbl_lsm_secattr *secattr);
unsigned char *cipso_v4_optptr(const struct sk_buff *skb);
int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
#else
static inline void cipso_v4_error(struct sk_buff *skb,
......@@ -235,6 +231,12 @@ static inline void cipso_v4_error(struct sk_buff *skb,
return;
}
static inline int cipso_v4_getattr(const unsigned char *cipso,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline int cipso_v4_sock_setattr(struct sock *sk,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr)
......@@ -282,6 +284,11 @@ static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
return -ENOSYS;
}
static inline unsigned char *cipso_v4_optptr(const struct sk_buff *skb)
{
return NULL;
}
static inline int cipso_v4_validate(const struct sk_buff *skb,
unsigned char **option)
{
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -126,7 +126,6 @@ config IMA_TRUSTED_KEYRING
bool "Require all keys on the .ima keyring be signed"
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
select KEYS_DEBUG_PROC_KEYS
default y
help
This option requires that all keys added to the .ima
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册