lkml.org 
[lkml]   [2012]   [Jan]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: [Sony Vaio TX3] TPM chip prevents machine from suspending a second time
    On 01/29/2012 05:49 AM, John Hughes wrote:
    > On 23/01/12 21:52, Stefan Berger wrote:
    >>
    >> Can you apply the patch below to your tpm_tis.c (or somewhere else in
    >> the kernel) and let me/us know what it reports in 'dmesg' upon a
    >> 'modprobe tpm_tis'?
    >
    > [ 48.826151] tpm_tis 00:07: dmi: 0: (null)
    > [ 48.826157] tpm_tis 00:07: dmi: 1: Phoenix Technologies LTD
    > [ 48.826161] tpm_tis 00:07: dmi: 2: R0021N3
    > [ 48.826165] tpm_tis 00:07: dmi: 3: 05/09/2006
    > [ 48.826169] tpm_tis 00:07: dmi: 4: Sony Corporation
    > [ 48.826173] tpm_tis 00:07: dmi: 5: VGN-TX3XP_B
    > [ 48.826177] tpm_tis 00:07: dmi: 6: J001QHZL
    > [ 48.826181] tpm_tis 00:07: dmi: 7: 28244651-5000176
    > [ 48.826186] tpm_tis 00:07: dmi: 8:
    > DC744BA0-5B3C-11D9-8822-0013A93CCD4D
    > [ 48.826190] tpm_tis 00:07: dmi: 9: Sony Corporation
    > [ 48.826195] tpm_tis 00:07: dmi: 10: VAIO
    > [ 48.826199] tpm_tis 00:07: dmi: 11: N/A
    > [ 48.826204] tpm_tis 00:07: dmi: 12: N/A
    > [ 48.826208] tpm_tis 00:07: dmi: 13: N/A
    > [ 48.826213] tpm_tis 00:07: dmi: 14: Sony Corporation
    > [ 48.826217] tpm_tis 00:07: dmi: 15: 10
    > [ 48.826221] tpm_tis 00:07: dmi: 16: N/A
    > [ 48.826225] tpm_tis 00:07: dmi: 17: J001QHZL
    > [ 48.826229] tpm_tis 00:07: dmi: 18:
    > [ 48.826235] tpm_tis 00:07: 1.2 TPM (device-id 0xB, rev-id 16)
    >
    Thanks. Please try the attached patch.

    I am not sure whether this is the right way to go, though: Is it a
    problem particular to this BIOS + Board or a general problem of this
    BIOS? Is it specific to the TX3 or to all VAIOs?

    Stefan



    Add a TPM resume quirk for machines where the BIOS doesn't send the
    TPM_Startup(ST_STATE) to the TPM and subsequent suspends fail due
    to this. Identify machines by their SMBIOS data and only apply the quirk
    on those known to need it.

    Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

    ---
    drivers/char/tpm/tpm.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++
    drivers/char/tpm/tpm.h | 8 ++
    2 files changed, 161 insertions(+)

    Index: linux-2.6/drivers/char/tpm/tpm.c
    ===================================================================
    --- linux-2.6.orig/drivers/char/tpm/tpm.c
    +++ linux-2.6/drivers/char/tpm/tpm.c
    @@ -28,6 +28,7 @@
    #include <linux/mutex.h>
    #include <linux/spinlock.h>
    #include <linux/freezer.h>
    +#include <linux/dmi.h>

    #include "tpm.h"

    @@ -62,6 +63,131 @@ static LIST_HEAD(tpm_chip_list);
    static DEFINE_SPINLOCK(driver_lock);
    static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);

    +/***** tpm quirks *****/
    +
    +#ifdef CONFIG_DMI
    +
    +struct tpm_dmi_entry {
    + enum dmi_field id;
    + const char **value;
    +};
    +
    +struct tpm_resume_quirks {
    + const char *quirk_name;
    + const struct tpm_dmi_entry *dmi_entry;
    +};
    +
    +#define TPM_DMI_ENTRY_LAST \
    + { .id = DMI_NONE, .value = (const char*[]) { NULL }, }
    +
    +static const struct tpm_resume_quirks tpm_resume_quirks[] = {
    + {
    + .quirk_name = "Sony Vaio TX3",
    + .dmi_entry = (struct tpm_dmi_entry[]) {
    + {
    + .id = DMI_BIOS_VENDOR,
    + .value = (const char*[]) {
    + "Phoenix Technologies LTD",
    + NULL,
    + },
    + },
    + {
    + .id = DMI_SYS_VENDOR,
    + .value = (const char*[]) {
    + "Sony Corporation",
    + NULL,
    + },
    + },
    + {
    + .id = DMI_PRODUCT_NAME,
    + .value = (const char*[]) {
    + "VGN-TX3XP_B",
    + NULL,
    + },
    + },
    + {
    + .id = DMI_BOARD_NAME,
    + .value = (const char*[]) {
    + "VAIO",
    + NULL,
    + },
    + },
    + TPM_DMI_ENTRY_LAST
    + }
    + }
    +};
    +
    +bool find_str_in_array(const char **array, const char *val)
    +{
    + int i = 0;
    +
    + while (array[i]) {
    + if (!strcmp(array[i++], val))
    + return true;
    + }
    +
    + return false;
    +}
    +
    +static bool tpm_resume_quirk_dmi(struct tpm_chip *chip)
    +{
    + int i, j, rc;
    + bool found = false, handled = false;
    + const char *val;
    + const struct tpm_dmi_entry *dmi_entry;
    +
    + for (i = 0; i < ARRAY_SIZE(tpm_resume_quirks) && !handled; i++) {
    + j = 0;
    + found = true;
    +
    + while (true) {
    + dmi_entry = &tpm_resume_quirks[i].dmi_entry[j];
    +
    + if (dmi_entry->id == DMI_NONE)
    + break;
    +
    + val = dmi_get_system_info(dmi_entry->id);
    + if (!val) {
    + found = false;
    + break;
    + }
    +
    + found = find_str_in_array(dmi_entry->value, val);
    + if (!found)
    + break;
    + j++;
    + }
    +
    + if (found) {
    + dev_info(chip->dev,
    + "Using tpm resume quirk '%s'.\n",
    + tpm_resume_quirks[i].quirk_name);
    + rc = tpm_startup_ststate(chip);
    + if (rc < 0)
    + dev_err(chip->dev,
    + "quirk: TPM startup(ST_STATE) "
    + "failed.\n");
    + handled = true;
    + break;
    + }
    + }
    + return handled;
    +}
    +
    +#else
    +
    +static bool tpm_resume_quirk_dmi(struct tpm_chip *tpm_chip)
    +{
    + return false;
    +}
    +
    +#endif
    +
    +static void tpm_resume_quirk(struct tpm_chip *tpm_chip)
    +{
    + tpm_resume_quirk_dmi(tpm_chip);
    +}
    +
    /*
    * Array with one entry per ordinal defining the maximum amount
    * of time the chip could take to return the result. The ordinal
    @@ -864,6 +990,31 @@ int tpm_do_selftest(struct tpm_chip *chi
    }
    EXPORT_SYMBOL_GPL(tpm_do_selftest);

    +/**
    + * tpm_startup_ststate - send a ststartup to the TPM
    + */
    +#define TPM_ORD_STARTUP 153
    +#define STARTUP_RESULT_SIZE 10
    +
    +static struct tpm_input_header startup_ststate_header = {
    + .tag = TPM_TAG_RQU_COMMAND,
    + .length = cpu_to_be32(10),
    + .ordinal = cpu_to_be32(TPM_ORD_STARTUP),
    +};
    +
    +int tpm_startup_ststate(struct tpm_chip *chip)
    +{
    + int rc;
    + struct tpm_cmd_t cmd;
    +
    + cmd.header.in = startup_ststate_header;
    + cmd.params.startup_in.state = cpu_to_be16(TPM_ST_STATE);
    + rc = transmit_cmd(chip, &cmd, STARTUP_RESULT_SIZE,
    + "startup(st_state)");
    + return rc;
    +}
    +EXPORT_SYMBOL_GPL(tpm_startup_ststate);
    +
    int tpm_send(u32 chip_num, void *cmd, size_t buflen)
    {
    struct tpm_chip *chip;
    @@ -1313,6 +1464,8 @@ int tpm_pm_resume(struct device *dev)
    if (chip == NULL)
    return -ENODEV;

    + tpm_resume_quirk(chip);
    +
    return 0;
    }
    EXPORT_SYMBOL_GPL(tpm_pm_resume);
    Index: linux-2.6/drivers/char/tpm/tpm.h
    ===================================================================
    --- linux-2.6.orig/drivers/char/tpm/tpm.h
    +++ linux-2.6/drivers/char/tpm/tpm.h
    @@ -42,6 +42,8 @@ enum tpm_addr {
    #define TPM_ERR_DEACTIVATED 0x6
    #define TPM_ERR_DISABLED 0x7

    +#define TPM_ST_STATE 0x2
    +
    #define TPM_HEADER_SIZE 10
    extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
    char *);
    @@ -269,6 +271,10 @@ struct tpm_pcrextend_in {
    u8 hash[TPM_DIGEST_SIZE];
    }__attribute__((packed));

    +struct tpm_startup_in {
    + __be16 state;
    +} __packed;
    +
    typedef union {
    struct tpm_getcap_params_out getcap_out;
    struct tpm_readpubek_params_out readpubek_out;
    @@ -277,6 +283,7 @@ typedef union {
    struct tpm_pcrread_in pcrread_in;
    struct tpm_pcrread_out pcrread_out;
    struct tpm_pcrextend_in pcrextend_in;
    + struct tpm_startup_in startup_in;
    } tpm_cmd_params;

    struct tpm_cmd_t {
    @@ -289,6 +296,7 @@ ssize_t tpm_getcap(struct device *, __be
    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 int tpm_startup_ststate(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_vendor_specific *);
    \
     
     \ /
      Last update: 2012-01-29 19:25    [W:0.041 / U:91.648 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site