2016-07-21 19:06:38 +08:00
/*
* Copyright ( c ) 2016 Hisilicon Limited .
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
# include <linux/dmapool.h>
# include "hns_roce_common.h"
# include "hns_roce_device.h"
# include "hns_roce_cmd.h"
2020-12-11 09:37:33 +08:00
# define CMD_POLL_TOKEN 0xffff
# define CMD_MAX_NUM 32
2016-07-21 19:06:38 +08:00
2022-03-02 14:48:26 +08:00
static int hns_roce_cmd_mbox_post_hw ( struct hns_roce_dev * hr_dev ,
struct hns_roce_mbox_msg * mbox_msg )
2016-07-21 19:06:38 +08:00
{
2022-03-02 14:48:26 +08:00
return hr_dev - > hw - > post_mbox ( hr_dev , mbox_msg ) ;
2016-07-21 19:06:38 +08:00
}
/* this should be called with "poll_sem" */
2022-03-02 14:48:26 +08:00
static int __hns_roce_cmd_mbox_poll ( struct hns_roce_dev * hr_dev ,
struct hns_roce_mbox_msg * mbox_msg )
2016-07-21 19:06:38 +08:00
{
int ret ;
2022-03-02 14:48:26 +08:00
ret = hns_roce_cmd_mbox_post_hw ( hr_dev , mbox_msg ) ;
2016-07-21 19:06:38 +08:00
if ( ret ) {
2021-04-01 15:32:21 +08:00
dev_err_ratelimited ( hr_dev - > dev ,
2021-11-19 22:02:00 +08:00
" failed to post mailbox 0x%x in poll mode, ret = %d. \n " ,
2022-03-02 14:48:26 +08:00
mbox_msg - > cmd , ret ) ;
2017-08-30 17:23:05 +08:00
return ret ;
2016-07-21 19:06:38 +08:00
}
2022-03-02 14:48:23 +08:00
return hr_dev - > hw - > poll_mbox_done ( hr_dev ) ;
2016-07-21 19:06:38 +08:00
}
2022-03-02 14:48:26 +08:00
static int hns_roce_cmd_mbox_poll ( struct hns_roce_dev * hr_dev ,
struct hns_roce_mbox_msg * mbox_msg )
2016-07-21 19:06:38 +08:00
{
int ret ;
down ( & hr_dev - > cmd . poll_sem ) ;
2022-03-02 14:48:26 +08:00
ret = __hns_roce_cmd_mbox_poll ( hr_dev , mbox_msg ) ;
2016-07-21 19:06:38 +08:00
up ( & hr_dev - > cmd . poll_sem ) ;
return ret ;
}
void hns_roce_cmd_event ( struct hns_roce_dev * hr_dev , u16 token , u8 status ,
u64 out_param )
{
2020-12-11 09:37:33 +08:00
struct hns_roce_cmd_context * context =
& hr_dev - > cmd . context [ token % hr_dev - > cmd . max_cmds ] ;
2016-07-21 19:06:38 +08:00
2021-04-01 15:32:19 +08:00
if ( unlikely ( token ! = context - > token ) ) {
dev_err_ratelimited ( hr_dev - > dev ,
2021-11-19 22:02:00 +08:00
" [cmd] invalid ae token 0x%x, context token is 0x%x. \n " ,
2021-04-01 15:32:19 +08:00
token , context - > token ) ;
2016-07-21 19:06:38 +08:00
return ;
2021-04-01 15:32:19 +08:00
}
2016-07-21 19:06:38 +08:00
context - > result = ( status = = HNS_ROCE_CMD_SUCCESS ) ? 0 : ( - EIO ) ;
context - > out_param = out_param ;
complete ( & context - > done ) ;
}
2022-03-02 14:48:26 +08:00
static int __hns_roce_cmd_mbox_wait ( struct hns_roce_dev * hr_dev ,
struct hns_roce_mbox_msg * mbox_msg )
2016-07-21 19:06:38 +08:00
{
struct hns_roce_cmdq * cmd = & hr_dev - > cmd ;
struct hns_roce_cmd_context * context ;
2017-08-30 17:23:02 +08:00
struct device * dev = hr_dev - > dev ;
2017-08-30 17:23:05 +08:00
int ret ;
2016-07-21 19:06:38 +08:00
spin_lock ( & cmd - > context_lock ) ;
2021-04-01 15:32:19 +08:00
do {
context = & cmd - > context [ cmd - > free_head ] ;
cmd - > free_head = context - > next ;
} while ( context - > busy ) ;
context - > busy = 1 ;
context - > token + = cmd - > max_cmds ;
2016-07-21 19:06:38 +08:00
spin_unlock ( & cmd - > context_lock ) ;
2021-04-01 15:32:19 +08:00
reinit_completion ( & context - > done ) ;
2016-07-21 19:06:38 +08:00
2022-03-02 14:48:26 +08:00
mbox_msg - > token = context - > token ;
ret = hns_roce_cmd_mbox_post_hw ( hr_dev , mbox_msg ) ;
2021-04-01 15:32:21 +08:00
if ( ret ) {
dev_err_ratelimited ( dev ,
2021-11-19 22:02:00 +08:00
" failed to post mailbox 0x%x in event mode, ret = %d. \n " ,
2022-03-02 14:48:26 +08:00
mbox_msg - > cmd , ret ) ;
2016-07-21 19:06:38 +08:00
goto out ;
2021-04-01 15:32:21 +08:00
}
2016-07-21 19:06:38 +08:00
if ( ! wait_for_completion_timeout ( & context - > done ,
2022-03-02 14:48:23 +08:00
msecs_to_jiffies ( HNS_ROCE_CMD_TIMEOUT_MSECS ) ) ) {
2021-11-19 22:02:00 +08:00
dev_err_ratelimited ( dev , " [cmd] token 0x%x mailbox 0x%x timeout. \n " ,
2022-03-02 14:48:26 +08:00
context - > token , mbox_msg - > cmd ) ;
2016-07-21 19:06:38 +08:00
ret = - EBUSY ;
goto out ;
}
ret = context - > result ;
2021-04-01 15:32:19 +08:00
if ( ret )
2021-11-19 22:02:00 +08:00
dev_err_ratelimited ( dev , " [cmd] token 0x%x mailbox 0x%x error %d. \n " ,
2022-03-02 14:48:26 +08:00
context - > token , mbox_msg - > cmd , ret ) ;
2016-07-21 19:06:38 +08:00
out :
2021-04-01 15:32:19 +08:00
context - > busy = 0 ;
2016-07-21 19:06:38 +08:00
return ret ;
}
2022-03-02 14:48:26 +08:00
static int hns_roce_cmd_mbox_wait ( struct hns_roce_dev * hr_dev ,
struct hns_roce_mbox_msg * mbox_msg )
2016-07-21 19:06:38 +08:00
{
2019-06-24 19:47:52 +08:00
int ret ;
2016-07-21 19:06:38 +08:00
down ( & hr_dev - > cmd . event_sem ) ;
2022-03-02 14:48:26 +08:00
ret = __hns_roce_cmd_mbox_wait ( hr_dev , mbox_msg ) ;
2016-07-21 19:06:38 +08:00
up ( & hr_dev - > cmd . event_sem ) ;
return ret ;
}
int hns_roce_cmd_mbox ( struct hns_roce_dev * hr_dev , u64 in_param , u64 out_param ,
2022-03-02 14:48:26 +08:00
u8 cmd , unsigned long tag )
2016-07-21 19:06:38 +08:00
{
2022-03-02 14:48:26 +08:00
struct hns_roce_mbox_msg mbox_msg = { } ;
2021-03-27 11:21:32 +08:00
bool is_busy ;
2019-02-03 20:43:14 +08:00
2021-03-27 11:21:32 +08:00
if ( hr_dev - > hw - > chk_mbox_avail )
if ( ! hr_dev - > hw - > chk_mbox_avail ( hr_dev , & is_busy ) )
return is_busy ? - EBUSY : 0 ;
2018-05-28 19:39:24 +08:00
2022-03-02 14:48:26 +08:00
mbox_msg . in_param = in_param ;
mbox_msg . out_param = out_param ;
mbox_msg . cmd = cmd ;
mbox_msg . tag = tag ;
if ( hr_dev - > cmd . use_events ) {
mbox_msg . event_en = 1 ;
return hns_roce_cmd_mbox_wait ( hr_dev , & mbox_msg ) ;
} else {
mbox_msg . event_en = 0 ;
mbox_msg . token = CMD_POLL_TOKEN ;
return hns_roce_cmd_mbox_poll ( hr_dev , & mbox_msg ) ;
}
2016-07-21 19:06:38 +08:00
}
int hns_roce_cmd_init ( struct hns_roce_dev * hr_dev )
{
sema_init ( & hr_dev - > cmd . poll_sem , 1 ) ;
hr_dev - > cmd . use_events = 0 ;
hr_dev - > cmd . max_cmds = CMD_MAX_NUM ;
2021-04-01 15:32:21 +08:00
hr_dev - > cmd . pool = dma_pool_create ( " hns_roce_cmd " , hr_dev - > dev ,
2016-07-21 19:06:38 +08:00
HNS_ROCE_MAILBOX_SIZE ,
HNS_ROCE_MAILBOX_SIZE , 0 ) ;
if ( ! hr_dev - > cmd . pool )
return - ENOMEM ;
return 0 ;
}
void hns_roce_cmd_cleanup ( struct hns_roce_dev * hr_dev )
{
dma_pool_destroy ( hr_dev - > cmd . pool ) ;
}
int hns_roce_cmd_use_events ( struct hns_roce_dev * hr_dev )
{
struct hns_roce_cmdq * hr_cmd = & hr_dev - > cmd ;
int i ;
2020-12-11 09:37:33 +08:00
hr_cmd - > context =
kcalloc ( hr_cmd - > max_cmds , sizeof ( * hr_cmd - > context ) , GFP_KERNEL ) ;
2021-08-02 14:56:14 +08:00
if ( ! hr_cmd - > context ) {
hr_dev - > cmd_mod = 0 ;
2016-07-21 19:06:38 +08:00
return - ENOMEM ;
2021-08-02 14:56:14 +08:00
}
2016-07-21 19:06:38 +08:00
for ( i = 0 ; i < hr_cmd - > max_cmds ; + + i ) {
hr_cmd - > context [ i ] . token = i ;
hr_cmd - > context [ i ] . next = i + 1 ;
2021-04-01 15:32:19 +08:00
init_completion ( & hr_cmd - > context [ i ] . done ) ;
2016-07-21 19:06:38 +08:00
}
2021-04-01 15:32:19 +08:00
hr_cmd - > context [ hr_cmd - > max_cmds - 1 ] . next = 0 ;
2016-07-21 19:06:38 +08:00
hr_cmd - > free_head = 0 ;
sema_init ( & hr_cmd - > event_sem , hr_cmd - > max_cmds ) ;
spin_lock_init ( & hr_cmd - > context_lock ) ;
hr_cmd - > use_events = 1 ;
return 0 ;
}
void hns_roce_cmd_use_polling ( struct hns_roce_dev * hr_dev )
{
struct hns_roce_cmdq * hr_cmd = & hr_dev - > cmd ;
kfree ( hr_cmd - > context ) ;
2019-08-29 16:41:41 +08:00
hr_cmd - > use_events = 0 ;
2016-07-21 19:06:38 +08:00
}
2020-12-11 09:37:33 +08:00
struct hns_roce_cmd_mailbox *
hns_roce_alloc_cmd_mailbox ( struct hns_roce_dev * hr_dev )
2016-07-21 19:06:38 +08:00
{
struct hns_roce_cmd_mailbox * mailbox ;
mailbox = kmalloc ( sizeof ( * mailbox ) , GFP_KERNEL ) ;
if ( ! mailbox )
return ERR_PTR ( - ENOMEM ) ;
2020-12-11 09:37:33 +08:00
mailbox - > buf =
dma_pool_alloc ( hr_dev - > cmd . pool , GFP_KERNEL , & mailbox - > dma ) ;
2016-07-21 19:06:38 +08:00
if ( ! mailbox - > buf ) {
kfree ( mailbox ) ;
return ERR_PTR ( - ENOMEM ) ;
}
return mailbox ;
}
void hns_roce_free_cmd_mailbox ( struct hns_roce_dev * hr_dev ,
struct hns_roce_cmd_mailbox * mailbox )
{
if ( ! mailbox )
return ;
dma_pool_free ( hr_dev - > cmd . pool , mailbox - > buf , mailbox - > dma ) ;
kfree ( mailbox ) ;
}
2022-03-02 14:48:27 +08:00
int hns_roce_create_hw_ctx ( struct hns_roce_dev * dev ,
struct hns_roce_cmd_mailbox * mailbox ,
u8 cmd , unsigned long idx )
{
return hns_roce_cmd_mbox ( dev , mailbox - > dma , 0 , cmd , idx ) ;
}
int hns_roce_destroy_hw_ctx ( struct hns_roce_dev * dev , u8 cmd , unsigned long idx )
{
return hns_roce_cmd_mbox ( dev , 0 , 0 , cmd , idx ) ;
}