2019-08-02 15:57:52 +08:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019 HiSilicon Limited. */
# include <crypto/internal/acompress.h>
# include <linux/bitfield.h>
# include <linux/dma-mapping.h>
# include <linux/scatterlist.h>
# include "zip.h"
2020-09-07 16:22:00 +08:00
/* hisi_zip_sqe dw3 */
# define HZIP_BD_STATUS_M GENMASK(7, 0)
/* hisi_zip_sqe dw7 */
# define HZIP_IN_SGE_DATA_OFFSET_M GENMASK(23, 0)
2021-03-27 15:28:47 +08:00
# define HZIP_SQE_TYPE_M GENMASK(31, 28)
2020-09-07 16:22:00 +08:00
/* hisi_zip_sqe dw8 */
# define HZIP_OUT_SGE_DATA_OFFSET_M GENMASK(23, 0)
/* hisi_zip_sqe dw9 */
# define HZIP_REQ_TYPE_M GENMASK(7, 0)
# define HZIP_ALG_TYPE_ZLIB 0x02
# define HZIP_ALG_TYPE_GZIP 0x03
# define HZIP_BUF_TYPE_M GENMASK(11, 8)
# define HZIP_PBUFFER 0x0
# define HZIP_SGL 0x1
2019-08-02 15:57:52 +08:00
# define HZIP_ZLIB_HEAD_SIZE 2
# define HZIP_GZIP_HEAD_SIZE 10
# define GZIP_HEAD_FHCRC_BIT BIT(1)
# define GZIP_HEAD_FEXTRA_BIT BIT(2)
# define GZIP_HEAD_FNAME_BIT BIT(3)
# define GZIP_HEAD_FCOMMENT_BIT BIT(4)
# define GZIP_HEAD_FLG_SHIFT 3
# define GZIP_HEAD_FEXTRA_SHIFT 10
2020-09-07 16:21:59 +08:00
# define GZIP_HEAD_FEXTRA_XLEN 2UL
2019-08-02 15:57:52 +08:00
# define GZIP_HEAD_FHCRC_SIZE 2
# define HZIP_GZIP_HEAD_BUF 256
# define HZIP_ALG_PRIORITY 300
2019-09-30 15:08:52 +08:00
# define HZIP_SGL_SGE_NR 10
2019-08-02 15:57:52 +08:00
static const u8 zlib_head [ HZIP_ZLIB_HEAD_SIZE ] = { 0x78 , 0x9c } ;
2020-09-07 16:22:02 +08:00
static const u8 gzip_head [ HZIP_GZIP_HEAD_SIZE ] = {
0x1f , 0x8b , 0x08 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x03
} ;
2019-08-02 15:57:52 +08:00
enum hisi_zip_alg_type {
HZIP_ALG_TYPE_COMP = 0 ,
HZIP_ALG_TYPE_DECOMP = 1 ,
} ;
2020-09-07 16:21:57 +08:00
enum {
HZIP_QPC_COMP ,
HZIP_QPC_DECOMP ,
HZIP_CTX_Q_NUM
} ;
2019-08-02 15:57:52 +08:00
# define COMP_NAME_TO_TYPE(alg_name) \
( ! strcmp ( ( alg_name ) , " zlib-deflate " ) ? HZIP_ALG_TYPE_ZLIB : \
! strcmp ( ( alg_name ) , " gzip " ) ? HZIP_ALG_TYPE_GZIP : 0 ) \
# define TO_HEAD_SIZE(req_type) \
( ( ( req_type ) = = HZIP_ALG_TYPE_ZLIB ) ? sizeof ( zlib_head ) : \
( ( req_type ) = = HZIP_ALG_TYPE_GZIP ) ? sizeof ( gzip_head ) : 0 ) \
# define TO_HEAD(req_type) \
( ( ( req_type ) = = HZIP_ALG_TYPE_ZLIB ) ? zlib_head : \
2019-10-21 15:41:01 +08:00
( ( req_type ) = = HZIP_ALG_TYPE_GZIP ) ? gzip_head : NULL ) \
2019-08-02 15:57:52 +08:00
struct hisi_zip_req {
struct acomp_req * req ;
2020-09-07 16:21:59 +08:00
u32 sskip ;
u32 dskip ;
2019-08-02 15:57:52 +08:00
struct hisi_acc_hw_sgl * hw_src ;
struct hisi_acc_hw_sgl * hw_dst ;
dma_addr_t dma_src ;
dma_addr_t dma_dst ;
2020-09-07 16:21:59 +08:00
u16 req_id ;
2019-08-02 15:57:52 +08:00
} ;
struct hisi_zip_req_q {
struct hisi_zip_req * q ;
unsigned long * req_bitmap ;
rwlock_t req_lock ;
u16 size ;
} ;
struct hisi_zip_qp_ctx {
struct hisi_qp * qp ;
struct hisi_zip_req_q req_q ;
2019-09-30 15:08:52 +08:00
struct hisi_acc_sgl_pool * sgl_pool ;
2019-08-02 15:57:52 +08:00
struct hisi_zip * zip_dev ;
struct hisi_zip_ctx * ctx ;
} ;
2021-03-27 15:28:47 +08:00
struct hisi_zip_sqe_ops {
u8 sqe_type ;
void ( * fill_addr ) ( struct hisi_zip_sqe * sqe , struct hisi_zip_req * req ) ;
void ( * fill_buf_size ) ( struct hisi_zip_sqe * sqe , struct hisi_zip_req * req ) ;
void ( * fill_buf_type ) ( struct hisi_zip_sqe * sqe , u8 buf_type ) ;
void ( * fill_req_type ) ( struct hisi_zip_sqe * sqe , u8 req_type ) ;
void ( * fill_tag ) ( struct hisi_zip_sqe * sqe , struct hisi_zip_req * req ) ;
void ( * fill_sqe_type ) ( struct hisi_zip_sqe * sqe , u8 sqe_type ) ;
u32 ( * get_tag ) ( struct hisi_zip_sqe * sqe ) ;
u32 ( * get_status ) ( struct hisi_zip_sqe * sqe ) ;
u32 ( * get_dstlen ) ( struct hisi_zip_sqe * sqe ) ;
} ;
2019-08-02 15:57:52 +08:00
struct hisi_zip_ctx {
struct hisi_zip_qp_ctx qp_ctx [ HZIP_CTX_Q_NUM ] ;
2021-03-27 15:28:47 +08:00
const struct hisi_zip_sqe_ops * ops ;
2019-08-02 15:57:52 +08:00
} ;
2019-09-30 15:08:53 +08:00
static int sgl_sge_nr_set ( const char * val , const struct kernel_param * kp )
{
int ret ;
u16 n ;
if ( ! val )
return - EINVAL ;
ret = kstrtou16 ( val , 10 , & n ) ;
if ( ret | | n = = 0 | | n > HISI_ACC_SGL_SGE_NR_MAX )
return - EINVAL ;
return param_set_int ( val , kp ) ;
}
static const struct kernel_param_ops sgl_sge_nr_ops = {
. set = sgl_sge_nr_set ,
. get = param_get_int ,
} ;
static u16 sgl_sge_nr = HZIP_SGL_SGE_NR ;
module_param_cb ( sgl_sge_nr , & sgl_sge_nr_ops , & sgl_sge_nr , 0444 ) ;
MODULE_PARM_DESC ( sgl_sge_nr , " Number of sge in sgl(1-255) " ) ;
2021-03-27 15:28:45 +08:00
static u16 get_extra_field_size ( const u8 * start )
{
return * ( ( u16 * ) start ) + GZIP_HEAD_FEXTRA_XLEN ;
}
static u32 get_name_field_size ( const u8 * start )
{
return strlen ( start ) + 1 ;
}
static u32 get_comment_field_size ( const u8 * start )
{
return strlen ( start ) + 1 ;
}
static u32 __get_gzip_head_size ( const u8 * src )
{
u8 head_flg = * ( src + GZIP_HEAD_FLG_SHIFT ) ;
u32 size = GZIP_HEAD_FEXTRA_SHIFT ;
if ( head_flg & GZIP_HEAD_FEXTRA_BIT )
size + = get_extra_field_size ( src + size ) ;
if ( head_flg & GZIP_HEAD_FNAME_BIT )
size + = get_name_field_size ( src + size ) ;
if ( head_flg & GZIP_HEAD_FCOMMENT_BIT )
size + = get_comment_field_size ( src + size ) ;
if ( head_flg & GZIP_HEAD_FHCRC_BIT )
size + = GZIP_HEAD_FHCRC_SIZE ;
return size ;
}
static size_t __maybe_unused get_gzip_head_size ( struct scatterlist * sgl )
{
char buf [ HZIP_GZIP_HEAD_BUF ] ;
sg_copy_to_buffer ( sgl , sg_nents ( sgl ) , buf , sizeof ( buf ) ) ;
return __get_gzip_head_size ( buf ) ;
}
static int add_comp_head ( struct scatterlist * dst , u8 req_type )
{
int head_size = TO_HEAD_SIZE ( req_type ) ;
const u8 * head = TO_HEAD ( req_type ) ;
int ret ;
ret = sg_copy_from_buffer ( dst , sg_nents ( dst ) , head , head_size ) ;
if ( ret ! = head_size ) {
pr_err ( " the head size of buffer is wrong (%d)! \n " , ret ) ;
return - ENOMEM ;
}
return head_size ;
}
static int get_comp_head_size ( struct acomp_req * acomp_req , u8 req_type )
{
if ( ! acomp_req - > src | | ! acomp_req - > slen )
return - EINVAL ;
if ( req_type = = HZIP_ALG_TYPE_GZIP & &
acomp_req - > slen < GZIP_HEAD_FEXTRA_SHIFT )
return - EINVAL ;
switch ( req_type ) {
case HZIP_ALG_TYPE_ZLIB :
return TO_HEAD_SIZE ( HZIP_ALG_TYPE_ZLIB ) ;
case HZIP_ALG_TYPE_GZIP :
return TO_HEAD_SIZE ( HZIP_ALG_TYPE_GZIP ) ;
default :
pr_err ( " request type does not support! \n " ) ;
return - EINVAL ;
}
}
static struct hisi_zip_req * hisi_zip_create_req ( struct acomp_req * req ,
struct hisi_zip_qp_ctx * qp_ctx ,
size_t head_size , bool is_comp )
{
struct hisi_zip_req_q * req_q = & qp_ctx - > req_q ;
struct hisi_zip_req * q = req_q - > q ;
struct hisi_zip_req * req_cache ;
int req_id ;
write_lock ( & req_q - > req_lock ) ;
req_id = find_first_zero_bit ( req_q - > req_bitmap , req_q - > size ) ;
if ( req_id > = req_q - > size ) {
write_unlock ( & req_q - > req_lock ) ;
dev_dbg ( & qp_ctx - > qp - > qm - > pdev - > dev , " req cache is full! \n " ) ;
return ERR_PTR ( - EAGAIN ) ;
}
set_bit ( req_id , req_q - > req_bitmap ) ;
req_cache = q + req_id ;
req_cache - > req_id = req_id ;
req_cache - > req = req ;
if ( is_comp ) {
req_cache - > sskip = 0 ;
req_cache - > dskip = head_size ;
} else {
req_cache - > sskip = head_size ;
req_cache - > dskip = 0 ;
}
write_unlock ( & req_q - > req_lock ) ;
return req_cache ;
}
static void hisi_zip_remove_req ( struct hisi_zip_qp_ctx * qp_ctx ,
struct hisi_zip_req * req )
{
struct hisi_zip_req_q * req_q = & qp_ctx - > req_q ;
write_lock ( & req_q - > req_lock ) ;
clear_bit ( req - > req_id , req_q - > req_bitmap ) ;
memset ( req , 0 , sizeof ( struct hisi_zip_req ) ) ;
write_unlock ( & req_q - > req_lock ) ;
}
2021-03-27 15:28:47 +08:00
static void hisi_zip_fill_addr ( struct hisi_zip_sqe * sqe , struct hisi_zip_req * req )
{
sqe - > source_addr_l = lower_32_bits ( req - > dma_src ) ;
sqe - > source_addr_h = upper_32_bits ( req - > dma_src ) ;
sqe - > dest_addr_l = lower_32_bits ( req - > dma_dst ) ;
sqe - > dest_addr_h = upper_32_bits ( req - > dma_dst ) ;
}
static void hisi_zip_fill_buf_size ( struct hisi_zip_sqe * sqe , struct hisi_zip_req * req )
{
struct acomp_req * a_req = req - > req ;
sqe - > input_data_length = a_req - > slen - req - > sskip ;
sqe - > dest_avail_out = a_req - > dlen - req - > dskip ;
sqe - > dw7 = FIELD_PREP ( HZIP_IN_SGE_DATA_OFFSET_M , req - > sskip ) ;
sqe - > dw8 = FIELD_PREP ( HZIP_OUT_SGE_DATA_OFFSET_M , req - > dskip ) ;
}
static void hisi_zip_fill_buf_type ( struct hisi_zip_sqe * sqe , u8 buf_type )
2019-08-02 15:57:52 +08:00
{
u32 val ;
2021-03-27 15:28:47 +08:00
val = sqe - > dw9 & ~ HZIP_BUF_TYPE_M ;
2019-08-02 15:57:52 +08:00
val | = FIELD_PREP ( HZIP_BUF_TYPE_M , buf_type ) ;
sqe - > dw9 = val ;
}
2021-03-27 15:28:47 +08:00
static void hisi_zip_fill_req_type ( struct hisi_zip_sqe * sqe , u8 req_type )
2019-08-02 15:57:52 +08:00
{
2021-03-27 15:28:47 +08:00
u32 val ;
val = sqe - > dw9 & ~ HZIP_REQ_TYPE_M ;
val | = FIELD_PREP ( HZIP_REQ_TYPE_M , req_type ) ;
sqe - > dw9 = val ;
2019-08-02 15:57:52 +08:00
}
2021-03-27 15:28:47 +08:00
static void hisi_zip_fill_tag_v1 ( struct hisi_zip_sqe * sqe , struct hisi_zip_req * req )
2019-08-02 15:57:52 +08:00
{
2021-03-27 15:28:47 +08:00
sqe - > dw13 = req - > req_id ;
}
2021-03-27 15:28:48 +08:00
static void hisi_zip_fill_tag_v2 ( struct hisi_zip_sqe * sqe , struct hisi_zip_req * req )
{
sqe - > dw26 = req - > req_id ;
}
2021-03-27 15:28:47 +08:00
static void hisi_zip_fill_sqe_type ( struct hisi_zip_sqe * sqe , u8 sqe_type )
{
u32 val ;
val = sqe - > dw7 & ~ HZIP_SQE_TYPE_M ;
val | = FIELD_PREP ( HZIP_SQE_TYPE_M , sqe_type ) ;
sqe - > dw7 = val ;
}
static void hisi_zip_fill_sqe ( struct hisi_zip_ctx * ctx , struct hisi_zip_sqe * sqe ,
u8 req_type , struct hisi_zip_req * req )
{
const struct hisi_zip_sqe_ops * ops = ctx - > ops ;
2019-08-02 15:57:52 +08:00
memset ( sqe , 0 , sizeof ( struct hisi_zip_sqe ) ) ;
2021-03-27 15:28:47 +08:00
ops - > fill_addr ( sqe , req ) ;
ops - > fill_buf_size ( sqe , req ) ;
ops - > fill_buf_type ( sqe , HZIP_SGL ) ;
ops - > fill_req_type ( sqe , req_type ) ;
ops - > fill_tag ( sqe , req ) ;
ops - > fill_sqe_type ( sqe , ops - > sqe_type ) ;
2019-08-02 15:57:52 +08:00
}
2021-03-27 15:28:45 +08:00
static int hisi_zip_do_work ( struct hisi_zip_req * req ,
struct hisi_zip_qp_ctx * qp_ctx )
{
struct hisi_acc_sgl_pool * pool = qp_ctx - > sgl_pool ;
struct hisi_zip_dfx * dfx = & qp_ctx - > zip_dev - > dfx ;
struct acomp_req * a_req = req - > req ;
struct hisi_qp * qp = qp_ctx - > qp ;
struct device * dev = & qp - > qm - > pdev - > dev ;
struct hisi_zip_sqe zip_sqe ;
int ret ;
if ( ! a_req - > src | | ! a_req - > slen | | ! a_req - > dst | | ! a_req - > dlen )
return - EINVAL ;
req - > hw_src = hisi_acc_sg_buf_map_to_hw_sgl ( dev , a_req - > src , pool ,
2021-03-27 15:28:47 +08:00
req - > req_id < < 1 , & req - > dma_src ) ;
2021-03-27 15:28:45 +08:00
if ( IS_ERR ( req - > hw_src ) ) {
dev_err ( dev , " failed to map the src buffer to hw sgl (%ld)! \n " ,
PTR_ERR ( req - > hw_src ) ) ;
return PTR_ERR ( req - > hw_src ) ;
}
req - > hw_dst = hisi_acc_sg_buf_map_to_hw_sgl ( dev , a_req - > dst , pool ,
( req - > req_id < < 1 ) + 1 ,
2021-03-27 15:28:47 +08:00
& req - > dma_dst ) ;
2021-03-27 15:28:45 +08:00
if ( IS_ERR ( req - > hw_dst ) ) {
ret = PTR_ERR ( req - > hw_dst ) ;
dev_err ( dev , " failed to map the dst buffer to hw slg (%d)! \n " ,
ret ) ;
goto err_unmap_input ;
}
2021-03-27 15:28:47 +08:00
hisi_zip_fill_sqe ( qp_ctx - > ctx , & zip_sqe , qp - > req_type , req ) ;
2021-03-27 15:28:45 +08:00
/* send command to start a task */
atomic64_inc ( & dfx - > send_cnt ) ;
ret = hisi_qp_send ( qp , & zip_sqe ) ;
if ( ret < 0 ) {
atomic64_inc ( & dfx - > send_busy_cnt ) ;
ret = - EAGAIN ;
dev_dbg_ratelimited ( dev , " failed to send request! \n " ) ;
goto err_unmap_output ;
}
return - EINPROGRESS ;
err_unmap_output :
hisi_acc_sg_buf_unmap ( dev , a_req - > dst , req - > hw_dst ) ;
err_unmap_input :
hisi_acc_sg_buf_unmap ( dev , a_req - > src , req - > hw_src ) ;
return ret ;
}
2021-03-27 15:28:47 +08:00
static u32 hisi_zip_get_tag_v1 ( struct hisi_zip_sqe * sqe )
{
return sqe - > dw13 ;
}
2021-03-27 15:28:48 +08:00
static u32 hisi_zip_get_tag_v2 ( struct hisi_zip_sqe * sqe )
{
return sqe - > dw26 ;
}
2021-03-27 15:28:47 +08:00
static u32 hisi_zip_get_status ( struct hisi_zip_sqe * sqe )
{
return sqe - > dw3 & HZIP_BD_STATUS_M ;
}
static u32 hisi_zip_get_dstlen ( struct hisi_zip_sqe * sqe )
{
return sqe - > produced ;
}
2021-03-27 15:28:45 +08:00
static void hisi_zip_acomp_cb ( struct hisi_qp * qp , void * data )
{
struct hisi_zip_qp_ctx * qp_ctx = qp - > qp_ctx ;
2021-03-27 15:28:47 +08:00
const struct hisi_zip_sqe_ops * ops = qp_ctx - > ctx - > ops ;
2021-03-27 15:28:45 +08:00
struct hisi_zip_dfx * dfx = & qp_ctx - > zip_dev - > dfx ;
struct hisi_zip_req_q * req_q = & qp_ctx - > req_q ;
struct device * dev = & qp - > qm - > pdev - > dev ;
struct hisi_zip_sqe * sqe = data ;
2021-03-27 15:28:47 +08:00
u32 tag = ops - > get_tag ( sqe ) ;
struct hisi_zip_req * req = req_q - > q + tag ;
2021-03-27 15:28:45 +08:00
struct acomp_req * acomp_req = req - > req ;
u32 status , dlen , head_size ;
int err = 0 ;
atomic64_inc ( & dfx - > recv_cnt ) ;
2021-03-27 15:28:47 +08:00
status = ops - > get_status ( sqe ) ;
2021-03-27 15:28:45 +08:00
if ( status ! = 0 & & status ! = HZIP_NC_ERR ) {
dev_err ( dev , " %scompress fail in qp%u: %u, output: %u \n " ,
( qp - > alg_type = = 0 ) ? " " : " de " , qp - > qp_id , status ,
sqe - > produced ) ;
atomic64_inc ( & dfx - > err_bd_cnt ) ;
err = - EIO ;
}
2021-03-27 15:28:47 +08:00
dlen = ops - > get_dstlen ( sqe ) ;
2021-03-27 15:28:45 +08:00
hisi_acc_sg_buf_unmap ( dev , acomp_req - > src , req - > hw_src ) ;
hisi_acc_sg_buf_unmap ( dev , acomp_req - > dst , req - > hw_dst ) ;
head_size = ( qp - > alg_type = = 0 ) ? TO_HEAD_SIZE ( qp - > req_type ) : 0 ;
acomp_req - > dlen = dlen + head_size ;
if ( acomp_req - > base . complete )
acomp_request_complete ( acomp_req , err ) ;
hisi_zip_remove_req ( qp_ctx , req ) ;
}
static int hisi_zip_acompress ( struct acomp_req * acomp_req )
{
struct hisi_zip_ctx * ctx = crypto_tfm_ctx ( acomp_req - > base . tfm ) ;
struct hisi_zip_qp_ctx * qp_ctx = & ctx - > qp_ctx [ HZIP_QPC_COMP ] ;
struct device * dev = & qp_ctx - > qp - > qm - > pdev - > dev ;
struct hisi_zip_req * req ;
int head_size ;
int ret ;
/* let's output compression head now */
head_size = add_comp_head ( acomp_req - > dst , qp_ctx - > qp - > req_type ) ;
if ( head_size < 0 ) {
dev_err_ratelimited ( dev , " failed to add comp head (%d)! \n " ,
head_size ) ;
return head_size ;
}
req = hisi_zip_create_req ( acomp_req , qp_ctx , head_size , true ) ;
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
ret = hisi_zip_do_work ( req , qp_ctx ) ;
if ( ret ! = - EINPROGRESS ) {
dev_info_ratelimited ( dev , " failed to do compress (%d)! \n " , ret ) ;
hisi_zip_remove_req ( qp_ctx , req ) ;
}
return ret ;
}
static int hisi_zip_adecompress ( struct acomp_req * acomp_req )
{
struct hisi_zip_ctx * ctx = crypto_tfm_ctx ( acomp_req - > base . tfm ) ;
struct hisi_zip_qp_ctx * qp_ctx = & ctx - > qp_ctx [ HZIP_QPC_DECOMP ] ;
struct device * dev = & qp_ctx - > qp - > qm - > pdev - > dev ;
struct hisi_zip_req * req ;
int head_size , ret ;
head_size = get_comp_head_size ( acomp_req , qp_ctx - > qp - > req_type ) ;
if ( head_size < 0 ) {
dev_err_ratelimited ( dev , " failed to get comp head size (%d)! \n " ,
head_size ) ;
return head_size ;
}
req = hisi_zip_create_req ( acomp_req , qp_ctx , head_size , false ) ;
if ( IS_ERR ( req ) )
return PTR_ERR ( req ) ;
ret = hisi_zip_do_work ( req , qp_ctx ) ;
if ( ret ! = - EINPROGRESS ) {
dev_info_ratelimited ( dev , " failed to do decompress (%d)! \n " ,
ret ) ;
hisi_zip_remove_req ( qp_ctx , req ) ;
}
return ret ;
}
2020-03-10 16:42:50 +08:00
static int hisi_zip_start_qp ( struct hisi_qp * qp , struct hisi_zip_qp_ctx * ctx ,
int alg_type , int req_type )
2019-08-02 15:57:52 +08:00
{
2020-03-10 16:42:50 +08:00
struct device * dev = & qp - > qm - > pdev - > dev ;
2019-08-02 15:57:52 +08:00
int ret ;
qp - > req_type = req_type ;
2020-03-10 16:42:50 +08:00
qp - > alg_type = alg_type ;
2019-08-02 15:57:52 +08:00
qp - > qp_ctx = ctx ;
ret = hisi_qm_start_qp ( qp , 0 ) ;
2020-03-10 16:42:50 +08:00
if ( ret < 0 ) {
2020-09-07 16:21:58 +08:00
dev_err ( dev , " failed to start qp (%d)! \n " , ret ) ;
2020-03-10 16:42:50 +08:00
return ret ;
}
2019-08-02 15:57:52 +08:00
2020-03-10 16:42:50 +08:00
ctx - > qp = qp ;
2019-08-02 15:57:52 +08:00
2020-03-10 16:42:50 +08:00
return 0 ;
2019-08-02 15:57:52 +08:00
}
static void hisi_zip_release_qp ( struct hisi_zip_qp_ctx * ctx )
{
hisi_qm_stop_qp ( ctx - > qp ) ;
hisi_qm_release_qp ( ctx - > qp ) ;
}
2021-03-27 15:28:47 +08:00
static const struct hisi_zip_sqe_ops hisi_zip_ops_v1 = {
. sqe_type = 0 ,
. fill_addr = hisi_zip_fill_addr ,
. fill_buf_size = hisi_zip_fill_buf_size ,
. fill_buf_type = hisi_zip_fill_buf_type ,
. fill_req_type = hisi_zip_fill_req_type ,
. fill_tag = hisi_zip_fill_tag_v1 ,
. fill_sqe_type = hisi_zip_fill_sqe_type ,
. get_tag = hisi_zip_get_tag_v1 ,
. get_status = hisi_zip_get_status ,
. get_dstlen = hisi_zip_get_dstlen ,
} ;
2021-03-27 15:28:48 +08:00
static const struct hisi_zip_sqe_ops hisi_zip_ops_v2 = {
. sqe_type = 0x3 ,
. fill_addr = hisi_zip_fill_addr ,
. fill_buf_size = hisi_zip_fill_buf_size ,
. fill_buf_type = hisi_zip_fill_buf_type ,
. fill_req_type = hisi_zip_fill_req_type ,
. fill_tag = hisi_zip_fill_tag_v2 ,
. fill_sqe_type = hisi_zip_fill_sqe_type ,
. get_tag = hisi_zip_get_tag_v2 ,
. get_status = hisi_zip_get_status ,
. get_dstlen = hisi_zip_get_dstlen ,
} ;
2020-07-05 21:18:59 +12:00
static int hisi_zip_ctx_init ( struct hisi_zip_ctx * hisi_zip_ctx , u8 req_type , int node )
2019-08-02 15:57:52 +08:00
{
2020-03-10 16:42:50 +08:00
struct hisi_qp * qps [ HZIP_CTX_Q_NUM ] = { NULL } ;
2021-03-27 15:28:47 +08:00
struct hisi_zip_qp_ctx * qp_ctx ;
2019-08-02 15:57:52 +08:00
struct hisi_zip * hisi_zip ;
int ret , i , j ;
2020-07-05 21:18:59 +12:00
ret = zip_create_qps ( qps , HZIP_CTX_Q_NUM , node ) ;
2020-03-10 16:42:50 +08:00
if ( ret ) {
2020-09-07 16:21:58 +08:00
pr_err ( " failed to create zip qps (%d)! \n " , ret ) ;
2019-08-02 15:57:52 +08:00
return - ENODEV ;
}
2020-03-10 16:42:50 +08:00
hisi_zip = container_of ( qps [ 0 ] - > qm , struct hisi_zip , qm ) ;
2019-08-02 15:57:52 +08:00
for ( i = 0 ; i < HZIP_CTX_Q_NUM ; i + + ) {
/* alg_type = 0 for compress, 1 for decompress in hw sqe */
2021-03-27 15:28:47 +08:00
qp_ctx = & hisi_zip_ctx - > qp_ctx [ i ] ;
qp_ctx - > ctx = hisi_zip_ctx ;
ret = hisi_zip_start_qp ( qps [ i ] , qp_ctx , i , req_type ) ;
2020-03-10 16:42:50 +08:00
if ( ret ) {
for ( j = i - 1 ; j > = 0 ; j - - )
hisi_qm_stop_qp ( hisi_zip_ctx - > qp_ctx [ j ] . qp ) ;
hisi_qm_free_qps ( qps , HZIP_CTX_Q_NUM ) ;
return ret ;
}
2019-08-02 15:57:52 +08:00
2021-03-27 15:28:47 +08:00
qp_ctx - > zip_dev = hisi_zip ;
2019-08-02 15:57:52 +08:00
}
2021-03-27 15:28:47 +08:00
if ( hisi_zip - > qm . ver < QM_HW_V3 )
hisi_zip_ctx - > ops = & hisi_zip_ops_v1 ;
2021-03-27 15:28:48 +08:00
else
hisi_zip_ctx - > ops = & hisi_zip_ops_v2 ;
2021-03-27 15:28:47 +08:00
2019-08-02 15:57:52 +08:00
return 0 ;
2021-03-27 15:28:45 +08:00
}
2019-08-02 15:57:52 +08:00
2021-03-27 15:28:45 +08:00
static void hisi_zip_ctx_exit ( struct hisi_zip_ctx * hisi_zip_ctx )
{
int i ;
2019-08-02 15:57:52 +08:00
2021-03-27 15:28:45 +08:00
for ( i = 1 ; i > = 0 ; i - - )
hisi_zip_release_qp ( & hisi_zip_ctx - > qp_ctx [ i ] ) ;
2019-08-02 15:57:52 +08:00
}
static int hisi_zip_create_req_q ( struct hisi_zip_ctx * ctx )
{
struct hisi_zip_req_q * req_q ;
int i , ret ;
for ( i = 0 ; i < HZIP_CTX_Q_NUM ; i + + ) {
req_q = & ctx - > qp_ctx [ i ] . req_q ;
req_q - > size = QM_Q_DEPTH ;
req_q - > req_bitmap = kcalloc ( BITS_TO_LONGS ( req_q - > size ) ,
sizeof ( long ) , GFP_KERNEL ) ;
if ( ! req_q - > req_bitmap ) {
ret = - ENOMEM ;
2019-08-14 17:28:39 +08:00
if ( i = = 0 )
return ret ;
goto err_free_loop0 ;
2019-08-02 15:57:52 +08:00
}
rwlock_init ( & req_q - > req_lock ) ;
req_q - > q = kcalloc ( req_q - > size , sizeof ( struct hisi_zip_req ) ,
GFP_KERNEL ) ;
if ( ! req_q - > q ) {
ret = - ENOMEM ;
if ( i = = 0 )
goto err_free_bitmap ;
else
goto err_free_loop1 ;
}
}
return 0 ;
err_free_loop1 :
2020-09-07 16:21:57 +08:00
kfree ( ctx - > qp_ctx [ HZIP_QPC_DECOMP ] . req_q . req_bitmap ) ;
2019-08-02 15:57:52 +08:00
err_free_loop0 :
2020-09-07 16:21:57 +08:00
kfree ( ctx - > qp_ctx [ HZIP_QPC_COMP ] . req_q . q ) ;
2019-08-02 15:57:52 +08:00
err_free_bitmap :
2020-09-07 16:21:57 +08:00
kfree ( ctx - > qp_ctx [ HZIP_QPC_COMP ] . req_q . req_bitmap ) ;
2019-08-02 15:57:52 +08:00
return ret ;
}
static void hisi_zip_release_req_q ( struct hisi_zip_ctx * ctx )
{
int i ;
for ( i = 0 ; i < HZIP_CTX_Q_NUM ; i + + ) {
kfree ( ctx - > qp_ctx [ i ] . req_q . q ) ;
kfree ( ctx - > qp_ctx [ i ] . req_q . req_bitmap ) ;
}
}
static int hisi_zip_create_sgl_pool ( struct hisi_zip_ctx * ctx )
{
struct hisi_zip_qp_ctx * tmp ;
2019-09-30 15:08:52 +08:00
struct device * dev ;
int i ;
2019-08-02 15:57:52 +08:00
for ( i = 0 ; i < HZIP_CTX_Q_NUM ; i + + ) {
tmp = & ctx - > qp_ctx [ i ] ;
2019-09-30 15:08:52 +08:00
dev = & tmp - > qp - > qm - > pdev - > dev ;
tmp - > sgl_pool = hisi_acc_create_sgl_pool ( dev , QM_Q_DEPTH < < 1 ,
2019-09-30 15:08:53 +08:00
sgl_sge_nr ) ;
2019-09-30 15:08:52 +08:00
if ( IS_ERR ( tmp - > sgl_pool ) ) {
2019-08-02 15:57:52 +08:00
if ( i = = 1 )
goto err_free_sgl_pool0 ;
return - ENOMEM ;
}
}
return 0 ;
err_free_sgl_pool0 :
2020-09-07 16:21:57 +08:00
hisi_acc_free_sgl_pool ( & ctx - > qp_ctx [ HZIP_QPC_COMP ] . qp - > qm - > pdev - > dev ,
ctx - > qp_ctx [ HZIP_QPC_COMP ] . sgl_pool ) ;
2019-08-02 15:57:52 +08:00
return - ENOMEM ;
}
static void hisi_zip_release_sgl_pool ( struct hisi_zip_ctx * ctx )
{
int i ;
for ( i = 0 ; i < HZIP_CTX_Q_NUM ; i + + )
hisi_acc_free_sgl_pool ( & ctx - > qp_ctx [ i ] . qp - > qm - > pdev - > dev ,
2019-09-30 15:08:52 +08:00
ctx - > qp_ctx [ i ] . sgl_pool ) ;
2019-08-02 15:57:52 +08:00
}
static void hisi_zip_set_acomp_cb ( struct hisi_zip_ctx * ctx ,
void ( * fn ) ( struct hisi_qp * , void * ) )
{
int i ;
for ( i = 0 ; i < HZIP_CTX_Q_NUM ; i + + )
ctx - > qp_ctx [ i ] . qp - > req_cb = fn ;
}
static int hisi_zip_acomp_init ( struct crypto_acomp * tfm )
{
const char * alg_name = crypto_tfm_alg_name ( & tfm - > base ) ;
struct hisi_zip_ctx * ctx = crypto_tfm_ctx ( & tfm - > base ) ;
2020-09-07 16:21:58 +08:00
struct device * dev ;
2019-08-02 15:57:52 +08:00
int ret ;
2020-07-05 21:18:59 +12:00
ret = hisi_zip_ctx_init ( ctx , COMP_NAME_TO_TYPE ( alg_name ) , tfm - > base . node ) ;
2020-09-07 16:21:58 +08:00
if ( ret ) {
pr_err ( " failed to init ctx (%d)! \n " , ret ) ;
2019-08-02 15:57:52 +08:00
return ret ;
2020-09-07 16:21:58 +08:00
}
dev = & ctx - > qp_ctx [ 0 ] . qp - > qm - > pdev - > dev ;
2019-08-02 15:57:52 +08:00
ret = hisi_zip_create_req_q ( ctx ) ;
2020-09-07 16:21:58 +08:00
if ( ret ) {
dev_err ( dev , " failed to create request queue (%d)! \n " , ret ) ;
2019-08-02 15:57:52 +08:00
goto err_ctx_exit ;
2020-09-07 16:21:58 +08:00
}
2019-08-02 15:57:52 +08:00
ret = hisi_zip_create_sgl_pool ( ctx ) ;
2020-09-07 16:21:58 +08:00
if ( ret ) {
dev_err ( dev , " failed to create sgl pool (%d)! \n " , ret ) ;
2019-08-02 15:57:52 +08:00
goto err_release_req_q ;
2020-09-07 16:21:58 +08:00
}
2019-08-02 15:57:52 +08:00
hisi_zip_set_acomp_cb ( ctx , hisi_zip_acomp_cb ) ;
return 0 ;
err_release_req_q :
hisi_zip_release_req_q ( ctx ) ;
err_ctx_exit :
hisi_zip_ctx_exit ( ctx ) ;
return ret ;
}
static void hisi_zip_acomp_exit ( struct crypto_acomp * tfm )
{
struct hisi_zip_ctx * ctx = crypto_tfm_ctx ( & tfm - > base ) ;
hisi_zip_set_acomp_cb ( ctx , NULL ) ;
hisi_zip_release_sgl_pool ( ctx ) ;
hisi_zip_release_req_q ( ctx ) ;
hisi_zip_ctx_exit ( ctx ) ;
}
static struct acomp_alg hisi_zip_acomp_zlib = {
. init = hisi_zip_acomp_init ,
. exit = hisi_zip_acomp_exit ,
. compress = hisi_zip_acompress ,
. decompress = hisi_zip_adecompress ,
. base = {
. cra_name = " zlib-deflate " ,
. cra_driver_name = " hisi-zlib-acomp " ,
. cra_module = THIS_MODULE ,
. cra_priority = HZIP_ALG_PRIORITY ,
. cra_ctxsize = sizeof ( struct hisi_zip_ctx ) ,
}
} ;
static struct acomp_alg hisi_zip_acomp_gzip = {
. init = hisi_zip_acomp_init ,
. exit = hisi_zip_acomp_exit ,
. compress = hisi_zip_acompress ,
. decompress = hisi_zip_adecompress ,
. base = {
. cra_name = " gzip " ,
. cra_driver_name = " hisi-gzip-acomp " ,
. cra_module = THIS_MODULE ,
. cra_priority = HZIP_ALG_PRIORITY ,
. cra_ctxsize = sizeof ( struct hisi_zip_ctx ) ,
}
} ;
2021-03-04 14:35:44 +08:00
int hisi_zip_register_to_crypto ( struct hisi_qm * qm )
2019-08-02 15:57:52 +08:00
{
2020-08-15 17:56:17 +08:00
int ret ;
2019-08-02 15:57:52 +08:00
ret = crypto_register_acomp ( & hisi_zip_acomp_zlib ) ;
if ( ret ) {
2020-09-07 16:21:58 +08:00
pr_err ( " failed to register to zlib (%d)! \n " , ret ) ;
2019-08-02 15:57:52 +08:00
return ret ;
}
ret = crypto_register_acomp ( & hisi_zip_acomp_gzip ) ;
if ( ret ) {
2020-09-07 16:21:58 +08:00
pr_err ( " failed to register to gzip (%d)! \n " , ret ) ;
2019-08-02 15:57:52 +08:00
crypto_unregister_acomp ( & hisi_zip_acomp_zlib ) ;
}
return ret ;
}
2021-03-04 14:35:44 +08:00
void hisi_zip_unregister_from_crypto ( struct hisi_qm * qm )
2019-08-02 15:57:52 +08:00
{
crypto_unregister_acomp ( & hisi_zip_acomp_gzip ) ;
crypto_unregister_acomp ( & hisi_zip_acomp_zlib ) ;
}