// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2005, 2006 IBM Corporation
* Copyright (C) 2014, 2015 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*
* This device driver implements the TPM interface as defined in
* the TCG TPM Interface Spec version 1.2, revision 1.0.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pnp.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/acpi.h>
#include <linux/freezer.h>
#include <linux/dmi.h>
#include "tpm.h"
#include "tpm_tis_core.h"
#define TPM_TIS_MAX_UNHANDLED_IRQS 1000
static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value);
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
bool check_cancel, bool *canceled)
{
u8 status = chip->ops->status(chip);
*canceled = false;
if ((status & mask) == mask)
return true;
if (check_cancel && chip->ops->req_canceled(chip, status)) {
*canceled = true;
return true;
}
return false;
}
static u8 tpm_tis_filter_sts_mask(u8 int_mask, u8 sts_mask)
{
if (!(int_mask & TPM_INTF_STS_VALID_INT))
sts_mask &= ~TPM_STS_VALID;
if (!(int_mask & TPM_INTF_DATA_AVAIL_INT))
sts_mask &= ~TPM_STS_DATA_AVAIL;
if (!(int_mask & TPM_INTF_CMD_READY_INT))
sts_mask &= ~TPM_STS_COMMAND_READY;
return sts_mask;
}
static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
unsigned long timeout, wait_queue_head_t *queue,
bool check_cancel)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
unsigned long stop;
long rc;
u8 status;
bool canceled = false;
u8 sts_mask;
int ret = 0;
/* check current status */
status = chip->ops->status(chip);
if ((status & mask) == mask)
return 0;
sts_mask = mask & (TPM_STS_VALID | TPM_STS_DATA_AVAIL |
TPM_STS_COMMAND_READY);
/* check what status changes can be handled by irqs */
sts_mask = tpm_tis_filter_sts_mask(priv->int_mask, sts_mask)