@ -44,6 +44,7 @@
# include "ufshcd.h"
# include "ufs_quirks.h"
# include "unipro.h"
# include "ufshcd-crypto.h"
# define CREATE_TRACE_POINTS
# include <trace/events/ufs.h>
@ -796,7 +797,14 @@ static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba)
*/
static inline void ufshcd_hba_start ( struct ufs_hba * hba )
{
ufshcd_writel ( hba , CONTROLLER_ENABLE , REG_CONTROLLER_ENABLE ) ;
u32 val = CONTROLLER_ENABLE ;
if ( ufshcd_hba_is_crypto_supported ( hba ) ) {
ufshcd_crypto_enable ( hba ) ;
val | = CRYPTO_GENERAL_ENABLE ;
}
ufshcd_writel ( hba , val , REG_CONTROLLER_ENABLE ) ;
}
/**
@ -2080,9 +2088,21 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
dword_0 | = UTP_REQ_DESC_INT_CMD ;
/* Transfer request descriptor header fields */
if ( lrbp - > crypto_enable ) {
dword_0 | = UTP_REQ_DESC_CRYPTO_ENABLE_CMD ;
dword_0 | = lrbp - > crypto_key_slot ;
req_desc - > header . dword_1 =
cpu_to_le32 ( ( u32 ) lrbp - > data_unit_num ) ;
req_desc - > header . dword_3 =
cpu_to_le32 ( ( u32 ) ( lrbp - > data_unit_num > > 32 ) ) ;
} else {
/* dword_1 and dword_3 are reserved, hence they are set to 0 */
req_desc - > header . dword_1 = 0 ;
req_desc - > header . dword_3 = 0 ;
}
req_desc - > header . dword_0 = cpu_to_le32 ( dword_0 ) ;
/* dword_1 is reserved, hence it is set to 0 */
req_desc - > header . dword_1 = 0 ;
/*
* assigning invalid value for command status . Controller
* updates OCS on command completion , with the command
@ -2090,8 +2110,6 @@ static void ufshcd_prepare_req_desc_hdr(struct ufshcd_lrb *lrbp,
*/
req_desc - > header . dword_2 =
cpu_to_le32 ( OCS_INVALID_COMMAND_STATUS ) ;
/* dword_3 is reserved, hence it is set to 0 */
req_desc - > header . dword_3 = 0 ;
req_desc - > prd_table_length = 0 ;
}
@ -2267,6 +2285,37 @@ static inline u16 ufshcd_upiu_wlun_to_scsi_wlun(u8 upiu_wlun_id)
return ( upiu_wlun_id & ~ UFS_UPIU_WLUN_ID ) | SCSI_W_LUN_BASE ;
}
static inline int ufshcd_prepare_lrbp_crypto ( struct ufs_hba * hba ,
struct scsi_cmnd * cmd ,
struct ufshcd_lrb * lrbp )
{
int key_slot ;
if ( ! cmd - > request - > bio | |
! bio_crypt_should_process ( cmd - > request - > bio , cmd - > request - > q ) ) {
lrbp - > crypto_enable = false ;
return 0 ;
}
if ( WARN_ON ( ! ufshcd_is_crypto_enabled ( hba ) ) ) {
/*
* Upper layer asked us to do inline encryption
* but that isn ' t enabled , so we fail this request .
*/
return - EINVAL ;
}
key_slot = bio_crypt_get_keyslot ( cmd - > request - > bio ) ;
if ( ! ufshcd_keyslot_valid ( hba , key_slot ) )
return - EINVAL ;
lrbp - > crypto_enable = true ;
lrbp - > crypto_key_slot = key_slot ;
lrbp - > data_unit_num = bio_crypt_data_unit_num ( cmd - > request - > bio ) ;
return 0 ;
}
/**
* ufshcd_queuecommand - main entry point for SCSI requests
* @ cmd : command from SCSI Midlayer
@ -2354,6 +2403,13 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
lrbp - > task_tag = tag ;
lrbp - > lun = ufshcd_scsi_to_upiu_lun ( cmd - > device - > lun ) ;
lrbp - > intr_cmd = ! ufshcd_is_intr_aggr_allowed ( hba ) ? true : false ;
err = ufshcd_prepare_lrbp_crypto ( hba , cmd , lrbp ) ;
if ( err ) {
lrbp - > cmd = NULL ;
clear_bit_unlock ( tag , & hba - > lrb_in_use ) ;
goto out ;
}
lrbp - > req_abort_skip = false ;
ufshcd_comp_scsi_upiu ( hba , lrbp ) ;
@ -2387,6 +2443,7 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
lrbp - > task_tag = tag ;
lrbp - > lun = 0 ; /* device management cmd is not specific to any LUN */
lrbp - > intr_cmd = true ; /* No interrupt aggregation */
lrbp - > crypto_enable = false ; /* No crypto operations */
hba - > dev_cmd . type = cmd_type ;
return ufshcd_comp_devman_upiu ( hba , lrbp ) ;
@ -4024,6 +4081,8 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep)
{
int err ;
ufshcd_crypto_disable ( hba ) ;
ufshcd_writel ( hba , CONTROLLER_DISABLE , REG_CONTROLLER_ENABLE ) ;
err = ufshcd_wait_for_register ( hba , REG_CONTROLLER_ENABLE ,
CONTROLLER_ENABLE , CONTROLLER_DISABLE ,
@ -4392,10 +4451,13 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth)
static int ufshcd_slave_configure ( struct scsi_device * sdev )
{
struct request_queue * q = sdev - > request_queue ;
struct ufs_hba * hba = shost_priv ( sdev - > host ) ;
blk_queue_update_dma_pad ( q , PRDT_DATA_BYTE_COUNT_PAD - 1 ) ;
blk_queue_max_segment_size ( q , PRDT_DATA_BYTE_COUNT_MAX ) ;
ufshcd_crypto_setup_rq_keyslot_manager ( hba , q ) ;
return 0 ;
}
@ -4406,6 +4468,7 @@ static int ufshcd_slave_configure(struct scsi_device *sdev)
static void ufshcd_slave_destroy ( struct scsi_device * sdev )
{
struct ufs_hba * hba ;
struct request_queue * q = sdev - > request_queue ;
hba = shost_priv ( sdev - > host ) ;
/* Drop the reference as it won't be needed anymore */
@ -4416,6 +4479,8 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
hba - > sdev_ufs_device = NULL ;
spin_unlock_irqrestore ( hba - > host - > host_lock , flags ) ;
}
ufshcd_crypto_destroy_rq_keyslot_manager ( hba , q ) ;
}
/**
@ -7993,6 +8058,13 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
goto exit_gating ;
}
/* Init crypto */
err = ufshcd_hba_init_crypto ( hba ) ;
if ( err ) {
dev_err ( hba - > dev , " crypto setup failed \n " ) ;
goto out_remove_scsi_host ;
}
/* Host controller enable */
err = ufshcd_hba_enable ( hba ) ;
if ( err ) {