2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-12-12 22:46:34 +03:00
/*
* 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 .
*/
# include <linux/poll.h>
# include <linux/slab.h>
# include <linux/mutex.h>
# include <linux/spinlock.h>
# include <linux/freezer.h>
2014-12-12 22:46:37 +03:00
# include <linux/major.h>
2017-09-20 11:13:36 +03:00
# include <linux/tpm_eventlog.h>
2017-11-17 16:24:03 +03:00
# include <linux/hw_random.h>
2014-12-12 22:46:34 +03:00
# include "tpm.h"
2016-02-29 16:53:02 +03:00
DEFINE_IDR ( dev_nums_idr ) ;
static DEFINE_MUTEX ( idr_lock ) ;
2014-12-12 22:46:34 +03:00
2014-12-12 22:46:37 +03:00
struct class * tpm_class ;
2017-01-03 20:07:32 +03:00
struct class * tpmrm_class ;
2014-12-12 22:46:37 +03:00
dev_t tpm_devt ;
2018-11-05 04:02:38 +03:00
static int tpm_request_locality ( struct tpm_chip * chip )
2018-11-04 22:18:46 +03:00
{
int rc ;
if ( ! chip - > ops - > request_locality )
return 0 ;
rc = chip - > ops - > request_locality ( chip , 0 ) ;
if ( rc < 0 )
return rc ;
chip - > locality = rc ;
return 0 ;
}
2018-11-05 04:02:38 +03:00
static void tpm_relinquish_locality ( struct tpm_chip * chip )
2018-11-04 22:18:46 +03:00
{
int rc ;
if ( ! chip - > ops - > relinquish_locality )
return ;
rc = chip - > ops - > relinquish_locality ( chip , chip - > locality ) ;
if ( rc )
dev_err ( & chip - > dev , " %s: : error %d \n " , __func__ , rc ) ;
chip - > locality = - 1 ;
}
2018-11-05 04:02:38 +03:00
static int tpm_cmd_ready ( struct tpm_chip * chip )
2018-11-04 22:18:46 +03:00
{
if ( ! chip - > ops - > cmd_ready )
return 0 ;
return chip - > ops - > cmd_ready ( chip ) ;
}
2018-11-05 04:02:38 +03:00
static int tpm_go_idle ( struct tpm_chip * chip )
2018-11-04 22:18:46 +03:00
{
if ( ! chip - > ops - > go_idle )
return 0 ;
return chip - > ops - > go_idle ( chip ) ;
}
2019-07-04 10:26:15 +03:00
static void tpm_clk_enable ( struct tpm_chip * chip )
{
if ( chip - > ops - > clk_enable )
chip - > ops - > clk_enable ( chip , true ) ;
}
static void tpm_clk_disable ( struct tpm_chip * chip )
{
if ( chip - > ops - > clk_enable )
chip - > ops - > clk_enable ( chip , false ) ;
}
2018-11-04 22:18:46 +03:00
/**
* tpm_chip_start ( ) - power on the TPM
* @ chip : a TPM chip to use
*
* Return :
* * The response length - OK
* * - errno - A system error
*/
2018-11-05 04:02:38 +03:00
int tpm_chip_start ( struct tpm_chip * chip )
2018-11-04 22:18:46 +03:00
{
int ret ;
2019-07-04 10:26:15 +03:00
tpm_clk_enable ( chip ) ;
2018-11-04 22:18:46 +03:00
if ( chip - > locality = = - 1 ) {
2018-11-05 04:02:38 +03:00
ret = tpm_request_locality ( chip ) ;
2018-11-04 22:18:46 +03:00
if ( ret ) {
2019-07-04 10:26:15 +03:00
tpm_clk_disable ( chip ) ;
2018-11-04 22:18:46 +03:00
return ret ;
}
}
2018-11-05 04:02:38 +03:00
ret = tpm_cmd_ready ( chip ) ;
2018-11-04 22:18:46 +03:00
if ( ret ) {
2018-11-05 04:02:38 +03:00
tpm_relinquish_locality ( chip ) ;
2019-07-04 10:26:15 +03:00
tpm_clk_disable ( chip ) ;
2018-11-04 22:18:46 +03:00
return ret ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( tpm_chip_start ) ;
/**
* tpm_chip_stop ( ) - power off the TPM
* @ chip : a TPM chip to use
*
* Return :
* * The response length - OK
* * - errno - A system error
*/
2018-11-05 04:02:38 +03:00
void tpm_chip_stop ( struct tpm_chip * chip )
2018-11-04 22:18:46 +03:00
{
2018-11-05 04:02:38 +03:00
tpm_go_idle ( chip ) ;
tpm_relinquish_locality ( chip ) ;
2019-07-04 10:26:15 +03:00
tpm_clk_disable ( chip ) ;
2018-11-04 22:18:46 +03:00
}
EXPORT_SYMBOL_GPL ( tpm_chip_stop ) ;
2016-02-13 06:29:53 +03:00
/**
* tpm_try_get_ops ( ) - Get a ref to the tpm_chip
* @ chip : Chip to ref
*
* The caller must already have some kind of locking to ensure that chip is
* valid . This function will lock the chip so that the ops member can be
* accessed safely . The locking prevents tpm_chip_unregister from
* completing , so it should not be held for long periods .
*
* Returns - ERRNO if the chip could not be got .
2014-12-12 22:46:34 +03:00
*/
2016-02-13 06:29:53 +03:00
int tpm_try_get_ops ( struct tpm_chip * chip )
{
int rc = - EIO ;
get_device ( & chip - > dev ) ;
down_read ( & chip - > ops_sem ) ;
if ( ! chip - > ops )
2018-11-05 03:07:56 +03:00
goto out_ops ;
2016-02-13 06:29:53 +03:00
2018-11-04 21:01:42 +03:00
mutex_lock ( & chip - > tpm_mutex ) ;
2018-11-05 04:02:38 +03:00
rc = tpm_chip_start ( chip ) ;
2018-11-05 03:07:56 +03:00
if ( rc )
goto out_lock ;
2016-02-13 06:29:53 +03:00
return 0 ;
out_lock :
2018-11-05 03:07:56 +03:00
mutex_unlock ( & chip - > tpm_mutex ) ;
out_ops :
2016-02-13 06:29:53 +03:00
up_read ( & chip - > ops_sem ) ;
put_device ( & chip - > dev ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( tpm_try_get_ops ) ;
/**
* tpm_put_ops ( ) - Release a ref to the tpm_chip
* @ chip : Chip to put
*
* This is the opposite pair to tpm_try_get_ops ( ) . After this returns chip may
* be kfree ' d .
*/
void tpm_put_ops ( struct tpm_chip * chip )
{
2018-11-05 04:02:38 +03:00
tpm_chip_stop ( chip ) ;
2018-11-04 21:01:42 +03:00
mutex_unlock ( & chip - > tpm_mutex ) ;
2016-02-13 06:29:53 +03:00
up_read ( & chip - > ops_sem ) ;
put_device ( & chip - > dev ) ;
}
EXPORT_SYMBOL_GPL ( tpm_put_ops ) ;
2018-06-26 22:09:30 +03:00
/**
* tpm_default_chip ( ) - find a TPM chip and get a reference to it
*/
struct tpm_chip * tpm_default_chip ( void )
{
struct tpm_chip * chip , * res = NULL ;
int chip_num = 0 ;
int chip_prev ;
mutex_lock ( & idr_lock ) ;
do {
chip_prev = chip_num ;
chip = idr_get_next ( & dev_nums_idr , & chip_num ) ;
if ( chip ) {
get_device ( & chip - > dev ) ;
res = chip ;
break ;
}
} while ( chip_prev ! = chip_num ) ;
mutex_unlock ( & idr_lock ) ;
return res ;
}
EXPORT_SYMBOL_GPL ( tpm_default_chip ) ;
2016-02-13 06:29:53 +03:00
/**
2018-06-26 14:06:15 +03:00
* tpm_find_get_ops ( ) - find and reserve a TPM chip
2017-11-05 14:16:26 +03:00
* @ chip : a & struct tpm_chip instance , % NULL for the default chip
2016-02-13 06:29:53 +03:00
*
2017-11-05 14:16:26 +03:00
* Finds a TPM chip and reserves its class device and operations . The chip must
2018-06-26 14:06:15 +03:00
* be released with tpm_put_ops ( ) after use .
* This function is for internal use only . It supports existing TPM callers
* by accepting NULL , but those callers should be converted to pass in a chip
* directly .
2017-11-05 14:16:26 +03:00
*
* Return :
* A reserved & struct tpm_chip instance .
* % NULL if a chip is not found .
* % NULL if the chip is not available .
2016-12-15 02:09:16 +03:00
*/
2018-06-26 14:06:15 +03:00
struct tpm_chip * tpm_find_get_ops ( struct tpm_chip * chip )
2014-12-12 22:46:34 +03:00
{
2018-06-26 22:09:31 +03:00
int rc ;
2016-02-29 16:53:02 +03:00
2018-06-26 22:09:31 +03:00
if ( chip ) {
2017-11-05 14:16:26 +03:00
if ( ! tpm_try_get_ops ( chip ) )
2018-06-26 22:09:31 +03:00
return chip ;
return NULL ;
2016-02-29 16:53:02 +03:00
}
2014-12-12 22:46:34 +03:00
2018-06-26 22:09:31 +03:00
chip = tpm_default_chip ( ) ;
if ( ! chip )
return NULL ;
rc = tpm_try_get_ops ( chip ) ;
/* release additional reference we got from tpm_default_chip() */
put_device ( & chip - > dev ) ;
if ( rc )
return NULL ;
return chip ;
2014-12-12 22:46:34 +03:00
}
/**
2014-12-12 22:46:37 +03:00
* tpm_dev_release ( ) - free chip memory and the device number
* @ dev : the character device for the TPM chip
2014-12-12 22:46:34 +03:00
*
2014-12-12 22:46:37 +03:00
* This is used as the release function for the character device .
2014-12-12 22:46:34 +03:00
*/
2014-12-12 22:46:37 +03:00
static void tpm_dev_release ( struct device * dev )
2014-12-12 22:46:34 +03:00
{
2014-12-12 22:46:37 +03:00
struct tpm_chip * chip = container_of ( dev , struct tpm_chip , dev ) ;
2014-12-12 22:46:34 +03:00
2016-02-29 16:53:02 +03:00
mutex_lock ( & idr_lock ) ;
idr_remove ( & dev_nums_idr , chip - > dev_num ) ;
mutex_unlock ( & idr_lock ) ;
2017-01-06 15:03:45 +03:00
kfree ( chip - > work_space . context_buf ) ;
2017-02-01 02:47:31 +03:00
kfree ( chip - > work_space . session_buf ) ;
2019-02-06 19:24:47 +03:00
kfree ( chip - > allocated_banks ) ;
2014-12-12 22:46:34 +03:00
kfree ( chip ) ;
}
2017-06-26 00:53:24 +03:00
/**
* tpm_class_shutdown ( ) - prepare the TPM device for loss of power .
* @ dev : device to which the chip is associated .
*
* Issues a TPM2_Shutdown command prior to loss of power , as required by the
2019-07-08 17:56:39 +03:00
* TPM 2.0 spec . Then , calls bus - and device - specific shutdown code .
2017-06-26 00:53:24 +03:00
*
2019-07-08 17:56:39 +03:00
* Return : always 0 ( i . e . success )
2017-06-26 00:53:24 +03:00
*/
static int tpm_class_shutdown ( struct device * dev )
{
struct tpm_chip * chip = container_of ( dev , struct tpm_chip , dev ) ;
2019-06-11 01:01:18 +03:00
down_write ( & chip - > ops_sem ) ;
2017-06-26 00:53:24 +03:00
if ( chip - > flags & TPM_CHIP_FLAG_TPM2 ) {
2018-11-05 04:02:38 +03:00
if ( ! tpm_chip_start ( chip ) ) {
2018-11-05 03:07:56 +03:00
tpm2_shutdown ( chip , TPM2_SU_CLEAR ) ;
2018-11-05 04:02:38 +03:00
tpm_chip_stop ( chip ) ;
2018-11-05 03:07:56 +03:00
}
2017-06-26 00:53:24 +03:00
}
2019-06-11 01:01:18 +03:00
chip - > ops = NULL ;
up_write ( & chip - > ops_sem ) ;
2017-08-11 16:44:43 +03:00
2017-06-26 00:53:24 +03:00
return 0 ;
}
2014-12-12 22:46:34 +03:00
/**
2016-02-11 22:45:48 +03:00
* tpm_chip_alloc ( ) - allocate a new struct tpm_chip instance
* @ pdev : device to which the chip is associated
* At this point pdev mst be initialized , but does not have to
* be registered
2014-12-12 22:46:34 +03:00
* @ ops : struct tpm_class_ops instance
*
* Allocates a new struct tpm_chip instance and assigns a free
2016-02-11 22:45:48 +03:00
* device number for it . Must be paired with put_device ( & chip - > dev ) .
2014-12-12 22:46:34 +03:00
*/
2016-11-23 13:04:13 +03:00
struct tpm_chip * tpm_chip_alloc ( struct device * pdev ,
2016-02-11 22:45:48 +03:00
const struct tpm_class_ops * ops )
2014-12-12 22:46:34 +03:00
{
struct tpm_chip * chip ;
2016-02-13 12:58:16 +03:00
int rc ;
2014-12-12 22:46:34 +03:00
chip = kzalloc ( sizeof ( * chip ) , GFP_KERNEL ) ;
if ( chip = = NULL )
return ERR_PTR ( - ENOMEM ) ;
mutex_init ( & chip - > tpm_mutex ) ;
2016-02-13 06:29:53 +03:00
init_rwsem ( & chip - > ops_sem ) ;
2014-12-12 22:46:34 +03:00
chip - > ops = ops ;
2016-02-29 16:53:02 +03:00
mutex_lock ( & idr_lock ) ;
rc = idr_alloc ( & dev_nums_idr , NULL , 0 , TPM_NUM_DEVICES , GFP_KERNEL ) ;
mutex_unlock ( & idr_lock ) ;
if ( rc < 0 ) {
2016-11-23 13:04:13 +03:00
dev_err ( pdev , " No available tpm device numbers \n " ) ;
2014-12-12 22:46:34 +03:00
kfree ( chip ) ;
2016-02-29 16:53:02 +03:00
return ERR_PTR ( rc ) ;
2014-12-12 22:46:34 +03:00
}
2016-02-29 16:53:02 +03:00
chip - > dev_num = rc ;
2014-12-12 22:46:34 +03:00
2016-02-29 20:29:48 +03:00
device_initialize ( & chip - > dev ) ;
2014-12-12 22:46:34 +03:00
2014-12-12 22:46:37 +03:00
chip - > dev . class = tpm_class ;
2017-08-11 16:44:43 +03:00
chip - > dev . class - > shutdown_pre = tpm_class_shutdown ;
2014-12-12 22:46:37 +03:00
chip - > dev . release = tpm_dev_release ;
2016-11-23 13:04:13 +03:00
chip - > dev . parent = pdev ;
2015-04-14 17:56:48 +03:00
chip - > dev . groups = chip - > groups ;
2014-12-12 22:46:37 +03:00
if ( chip - > dev_num = = 0 )
chip - > dev . devt = MKDEV ( MISC_MAJOR , TPM_MINOR ) ;
else
chip - > dev . devt = MKDEV ( MAJOR ( tpm_devt ) , chip - > dev_num ) ;
2016-02-29 20:29:48 +03:00
rc = dev_set_name ( & chip - > dev , " tpm%d " , chip - > dev_num ) ;
if ( rc )
goto out ;
2014-12-12 22:46:37 +03:00
2016-11-23 13:04:13 +03:00
if ( ! pdev )
2016-04-18 20:26:14 +03:00
chip - > flags | = TPM_CHIP_FLAG_VIRTUAL ;
2014-12-12 22:46:37 +03:00
cdev_init ( & chip - > cdev , & tpm_fops ) ;
2016-02-29 16:53:01 +03:00
chip - > cdev . owner = THIS_MODULE ;
2014-12-12 22:46:37 +03:00
2020-07-03 01:55:59 +03:00
rc = tpm2_init_space ( & chip - > work_space , TPM2_SPACE_BUFFER_SIZE ) ;
if ( rc ) {
2017-02-01 02:47:31 +03:00
rc = - ENOMEM ;
goto out ;
}
2017-01-06 15:03:45 +03:00
2017-03-24 12:45:49 +03:00
chip - > locality = - 1 ;
2016-02-11 22:45:48 +03:00
return chip ;
out :
put_device ( & chip - > dev ) ;
return ERR_PTR ( rc ) ;
}
EXPORT_SYMBOL_GPL ( tpm_chip_alloc ) ;
2022-10-21 15:33:09 +03:00
static void tpm_put_device ( void * dev )
{
put_device ( dev ) ;
}
2016-02-11 22:45:48 +03:00
/**
* tpmm_chip_alloc ( ) - allocate a new struct tpm_chip instance
* @ pdev : parent device to which the chip is associated
* @ ops : struct tpm_class_ops instance
*
* Same as tpm_chip_alloc except devm is used to do the put_device
*/
struct tpm_chip * tpmm_chip_alloc ( struct device * pdev ,
const struct tpm_class_ops * ops )
{
struct tpm_chip * chip ;
int rc ;
chip = tpm_chip_alloc ( pdev , ops ) ;
if ( IS_ERR ( chip ) )
return chip ;
2016-06-12 17:05:29 +03:00
rc = devm_add_action_or_reset ( pdev ,
2022-10-21 15:33:09 +03:00
tpm_put_device ,
2016-06-12 17:05:29 +03:00
& chip - > dev ) ;
if ( rc )
2016-02-13 12:58:16 +03:00
return ERR_PTR ( rc ) ;
2016-02-08 23:31:08 +03:00
2016-02-11 22:45:48 +03:00
dev_set_drvdata ( pdev , chip ) ;
2016-02-29 20:29:48 +03:00
2016-02-11 22:45:48 +03:00
return chip ;
2014-12-12 22:46:34 +03:00
}
EXPORT_SYMBOL_GPL ( tpmm_chip_alloc ) ;
2016-01-29 20:47:22 +03:00
static int tpm_add_char_device ( struct tpm_chip * chip )
2014-12-12 22:46:37 +03:00
{
int rc ;
2017-03-17 21:48:13 +03:00
rc = cdev_device_add ( & chip - > cdev , & chip - > dev ) ;
2014-12-12 22:46:37 +03:00
if ( rc ) {
dev_err ( & chip - > dev ,
2017-03-17 21:48:13 +03:00
" unable to cdev_device_add() %s, major %d, minor %d, err=%d \n " ,
2016-02-29 20:29:48 +03:00
dev_name ( & chip - > dev ) , MAJOR ( chip - > dev . devt ) ,
2014-12-12 22:46:37 +03:00
MINOR ( chip - > dev . devt ) , rc ) ;
return rc ;
}
2021-12-13 10:09:25 +03:00
if ( chip - > flags & TPM_CHIP_FLAG_TPM2 & & ! tpm_is_firmware_upgrade ( chip ) ) {
2022-03-02 12:43:53 +03:00
rc = tpm_devs_add ( chip ) ;
if ( rc )
goto err_del_cdev ;
2017-01-03 20:07:32 +03:00
}
2016-02-29 16:53:02 +03:00
/* Make the chip available. */
mutex_lock ( & idr_lock ) ;
idr_replace ( & dev_nums_idr , chip , chip - > dev_num ) ;
mutex_unlock ( & idr_lock ) ;
2022-03-02 12:43:53 +03:00
return 0 ;
err_del_cdev :
cdev_device_del ( & chip - > cdev , & chip - > dev ) ;
2014-12-12 22:46:37 +03:00
return rc ;
}
2016-01-29 20:47:22 +03:00
static void tpm_del_char_device ( struct tpm_chip * chip )
2014-12-12 22:46:37 +03:00
{
2017-03-17 21:48:13 +03:00
cdev_device_del ( & chip - > cdev , & chip - > dev ) ;
2016-02-29 16:53:02 +03:00
/* Make the chip unavailable. */
mutex_lock ( & idr_lock ) ;
idr_replace ( & dev_nums_idr , NULL , chip - > dev_num ) ;
mutex_unlock ( & idr_lock ) ;
2016-02-13 06:29:53 +03:00
/* Make the driver uncallable. */
down_write ( & chip - > ops_sem ) ;
2021-12-20 18:06:35 +03:00
/*
* Check if chip - > ops is still valid : In case that the controller
* drivers shutdown handler unregisters the controller in its
* shutdown handler we are called twice and chip - > ops to NULL .
*/
if ( chip - > ops ) {
if ( chip - > flags & TPM_CHIP_FLAG_TPM2 ) {
if ( ! tpm_chip_start ( chip ) ) {
tpm2_shutdown ( chip , TPM2_SU_CLEAR ) ;
tpm_chip_stop ( chip ) ;
}
2018-11-05 03:07:56 +03:00
}
2021-12-20 18:06:35 +03:00
chip - > ops = NULL ;
2018-11-05 03:07:56 +03:00
}
2016-02-13 06:29:53 +03:00
up_write ( & chip - > ops_sem ) ;
2014-12-12 22:46:37 +03:00
}
2016-04-18 20:26:13 +03:00
static void tpm_del_legacy_sysfs ( struct tpm_chip * chip )
{
struct attribute * * i ;
2021-12-13 10:09:25 +03:00
if ( chip - > flags & ( TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL ) | |
tpm_is_firmware_upgrade ( chip ) )
2016-04-18 20:26:13 +03:00
return ;
2015-03-18 09:17:14 +03:00
2016-04-18 20:26:13 +03:00
sysfs_remove_link ( & chip - > dev . parent - > kobj , " ppi " ) ;
for ( i = chip - > groups [ 0 ] - > attrs ; * i ! = NULL ; + + i )
sysfs_remove_link ( & chip - > dev . parent - > kobj , ( * i ) - > name ) ;
2015-03-18 09:17:14 +03:00
}
2016-04-18 20:26:13 +03:00
/* For compatibility with legacy sysfs paths we provide symlinks from the
* parent dev directory to selected names within the tpm chip directory . Old
* kernel versions created these files directly under the parent .
*/
static int tpm_add_legacy_sysfs ( struct tpm_chip * chip )
{
struct attribute * * i ;
int rc ;
2021-12-13 10:09:25 +03:00
if ( chip - > flags & ( TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL ) | |
tpm_is_firmware_upgrade ( chip ) )
2016-04-18 20:26:13 +03:00
return 0 ;
2020-04-05 21:34:35 +03:00
rc = compat_only_sysfs_link_entry_to_kobj (
& chip - > dev . parent - > kobj , & chip - > dev . kobj , " ppi " , NULL ) ;
2016-04-18 20:26:13 +03:00
if ( rc & & rc ! = - ENOENT )
return rc ;
/* All the names from tpm-sysfs */
for ( i = chip - > groups [ 0 ] - > attrs ; * i ! = NULL ; + + i ) {
2020-04-05 21:34:35 +03:00
rc = compat_only_sysfs_link_entry_to_kobj (
& chip - > dev . parent - > kobj , & chip - > dev . kobj , ( * i ) - > name , NULL ) ;
2016-04-18 20:26:13 +03:00
if ( rc ) {
tpm_del_legacy_sysfs ( chip ) ;
return rc ;
}
}
return 0 ;
}
2017-11-17 16:24:03 +03:00
2023-02-28 05:44:39 +03:00
/*
* Some AMD fTPM versions may cause stutter
* https : //www.amd.com/en/support/kb/faq/pa-410
*
* Fixes are available in two series of fTPM firmware :
* 6. x . y . z series : 6.0 .18 .6 +
* 3. x . y . z series : 3.57 . y .5 +
*/
static bool tpm_amd_is_rng_defective ( struct tpm_chip * chip )
{
u32 val1 , val2 ;
u64 version ;
int ret ;
if ( ! ( chip - > flags & TPM_CHIP_FLAG_TPM2 ) )
return false ;
ret = tpm_request_locality ( chip ) ;
if ( ret )
return false ;
ret = tpm2_get_tpm_pt ( chip , TPM2_PT_MANUFACTURER , & val1 , NULL ) ;
if ( ret )
goto release ;
if ( val1 ! = 0x414D4400U /* AMD */ ) {
ret = - ENODEV ;
goto release ;
}
ret = tpm2_get_tpm_pt ( chip , TPM2_PT_FIRMWARE_VERSION_1 , & val1 , NULL ) ;
if ( ret )
goto release ;
ret = tpm2_get_tpm_pt ( chip , TPM2_PT_FIRMWARE_VERSION_2 , & val2 , NULL ) ;
release :
tpm_relinquish_locality ( chip ) ;
if ( ret )
return false ;
version = ( ( u64 ) val1 < < 32 ) | val2 ;
if ( ( version > > 48 ) = = 6 ) {
if ( version > = 0x0006000000180006ULL )
return false ;
} else if ( ( version > > 48 ) = = 3 ) {
if ( version > = 0x0003005700000005ULL )
return false ;
} else {
return false ;
}
dev_warn ( & chip - > dev ,
" AMD fTPM version 0x%llx causes system stutter; hwrng disabled \n " ,
version ) ;
return true ;
}
2017-11-17 16:24:03 +03:00
static int tpm_hwrng_read ( struct hwrng * rng , void * data , size_t max , bool wait )
{
struct tpm_chip * chip = container_of ( rng , struct tpm_chip , hwrng ) ;
return tpm_get_random ( chip , data , max ) ;
}
static int tpm_add_hwrng ( struct tpm_chip * chip )
{
2023-02-28 05:44:39 +03:00
if ( ! IS_ENABLED ( CONFIG_HW_RANDOM_TPM ) | | tpm_is_firmware_upgrade ( chip ) | |
tpm_amd_is_rng_defective ( chip ) )
2017-11-17 16:24:03 +03:00
return 0 ;
snprintf ( chip - > hwrng_name , sizeof ( chip - > hwrng_name ) ,
" tpm-rng-%d " , chip - > dev_num ) ;
chip - > hwrng . name = chip - > hwrng_name ;
chip - > hwrng . read = tpm_hwrng_read ;
return hwrng_register ( & chip - > hwrng ) ;
}
2019-07-11 19:13:35 +03:00
static int tpm_get_pcr_allocation ( struct tpm_chip * chip )
{
int rc ;
2021-12-13 10:09:25 +03:00
if ( tpm_is_firmware_upgrade ( chip ) )
return 0 ;
2019-07-11 19:13:35 +03:00
rc = ( chip - > flags & TPM_CHIP_FLAG_TPM2 ) ?
tpm2_get_pcr_allocation ( chip ) :
tpm1_get_pcr_allocation ( chip ) ;
if ( rc > 0 )
return - ENODEV ;
return rc ;
}
2022-11-24 16:55:37 +03:00
/*
* tpm_chip_startup ( ) - performs auto startup and allocates the PCRs
* @ chip : TPM chip to use .
*/
int tpm_chip_startup ( struct tpm_chip * chip )
{
int rc ;
rc = tpm_chip_start ( chip ) ;
if ( rc )
return rc ;
rc = tpm_auto_startup ( chip ) ;
if ( rc )
goto stop ;
rc = tpm_get_pcr_allocation ( chip ) ;
stop :
tpm_chip_stop ( chip ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( tpm_chip_startup ) ;
2014-12-12 22:46:34 +03:00
/*
2014-12-12 22:46:37 +03:00
* tpm_chip_register ( ) - create a character device for the TPM chip
2014-12-12 22:46:34 +03:00
* @ chip : TPM chip to use .
*
2015-03-02 00:55:47 +03:00
* Creates a character device for the TPM chip and adds sysfs attributes for
* the device . As the last step this function adds the chip to the list of TPM
* chips available for in - kernel use .
2014-12-12 22:46:34 +03:00
*
2015-03-02 00:55:47 +03:00
* This function should be only called after the chip initialization is
* complete .
2014-12-12 22:46:34 +03:00
*/
int tpm_chip_register ( struct tpm_chip * chip )
{
int rc ;
2016-11-14 13:00:51 +03:00
tpm_sysfs_add_device ( chip ) ;
2020-01-03 00:55:18 +03:00
tpm_bios_log_setup ( chip ) ;
2014-12-12 22:46:34 +03:00
2015-04-14 17:56:48 +03:00
tpm_add_ppi ( chip ) ;
2017-11-17 16:24:03 +03:00
rc = tpm_add_hwrng ( chip ) ;
if ( rc )
goto out_ppi ;
2016-01-29 20:47:22 +03:00
rc = tpm_add_char_device ( chip ) ;
2017-11-17 16:24:03 +03:00
if ( rc )
goto out_hwrng ;
2015-03-02 00:55:47 +03:00
2016-04-18 20:26:13 +03:00
rc = tpm_add_legacy_sysfs ( chip ) ;
if ( rc ) {
tpm_chip_unregister ( chip ) ;
return rc ;
2015-11-07 14:33:25 +03:00
}
2014-12-12 22:46:34 +03:00
return 0 ;
2017-11-17 16:24:03 +03:00
out_hwrng :
2021-12-13 10:09:25 +03:00
if ( IS_ENABLED ( CONFIG_HW_RANDOM_TPM ) & & ! tpm_is_firmware_upgrade ( chip ) )
2017-11-17 16:24:03 +03:00
hwrng_unregister ( & chip - > hwrng ) ;
out_ppi :
tpm_bios_log_teardown ( chip ) ;
return rc ;
2014-12-12 22:46:34 +03:00
}
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 ( ) .
*
2016-02-13 06:29:53 +03:00
* Once this function returns the driver call backs in ' op ' s will not be
* running and will no longer start .
*
2014-12-12 22:46:34 +03:00
* NOTE : This function should be only called before deinitializing chip
* resources .
*/
void tpm_chip_unregister ( struct tpm_chip * chip )
{
2016-04-18 20:26:13 +03:00
tpm_del_legacy_sysfs ( chip ) ;
2023-04-23 18:49:58 +03:00
if ( IS_ENABLED ( CONFIG_HW_RANDOM_TPM ) & & ! tpm_is_firmware_upgrade ( chip ) & &
! tpm_amd_is_rng_defective ( chip ) )
2017-11-17 16:24:03 +03:00
hwrng_unregister ( & chip - > hwrng ) ;
2016-11-14 13:00:51 +03:00
tpm_bios_log_teardown ( chip ) ;
2021-12-13 10:09:25 +03:00
if ( chip - > flags & TPM_CHIP_FLAG_TPM2 & & ! tpm_is_firmware_upgrade ( chip ) )
2022-03-02 12:43:53 +03:00
tpm_devs_remove ( chip ) ;
2016-01-29 20:47:22 +03:00
tpm_del_char_device ( chip ) ;
2014-12-12 22:46:34 +03:00
}
EXPORT_SYMBOL_GPL ( tpm_chip_unregister ) ;