2020-05-27 16:21:28 +01:00
// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
/* Copyright(c) 2014 - 2020 Intel Corporation */
2014-06-05 13:42:39 -07:00
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/list.h>
# include <linux/seq_file.h>
# include "adf_accel_devices.h"
# include "adf_cfg.h"
crypto: qat - fix device reset flow
When the device needs a reset, e.g. when an uncorrectable PCIe AER event
occurs, various services/data structures need to be cleaned up, the
hardware reset and the services/data structures initialized and started.
The code to perform the cleanup and initialization was not performed when
a device reset was done.
This patch moves some of the initialization code out of the .probe entry-
point into a separate function that is now called during probe as well as
after the hardware has been reset. Similarly, a new function is added for
first cleaning up these services/data structures prior to resetting. The
new functions are adf_dev_init() and adf_dev_shutdown(), respectively, for
which there are already prototypes but no actual functions just yet and are
now called when the device is reset and during probe/cleanup of the driver.
The down and up flows via ioctl calls has similarly been updated.
In addition, there are two other bugs in the reset flow - one in the logic
for determining whether to schedule a device reset upon receiving an
uncorrectable AER event which prevents the reset flow from being initiated,
and another with clearing the status bit indicating a device is configured
(when resetting the device the configuration remains across the reset so
the bit should not be cleared, otherwise, the necessary services will not
be re-started in adf_dev_start() after the reset - clear the bit only when
actually deleting the configuration).
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2015-01-09 11:54:58 -08:00
# include "adf_common_drv.h"
2014-06-05 13:42:39 -07:00
static DEFINE_MUTEX ( qat_cfg_read_lock ) ;
static void * qat_dev_cfg_start ( struct seq_file * sfile , loff_t * pos )
{
struct adf_cfg_device_data * dev_cfg = sfile - > private ;
2014-06-24 15:19:34 -07:00
2014-06-05 13:42:39 -07:00
mutex_lock ( & qat_cfg_read_lock ) ;
return seq_list_start ( & dev_cfg - > sec_list , * pos ) ;
}
static int qat_dev_cfg_show ( struct seq_file * sfile , void * v )
{
struct list_head * list ;
struct adf_cfg_section * sec =
list_entry ( v , struct adf_cfg_section , list ) ;
seq_printf ( sfile , " [%s] \n " , sec - > name ) ;
list_for_each ( list , & sec - > param_head ) {
struct adf_cfg_key_val * ptr =
list_entry ( list , struct adf_cfg_key_val , list ) ;
seq_printf ( sfile , " %s = %s \n " , ptr - > key , ptr - > val ) ;
}
return 0 ;
}
static void * qat_dev_cfg_next ( struct seq_file * sfile , void * v , loff_t * pos )
{
struct adf_cfg_device_data * dev_cfg = sfile - > private ;
2014-06-24 15:19:34 -07:00
2014-06-05 13:42:39 -07:00
return seq_list_next ( v , & dev_cfg - > sec_list , pos ) ;
}
static void qat_dev_cfg_stop ( struct seq_file * sfile , void * v )
{
mutex_unlock ( & qat_cfg_read_lock ) ;
}
static const struct seq_operations qat_dev_cfg_sops = {
. start = qat_dev_cfg_start ,
. next = qat_dev_cfg_next ,
. stop = qat_dev_cfg_stop ,
. show = qat_dev_cfg_show
} ;
2020-09-16 10:50:17 +08:00
DEFINE_SEQ_ATTRIBUTE ( qat_dev_cfg ) ;
2014-06-05 13:42:39 -07:00
/**
* adf_cfg_dev_add ( ) - Create an acceleration device configuration table .
* @ accel_dev : Pointer to acceleration device .
*
* Function creates a configuration table for the given acceleration device .
* The table stores device specific config values .
* To be used by QAT device specific drivers .
*
2015-07-24 13:18:26 -07:00
* Return : 0 on success , error code otherwise .
2014-06-05 13:42:39 -07:00
*/
int adf_cfg_dev_add ( struct adf_accel_dev * accel_dev )
{
struct adf_cfg_device_data * dev_cfg_data ;
dev_cfg_data = kzalloc ( sizeof ( * dev_cfg_data ) , GFP_KERNEL ) ;
if ( ! dev_cfg_data )
return - ENOMEM ;
INIT_LIST_HEAD ( & dev_cfg_data - > sec_list ) ;
init_rwsem ( & dev_cfg_data - > lock ) ;
accel_dev - > cfg = dev_cfg_data ;
/* accel_dev->debugfs_dir should always be non-NULL here */
dev_cfg_data - > debug = debugfs_create_file ( " dev_cfg " , S_IRUSR ,
accel_dev - > debugfs_dir ,
dev_cfg_data ,
& qat_dev_cfg_fops ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( adf_cfg_dev_add ) ;
static void adf_cfg_section_del_all ( struct list_head * head ) ;
void adf_cfg_del_all ( struct adf_accel_dev * accel_dev )
{
struct adf_cfg_device_data * dev_cfg_data = accel_dev - > cfg ;
down_write ( & dev_cfg_data - > lock ) ;
adf_cfg_section_del_all ( & dev_cfg_data - > sec_list ) ;
up_write ( & dev_cfg_data - > lock ) ;
crypto: qat - fix device reset flow
When the device needs a reset, e.g. when an uncorrectable PCIe AER event
occurs, various services/data structures need to be cleaned up, the
hardware reset and the services/data structures initialized and started.
The code to perform the cleanup and initialization was not performed when
a device reset was done.
This patch moves some of the initialization code out of the .probe entry-
point into a separate function that is now called during probe as well as
after the hardware has been reset. Similarly, a new function is added for
first cleaning up these services/data structures prior to resetting. The
new functions are adf_dev_init() and adf_dev_shutdown(), respectively, for
which there are already prototypes but no actual functions just yet and are
now called when the device is reset and during probe/cleanup of the driver.
The down and up flows via ioctl calls has similarly been updated.
In addition, there are two other bugs in the reset flow - one in the logic
for determining whether to schedule a device reset upon receiving an
uncorrectable AER event which prevents the reset flow from being initiated,
and another with clearing the status bit indicating a device is configured
(when resetting the device the configuration remains across the reset so
the bit should not be cleared, otherwise, the necessary services will not
be re-started in adf_dev_start() after the reset - clear the bit only when
actually deleting the configuration).
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2015-01-09 11:54:58 -08:00
clear_bit ( ADF_STATUS_CONFIGURED , & accel_dev - > status ) ;
2014-06-05 13:42:39 -07:00
}
/**
* adf_cfg_dev_remove ( ) - Clears acceleration device configuration table .
* @ accel_dev : Pointer to acceleration device .
*
* Function removes configuration table from the given acceleration device
* and frees all allocated memory .
* To be used by QAT device specific drivers .
*
* Return : void
*/
void adf_cfg_dev_remove ( struct adf_accel_dev * accel_dev )
{
struct adf_cfg_device_data * dev_cfg_data = accel_dev - > cfg ;
2015-08-07 11:34:25 -07:00
if ( ! dev_cfg_data )
return ;
2014-06-05 13:42:39 -07:00
down_write ( & dev_cfg_data - > lock ) ;
adf_cfg_section_del_all ( & dev_cfg_data - > sec_list ) ;
up_write ( & dev_cfg_data - > lock ) ;
debugfs_remove ( dev_cfg_data - > debug ) ;
kfree ( dev_cfg_data ) ;
accel_dev - > cfg = NULL ;
}
EXPORT_SYMBOL_GPL ( adf_cfg_dev_remove ) ;
static void adf_cfg_keyval_add ( struct adf_cfg_key_val * new ,
struct adf_cfg_section * sec )
{
list_add_tail ( & new - > list , & sec - > param_head ) ;
}
static void adf_cfg_keyval_del_all ( struct list_head * head )
{
struct list_head * list_ptr , * tmp ;
list_for_each_prev_safe ( list_ptr , tmp , head ) {
struct adf_cfg_key_val * ptr =
list_entry ( list_ptr , struct adf_cfg_key_val , list ) ;
list_del ( list_ptr ) ;
kfree ( ptr ) ;
}
}
static void adf_cfg_section_del_all ( struct list_head * head )
{
struct adf_cfg_section * ptr ;
struct list_head * list , * tmp ;
list_for_each_prev_safe ( list , tmp , head ) {
ptr = list_entry ( list , struct adf_cfg_section , list ) ;
adf_cfg_keyval_del_all ( & ptr - > param_head ) ;
list_del ( list ) ;
kfree ( ptr ) ;
}
}
static struct adf_cfg_key_val * adf_cfg_key_value_find ( struct adf_cfg_section * s ,
const char * key )
{
struct list_head * list ;
list_for_each ( list , & s - > param_head ) {
struct adf_cfg_key_val * ptr =
list_entry ( list , struct adf_cfg_key_val , list ) ;
if ( ! strcmp ( ptr - > key , key ) )
return ptr ;
}
return NULL ;
}
static struct adf_cfg_section * adf_cfg_sec_find ( struct adf_accel_dev * accel_dev ,
const char * sec_name )
{
struct adf_cfg_device_data * cfg = accel_dev - > cfg ;
struct list_head * list ;
list_for_each ( list , & cfg - > sec_list ) {
struct adf_cfg_section * ptr =
list_entry ( list , struct adf_cfg_section , list ) ;
if ( ! strcmp ( ptr - > name , sec_name ) )
return ptr ;
}
return NULL ;
}
static int adf_cfg_key_val_get ( struct adf_accel_dev * accel_dev ,
const char * sec_name ,
const char * key_name ,
char * val )
{
struct adf_cfg_section * sec = adf_cfg_sec_find ( accel_dev , sec_name ) ;
struct adf_cfg_key_val * keyval = NULL ;
if ( sec )
keyval = adf_cfg_key_value_find ( sec , key_name ) ;
if ( keyval ) {
memcpy ( val , keyval - > val , ADF_CFG_MAX_VAL_LEN_IN_BYTES ) ;
return 0 ;
}
2020-10-12 21:38:43 +01:00
return - ENODATA ;
2014-06-05 13:42:39 -07:00
}
/**
* adf_cfg_add_key_value_param ( ) - Add key - value config entry to config table .
* @ accel_dev : Pointer to acceleration device .
* @ section_name : Name of the section where the param will be added
* @ key : The key string
* @ val : Value pain for the given @ key
* @ type : Type - string , int or address
*
* Function adds configuration key - value entry in the appropriate section
* in the given acceleration device
* To be used by QAT device specific drivers .
*
2015-07-24 13:18:26 -07:00
* Return : 0 on success , error code otherwise .
2014-06-05 13:42:39 -07:00
*/
int adf_cfg_add_key_value_param ( struct adf_accel_dev * accel_dev ,
const char * section_name ,
const char * key , const void * val ,
enum adf_cfg_val_type type )
{
struct adf_cfg_device_data * cfg = accel_dev - > cfg ;
struct adf_cfg_key_val * key_val ;
struct adf_cfg_section * section = adf_cfg_sec_find ( accel_dev ,
section_name ) ;
if ( ! section )
return - EFAULT ;
key_val = kzalloc ( sizeof ( * key_val ) , GFP_KERNEL ) ;
if ( ! key_val )
return - ENOMEM ;
INIT_LIST_HEAD ( & key_val - > list ) ;
strlcpy ( key_val - > key , key , sizeof ( key_val - > key ) ) ;
if ( type = = ADF_DEC ) {
snprintf ( key_val - > val , ADF_CFG_MAX_VAL_LEN_IN_BYTES ,
" %ld " , ( * ( ( long * ) val ) ) ) ;
} else if ( type = = ADF_STR ) {
strlcpy ( key_val - > val , ( char * ) val , sizeof ( key_val - > val ) ) ;
} else if ( type = = ADF_HEX ) {
snprintf ( key_val - > val , ADF_CFG_MAX_VAL_LEN_IN_BYTES ,
" 0x%lx " , ( unsigned long ) val ) ;
} else {
2015-03-19 16:03:44 -07:00
dev_err ( & GET_DEV ( accel_dev ) , " Unknown type given. \n " ) ;
2014-06-05 13:42:39 -07:00
kfree ( key_val ) ;
2020-10-12 21:38:42 +01:00
return - EINVAL ;
2014-06-05 13:42:39 -07:00
}
key_val - > type = type ;
down_write ( & cfg - > lock ) ;
adf_cfg_keyval_add ( key_val , section ) ;
up_write ( & cfg - > lock ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( adf_cfg_add_key_value_param ) ;
/**
* adf_cfg_section_add ( ) - Add config section entry to config table .
* @ accel_dev : Pointer to acceleration device .
* @ name : Name of the section
*
* Function adds configuration section where key - value entries
* will be stored .
* To be used by QAT device specific drivers .
*
2015-07-24 13:18:26 -07:00
* Return : 0 on success , error code otherwise .
2014-06-05 13:42:39 -07:00
*/
int adf_cfg_section_add ( struct adf_accel_dev * accel_dev , const char * name )
{
struct adf_cfg_device_data * cfg = accel_dev - > cfg ;
struct adf_cfg_section * sec = adf_cfg_sec_find ( accel_dev , name ) ;
if ( sec )
return 0 ;
sec = kzalloc ( sizeof ( * sec ) , GFP_KERNEL ) ;
if ( ! sec )
return - ENOMEM ;
strlcpy ( sec - > name , name , sizeof ( sec - > name ) ) ;
INIT_LIST_HEAD ( & sec - > param_head ) ;
down_write ( & cfg - > lock ) ;
list_add_tail ( & sec - > list , & cfg - > sec_list ) ;
up_write ( & cfg - > lock ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( adf_cfg_section_add ) ;
int adf_cfg_get_param_value ( struct adf_accel_dev * accel_dev ,
const char * section , const char * name ,
char * value )
{
struct adf_cfg_device_data * cfg = accel_dev - > cfg ;
int ret ;
down_read ( & cfg - > lock ) ;
ret = adf_cfg_key_val_get ( accel_dev , section , name , value ) ;
up_read ( & cfg - > lock ) ;
return ret ;
}