2023-08-23 11:29:12 +02:00
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2016-01-06 09:57:21 -08:00
/*
2016-01-22 13:04:58 -08:00
* Copyright ( c ) 2016 Intel Corporation .
2016-01-06 09:57:21 -08:00
*/
# include <linux/slab.h>
2016-01-06 10:03:31 -08:00
# include <linux/vmalloc.h>
# include <rdma/ib_umem.h>
# include <rdma/rdma_vt.h>
# include "vt.h"
2016-01-06 09:57:21 -08:00
# include "mr.h"
2016-12-07 19:33:20 -08:00
# include "trace.h"
2016-01-06 09:57:21 -08:00
2016-02-14 12:10:29 -08:00
/**
* rvt_driver_mr_init - Init MR resources per driver
* @ rdi : rvt dev struct
*
2016-01-06 10:03:31 -08:00
* Do any intilization needed when a driver registers with rdmavt .
2016-02-14 12:10:29 -08:00
*
* Return : 0 on success or errno on failure
2016-01-06 10:03:31 -08:00
*/
int rvt_driver_mr_init ( struct rvt_dev_info * rdi )
{
unsigned int lkey_table_size = rdi - > dparms . lkey_table_size ;
unsigned lk_tab_size ;
int i ;
/*
* The top hfi1_lkey_table_size bits are used to index the
* table . The lower 8 bits can be owned by the user ( copied from
* the LKEY ) . The remaining bits act as a generation number or tag .
*/
if ( ! lkey_table_size )
return - EINVAL ;
spin_lock_init ( & rdi - > lkey_table . lock ) ;
/* ensure generation is at least 4 bits */
if ( lkey_table_size > RVT_MAX_LKEY_TABLE_BITS ) {
rvt_pr_warn ( rdi , " lkey bits %u too large, reduced to %u \n " ,
lkey_table_size , RVT_MAX_LKEY_TABLE_BITS ) ;
rdi - > dparms . lkey_table_size = RVT_MAX_LKEY_TABLE_BITS ;
lkey_table_size = rdi - > dparms . lkey_table_size ;
}
2016-02-26 13:33:08 -08:00
rdi - > lkey_table . max = 1 < < lkey_table_size ;
2016-10-10 06:14:39 -07:00
rdi - > lkey_table . shift = 32 - lkey_table_size ;
2016-01-06 10:03:31 -08:00
lk_tab_size = rdi - > lkey_table . max * sizeof ( * rdi - > lkey_table . table ) ;
rdi - > lkey_table . table = ( struct rvt_mregion __rcu * * )
2016-02-03 14:14:54 -08:00
vmalloc_node ( lk_tab_size , rdi - > dparms . node ) ;
2016-01-06 10:03:31 -08:00
if ( ! rdi - > lkey_table . table )
return - ENOMEM ;
RCU_INIT_POINTER ( rdi - > dma_mr , NULL ) ;
for ( i = 0 ; i < rdi - > lkey_table . max ; i + + )
RCU_INIT_POINTER ( rdi - > lkey_table . table [ i ] , NULL ) ;
2019-05-24 11:44:51 -04:00
rdi - > dparms . props . max_mr = rdi - > lkey_table . max ;
2016-01-06 10:03:31 -08:00
return 0 ;
}
2016-02-14 12:10:29 -08:00
/**
2021-06-16 09:09:47 +03:00
* rvt_mr_exit - clean up MR
* @ rdi : rvt dev structure
2016-02-14 12:10:29 -08:00
*
2016-01-06 10:03:31 -08:00
* called when drivers have unregistered or perhaps failed to register with us
*/
void rvt_mr_exit ( struct rvt_dev_info * rdi )
{
if ( rdi - > dma_mr )
rvt_pr_err ( rdi , " DMA MR not null! \n " ) ;
vfree ( rdi - > lkey_table . table ) ;
}
static void rvt_deinit_mregion ( struct rvt_mregion * mr )
{
int i = mr - > mapsz ;
mr - > mapsz = 0 ;
while ( i )
kfree ( mr - > map [ - - i ] ) ;
2017-02-08 05:26:31 -08:00
percpu_ref_exit ( & mr - > refcount ) ;
}
static void __rvt_mregion_complete ( struct percpu_ref * ref )
{
struct rvt_mregion * mr = container_of ( ref , struct rvt_mregion ,
refcount ) ;
complete ( & mr - > comp ) ;
2016-01-06 10:03:31 -08:00
}
static int rvt_init_mregion ( struct rvt_mregion * mr , struct ib_pd * pd ,
2017-02-08 05:26:31 -08:00
int count , unsigned int percpu_flags )
2016-01-06 10:03:31 -08:00
{
int m , i = 0 ;
2016-05-19 05:21:31 -07:00
struct rvt_dev_info * dev = ib_to_rvt ( pd - > device ) ;
2016-01-06 10:03:31 -08:00
mr - > mapsz = 0 ;
m = ( count + RVT_SEGSZ - 1 ) / RVT_SEGSZ ;
for ( ; i < m ; i + + ) {
2016-05-19 05:21:31 -07:00
mr - > map [ i ] = kzalloc_node ( sizeof ( * mr - > map [ 0 ] ) , GFP_KERNEL ,
dev - > dparms . node ) ;
2017-02-08 05:26:31 -08:00
if ( ! mr - > map [ i ] )
goto bail ;
2016-01-06 10:03:31 -08:00
mr - > mapsz + + ;
}
init_completion ( & mr - > comp ) ;
/* count returning the ptr to user */
2017-02-08 05:26:31 -08:00
if ( percpu_ref_init ( & mr - > refcount , & __rvt_mregion_complete ,
percpu_flags , GFP_KERNEL ) )
goto bail ;
2016-07-25 13:38:19 -07:00
atomic_set ( & mr - > lkey_invalid , 0 ) ;
2016-01-06 10:03:31 -08:00
mr - > pd = pd ;
mr - > max_segs = count ;
return 0 ;
2017-02-08 05:26:31 -08:00
bail :
rvt_deinit_mregion ( mr ) ;
return - ENOMEM ;
2016-01-06 10:03:31 -08:00
}
/**
* rvt_alloc_lkey - allocate an lkey
* @ mr : memory region that this lkey protects
* @ dma_region : 0 - > normal key , 1 - > restricted DMA key
*
* Returns 0 if successful , otherwise returns - errno .
*
* Increments mr reference count as required .
*
* Sets the lkey field mr for non - dma regions .
*
*/
static int rvt_alloc_lkey ( struct rvt_mregion * mr , int dma_region )
{
unsigned long flags ;
u32 r ;
u32 n ;
int ret = 0 ;
struct rvt_dev_info * dev = ib_to_rvt ( mr - > pd - > device ) ;
struct rvt_lkey_table * rkt = & dev - > lkey_table ;
rvt_get_mr ( mr ) ;
spin_lock_irqsave ( & rkt - > lock , flags ) ;
/* special case for dma_mr lkey == 0 */
if ( dma_region ) {
struct rvt_mregion * tmr ;
tmr = rcu_access_pointer ( dev - > dma_mr ) ;
if ( ! tmr ) {
mr - > lkey_published = 1 ;
2017-03-20 17:26:26 -07:00
/* Insure published written first */
rcu_assign_pointer ( dev - > dma_mr , mr ) ;
2017-02-08 05:26:31 -08:00
rvt_get_mr ( mr ) ;
2016-01-06 10:03:31 -08:00
}
goto success ;
}
/* Find the next available LKEY */
r = rkt - > next ;
n = r ;
for ( ; ; ) {
if ( ! rcu_access_pointer ( rkt - > table [ r ] ) )
break ;
r = ( r + 1 ) & ( rkt - > max - 1 ) ;
if ( r = = n )
goto bail ;
}
rkt - > next = ( r + 1 ) & ( rkt - > max - 1 ) ;
/*
* Make sure lkey is never zero which is reserved to indicate an
* unrestricted LKEY .
*/
rkt - > gen + + ;
/*
* bits are capped to ensure enough bits for generation number
*/
mr - > lkey = ( r < < ( 32 - dev - > dparms . lkey_table_size ) ) |
( ( ( ( 1 < < ( 24 - dev - > dparms . lkey_table_size ) ) - 1 ) & rkt - > gen )
< < 8 ) ;
if ( mr - > lkey = = 0 ) {
mr - > lkey | = 1 < < 8 ;
rkt - > gen + + ;
}
mr - > lkey_published = 1 ;
2017-03-20 17:26:26 -07:00
/* Insure published written first */
rcu_assign_pointer ( rkt - > table [ r ] , mr ) ;
2016-01-06 10:03:31 -08:00
success :
spin_unlock_irqrestore ( & rkt - > lock , flags ) ;
out :
return ret ;
bail :
rvt_put_mr ( mr ) ;
spin_unlock_irqrestore ( & rkt - > lock , flags ) ;
ret = - ENOMEM ;
goto out ;
}
/**
* rvt_free_lkey - free an lkey
* @ mr : mr to free from tables
*/
static void rvt_free_lkey ( struct rvt_mregion * mr )
{
unsigned long flags ;
u32 lkey = mr - > lkey ;
u32 r ;
struct rvt_dev_info * dev = ib_to_rvt ( mr - > pd - > device ) ;
struct rvt_lkey_table * rkt = & dev - > lkey_table ;
int freed = 0 ;
spin_lock_irqsave ( & rkt - > lock , flags ) ;
2017-02-08 05:26:31 -08:00
if ( ! lkey ) {
if ( mr - > lkey_published ) {
2017-03-20 17:26:26 -07:00
mr - > lkey_published = 0 ;
/* insure published is written before pointer */
rcu_assign_pointer ( dev - > dma_mr , NULL ) ;
2017-02-08 05:26:31 -08:00
rvt_put_mr ( mr ) ;
}
2016-01-06 10:03:31 -08:00
} else {
2017-02-08 05:26:31 -08:00
if ( ! mr - > lkey_published )
goto out ;
2016-01-06 10:03:31 -08:00
r = lkey > > ( 32 - dev - > dparms . lkey_table_size ) ;
2017-03-20 17:26:26 -07:00
mr - > lkey_published = 0 ;
/* insure published is written before pointer */
rcu_assign_pointer ( rkt - > table [ r ] , NULL ) ;
2016-01-06 10:03:31 -08:00
}
freed + + ;
out :
spin_unlock_irqrestore ( & rkt - > lock , flags ) ;
2017-03-20 17:26:26 -07:00
if ( freed )
2017-02-08 05:26:31 -08:00
percpu_ref_kill ( & mr - > refcount ) ;
2016-01-06 10:03:31 -08:00
}
static struct rvt_mr * __rvt_alloc_mr ( int count , struct ib_pd * pd )
{
struct rvt_mr * mr ;
int rval = - ENOMEM ;
int m ;
/* Allocate struct plus pointers to first level page tables. */
m = ( count + RVT_SEGSZ - 1 ) / RVT_SEGSZ ;
treewide: Use struct_size() for kmalloc()-family
One of the more common cases of allocation size calculations is finding
the size of a structure that has a zero-sized array at the end, along
with memory for some number of elements for that array. For example:
struct foo {
int stuff;
void *entry[];
};
instance = kmalloc(sizeof(struct foo) + sizeof(void *) * count, GFP_KERNEL);
Instead of leaving these open-coded and prone to type mistakes, we can
now use the new struct_size() helper:
instance = kmalloc(struct_size(instance, entry, count), GFP_KERNEL);
This patch makes the changes for kmalloc()-family (and kvmalloc()-family)
uses. It was done via automatic conversion with manual review for the
"CHECKME" non-standard cases noted below, using the following Coccinelle
script:
// pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len *
// sizeof *pkey_cache->table, GFP_KERNEL);
@@
identifier alloc =~ "kmalloc|kzalloc|kvmalloc|kvzalloc";
expression GFP;
identifier VAR, ELEMENT;
expression COUNT;
@@
- alloc(sizeof(*VAR) + COUNT * sizeof(*VAR->ELEMENT), GFP)
+ alloc(struct_size(VAR, ELEMENT, COUNT), GFP)
// mr = kzalloc(sizeof(*mr) + m * sizeof(mr->map[0]), GFP_KERNEL);
@@
identifier alloc =~ "kmalloc|kzalloc|kvmalloc|kvzalloc";
expression GFP;
identifier VAR, ELEMENT;
expression COUNT;
@@
- alloc(sizeof(*VAR) + COUNT * sizeof(VAR->ELEMENT[0]), GFP)
+ alloc(struct_size(VAR, ELEMENT, COUNT), GFP)
// Same pattern, but can't trivially locate the trailing element name,
// or variable name.
@@
identifier alloc =~ "kmalloc|kzalloc|kvmalloc|kvzalloc";
expression GFP;
expression SOMETHING, COUNT, ELEMENT;
@@
- alloc(sizeof(SOMETHING) + COUNT * sizeof(ELEMENT), GFP)
+ alloc(CHECKME_struct_size(&SOMETHING, ELEMENT, COUNT), GFP)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-05-08 13:45:50 -07:00
mr = kzalloc ( struct_size ( mr , mr . map , m ) , GFP_KERNEL ) ;
2016-01-06 10:03:31 -08:00
if ( ! mr )
goto bail ;
2017-02-08 05:26:31 -08:00
rval = rvt_init_mregion ( & mr - > mr , pd , count , 0 ) ;
2016-01-06 10:03:31 -08:00
if ( rval )
goto bail ;
/*
* ib_reg_phys_mr ( ) will initialize mr - > ibmr except for
* lkey and rkey .
*/
rval = rvt_alloc_lkey ( & mr - > mr , 0 ) ;
if ( rval )
goto bail_mregion ;
mr - > ibmr . lkey = mr - > mr . lkey ;
mr - > ibmr . rkey = mr - > mr . lkey ;
done :
return mr ;
bail_mregion :
rvt_deinit_mregion ( & mr - > mr ) ;
bail :
kfree ( mr ) ;
mr = ERR_PTR ( rval ) ;
goto done ;
}
static void __rvt_free_mr ( struct rvt_mr * mr )
{
rvt_free_lkey ( & mr - > mr ) ;
2017-02-08 05:26:31 -08:00
rvt_deinit_mregion ( & mr - > mr ) ;
2016-09-09 08:15:37 +01:00
kfree ( mr ) ;
2016-01-06 10:03:31 -08:00
}
2016-01-06 09:57:21 -08:00
/**
* rvt_get_dma_mr - get a DMA memory region
* @ pd : protection domain for this memory region
* @ acc : access flags
*
2016-02-14 12:10:29 -08:00
* Return : the memory region on success , otherwise returns an errno .
2016-01-06 09:57:21 -08:00
*/
struct ib_mr * rvt_get_dma_mr ( struct ib_pd * pd , int acc )
{
2016-01-06 10:03:31 -08:00
struct rvt_mr * mr ;
struct ib_mr * ret ;
int rval ;
if ( ibpd_to_rvtpd ( pd ) - > user )
return ERR_PTR ( - EPERM ) ;
mr = kzalloc ( sizeof ( * mr ) , GFP_KERNEL ) ;
if ( ! mr ) {
ret = ERR_PTR ( - ENOMEM ) ;
goto bail ;
}
2017-02-08 05:26:31 -08:00
rval = rvt_init_mregion ( & mr - > mr , pd , 0 , 0 ) ;
2016-01-06 10:03:31 -08:00
if ( rval ) {
ret = ERR_PTR ( rval ) ;
goto bail ;
}
rval = rvt_alloc_lkey ( & mr - > mr , 1 ) ;
if ( rval ) {
ret = ERR_PTR ( rval ) ;
goto bail_mregion ;
}
mr - > mr . access_flags = acc ;
ret = & mr - > ibmr ;
done :
return ret ;
bail_mregion :
rvt_deinit_mregion ( & mr - > mr ) ;
bail :
kfree ( mr ) ;
goto done ;
2016-01-06 09:57:21 -08:00
}
/**
* rvt_reg_user_mr - register a userspace memory region
* @ pd : protection domain for this memory region
* @ start : starting userspace address
* @ length : length of region to register
2021-01-21 09:45:15 +00:00
* @ virt_addr : associated virtual address
2016-01-06 09:57:21 -08:00
* @ mr_access_flags : access flags for this memory region
* @ udata : unused by the driver
*
2016-02-14 12:10:29 -08:00
* Return : the memory region on success , otherwise returns an errno .
2016-01-06 09:57:21 -08:00
*/
struct ib_mr * rvt_reg_user_mr ( struct ib_pd * pd , u64 start , u64 length ,
u64 virt_addr , int mr_access_flags ,
struct ib_udata * udata )
{
2016-01-06 10:03:31 -08:00
struct rvt_mr * mr ;
struct ib_umem * umem ;
2019-02-12 10:52:24 -06:00
struct sg_page_iter sg_iter ;
int n , m ;
2016-01-06 10:03:31 -08:00
struct ib_mr * ret ;
if ( length = = 0 )
return ERR_PTR ( - EINVAL ) ;
2020-01-15 14:43:31 +02:00
umem = ib_umem_get ( pd - > device , start , length , mr_access_flags ) ;
2016-01-06 10:03:31 -08:00
if ( IS_ERR ( umem ) )
return ( void * ) umem ;
2019-03-28 11:49:47 -05:00
n = ib_umem_num_pages ( umem ) ;
2016-01-06 10:03:31 -08:00
mr = __rvt_alloc_mr ( n , pd ) ;
if ( IS_ERR ( mr ) ) {
ret = ( struct ib_mr * ) mr ;
goto bail_umem ;
}
mr - > mr . user_base = start ;
mr - > mr . iova = virt_addr ;
mr - > mr . length = length ;
mr - > mr . offset = ib_umem_offset ( umem ) ;
mr - > mr . access_flags = mr_access_flags ;
mr - > umem = umem ;
2019-02-12 10:52:24 -06:00
mr - > mr . page_shift = PAGE_SHIFT ;
2016-01-06 10:03:31 -08:00
m = 0 ;
n = 0 ;
2021-08-24 17:25:31 +03:00
for_each_sgtable_page ( & umem - > sgt_append . sgt , & sg_iter , 0 ) {
2016-01-06 10:03:31 -08:00
void * vaddr ;
2019-02-12 10:52:24 -06:00
vaddr = page_address ( sg_page_iter_page ( & sg_iter ) ) ;
2016-01-06 10:03:31 -08:00
if ( ! vaddr ) {
ret = ERR_PTR ( - EINVAL ) ;
goto bail_inval ;
}
mr - > mr . map [ m ] - > segs [ n ] . vaddr = vaddr ;
2019-02-12 10:52:24 -06:00
mr - > mr . map [ m ] - > segs [ n ] . length = PAGE_SIZE ;
trace_rvt_mr_user_seg ( & mr - > mr , m , n , vaddr , PAGE_SIZE ) ;
if ( + + n = = RVT_SEGSZ ) {
2016-01-06 10:03:31 -08:00
m + + ;
n = 0 ;
}
}
return & mr - > ibmr ;
bail_inval :
__rvt_free_mr ( mr ) ;
bail_umem :
ib_umem_release ( umem ) ;
return ret ;
2016-01-06 09:57:21 -08:00
}
2017-08-28 11:24:10 -07:00
/**
* rvt_dereg_clean_qp_cb - callback from iterator
2021-01-21 09:45:15 +00:00
* @ qp : the qp
* @ v : the mregion ( as u64 )
2017-08-28 11:24:10 -07:00
*
* This routine fields the callback for all QPs and
* for QPs in the same PD as the MR will call the
* rvt_qp_mr_clean ( ) to potentially cleanup references .
*/
static void rvt_dereg_clean_qp_cb ( struct rvt_qp * qp , u64 v )
{
struct rvt_mregion * mr = ( struct rvt_mregion * ) v ;
/* skip PDs that are not ours */
if ( mr - > pd ! = qp - > ibqp . pd )
return ;
rvt_qp_mr_clean ( qp , mr - > lkey ) ;
}
/**
* rvt_dereg_clean_qps - find QPs for reference cleanup
2021-01-21 09:45:15 +00:00
* @ mr : the MR that is being deregistered
2017-08-28 11:24:10 -07:00
*
* This routine iterates RC QPs looking for references
* to the lkey noted in mr .
*/
static void rvt_dereg_clean_qps ( struct rvt_mregion * mr )
{
struct rvt_dev_info * rdi = ib_to_rvt ( mr - > pd - > device ) ;
rvt_qp_iter ( rdi , ( u64 ) mr , rvt_dereg_clean_qp_cb ) ;
}
/**
* rvt_check_refs - check references
2021-01-21 09:45:15 +00:00
* @ mr : the megion
* @ t : the caller identification
2017-08-28 11:24:10 -07:00
*
* This routine checks MRs holding a reference during
* when being de - registered .
*
* If the count is non - zero , the code calls a clean routine then
* waits for the timeout for the count to zero .
*/
static int rvt_check_refs ( struct rvt_mregion * mr , const char * t )
{
unsigned long timeout ;
struct rvt_dev_info * rdi = ib_to_rvt ( mr - > pd - > device ) ;
2018-03-14 12:10:18 -07:00
if ( mr - > lkey ) {
/* avoid dma mr */
2017-08-28 11:24:10 -07:00
rvt_dereg_clean_qps ( mr ) ;
2018-03-14 12:10:18 -07:00
/* @mr was indexed on rcu protected @lkey_table */
synchronize_rcu ( ) ;
}
2017-08-28 11:24:10 -07:00
timeout = wait_for_completion_timeout ( & mr - > comp , 5 * HZ ) ;
if ( ! timeout ) {
rvt_pr_err ( rdi ,
" %s timeout mr %p pd %p lkey %x refcount %ld \n " ,
t , mr , mr - > pd , mr - > lkey ,
2020-10-01 23:48:41 +08:00
atomic_long_read ( & mr - > refcount . data - > count ) ) ;
2017-08-28 11:24:10 -07:00
rvt_get_mr ( mr ) ;
return - EBUSY ;
}
return 0 ;
}
/**
* rvt_mr_has_lkey - is MR
2021-01-21 09:45:15 +00:00
* @ mr : the mregion
* @ lkey : the lkey
2017-08-28 11:24:10 -07:00
*/
bool rvt_mr_has_lkey ( struct rvt_mregion * mr , u32 lkey )
{
return mr & & lkey = = mr - > lkey ;
}
/**
* rvt_ss_has_lkey - is mr in sge tests
2021-01-21 09:45:15 +00:00
* @ ss : the sge state
* @ lkey : the lkey
2017-08-28 11:24:10 -07:00
*
* This code tests for an MR in the indicated
* sge state .
*/
bool rvt_ss_has_lkey ( struct rvt_sge_state * ss , u32 lkey )
{
int i ;
bool rval = false ;
if ( ! ss - > num_sge )
return rval ;
/* first one */
rval = rvt_mr_has_lkey ( ss - > sge . mr , lkey ) ;
/* any others */
for ( i = 0 ; ! rval & & i < ss - > num_sge - 1 ; i + + )
rval = rvt_mr_has_lkey ( ss - > sg_list [ i ] . mr , lkey ) ;
return rval ;
}
2016-01-06 09:57:21 -08:00
/**
* rvt_dereg_mr - unregister and free a memory region
* @ ibmr : the memory region to free
2021-01-21 09:45:15 +00:00
* @ udata : unused by the driver
2016-01-06 09:57:21 -08:00
*
* Note that this is called to free MRs created by rvt_get_dma_mr ( )
* or rvt_reg_user_mr ( ) .
2016-02-14 12:10:29 -08:00
*
* Returns 0 on success .
2016-01-06 09:57:21 -08:00
*/
2019-03-31 19:10:05 +03:00
int rvt_dereg_mr ( struct ib_mr * ibmr , struct ib_udata * udata )
2016-01-06 09:57:21 -08:00
{
2016-01-06 10:03:31 -08:00
struct rvt_mr * mr = to_imr ( ibmr ) ;
2017-08-28 11:24:10 -07:00
int ret ;
2016-01-06 10:03:31 -08:00
rvt_free_lkey ( & mr - > mr ) ;
rvt_put_mr ( & mr - > mr ) ; /* will set completion if last */
2017-08-28 11:24:10 -07:00
ret = rvt_check_refs ( & mr - > mr , __func__ ) ;
if ( ret )
2016-01-06 10:03:31 -08:00
goto out ;
rvt_deinit_mregion ( & mr - > mr ) ;
2019-06-16 15:05:20 +03:00
ib_umem_release ( mr - > umem ) ;
2016-01-06 10:03:31 -08:00
kfree ( mr ) ;
out :
return ret ;
2016-01-06 09:57:21 -08:00
}
/**
* rvt_alloc_mr - Allocate a memory region usable with the
* @ pd : protection domain for this memory region
* @ mr_type : mem region type
* @ max_num_sg : Max number of segments allowed
*
2016-02-14 12:10:29 -08:00
* Return : the memory region on success , otherwise return an errno .
2016-01-06 09:57:21 -08:00
*/
2019-03-31 19:10:05 +03:00
struct ib_mr * rvt_alloc_mr ( struct ib_pd * pd , enum ib_mr_type mr_type ,
2020-07-06 15:03:43 +03:00
u32 max_num_sg )
2016-01-06 09:57:21 -08:00
{
2016-01-06 10:03:31 -08:00
struct rvt_mr * mr ;
if ( mr_type ! = IB_MR_TYPE_MEM_REG )
return ERR_PTR ( - EINVAL ) ;
mr = __rvt_alloc_mr ( max_num_sg , pd ) ;
if ( IS_ERR ( mr ) )
return ( struct ib_mr * ) mr ;
return & mr - > ibmr ;
2016-01-06 09:57:21 -08:00
}
2016-07-25 13:38:13 -07:00
/**
* rvt_set_page - page assignment function called by ib_sg_to_pages
* @ ibmr : memory region
* @ addr : dma address of mapped page
*
* Return : 0 on success
*/
static int rvt_set_page ( struct ib_mr * ibmr , u64 addr )
{
struct rvt_mr * mr = to_imr ( ibmr ) ;
u32 ps = 1 < < mr - > mr . page_shift ;
u32 mapped_segs = mr - > mr . length > > mr - > mr . page_shift ;
int m , n ;
if ( unlikely ( mapped_segs = = mr - > mr . max_segs ) )
return - ENOMEM ;
m = mapped_segs / RVT_SEGSZ ;
n = mapped_segs % RVT_SEGSZ ;
mr - > mr . map [ m ] - > segs [ n ] . vaddr = ( void * ) addr ;
mr - > mr . map [ m ] - > segs [ n ] . length = ps ;
mr - > mr . length + = ps ;
2019-06-28 14:22:33 -04:00
trace_rvt_mr_page_seg ( & mr - > mr , m , n , ( void * ) addr , ps ) ;
2016-07-25 13:38:13 -07:00
return 0 ;
}
/**
* rvt_map_mr_sg - map sg list and set it the memory region
* @ ibmr : memory region
* @ sg : dma mapped scatterlist
* @ sg_nents : number of entries in sg
* @ sg_offset : offset in bytes into sg
*
2019-04-15 11:34:22 -07:00
* Overwrite rvt_mr length with mr length calculated by ib_sg_to_pages .
*
2016-07-25 13:38:13 -07:00
* Return : number of sg elements mapped to the memory region
*/
int rvt_map_mr_sg ( struct ib_mr * ibmr , struct scatterlist * sg ,
int sg_nents , unsigned int * sg_offset )
{
struct rvt_mr * mr = to_imr ( ibmr ) ;
2019-04-15 11:34:22 -07:00
int ret ;
2016-07-25 13:38:13 -07:00
mr - > mr . length = 0 ;
mr - > mr . page_shift = PAGE_SHIFT ;
2019-04-15 11:34:22 -07:00
ret = ib_sg_to_pages ( ibmr , sg , sg_nents , sg_offset , rvt_set_page ) ;
mr - > mr . user_base = ibmr - > iova ;
mr - > mr . iova = ibmr - > iova ;
mr - > mr . offset = ibmr - > iova - ( u64 ) mr - > mr . map [ 0 ] - > segs [ 0 ] . vaddr ;
mr - > mr . length = ( size_t ) ibmr - > length ;
2019-06-28 14:22:39 -04:00
trace_rvt_map_mr_sg ( ibmr , sg_nents , sg_offset ) ;
2019-04-15 11:34:22 -07:00
return ret ;
2016-07-25 13:38:13 -07:00
}
2016-07-25 13:38:19 -07:00
/**
* rvt_fast_reg_mr - fast register physical MR
* @ qp : the queue pair where the work request comes from
* @ ibmr : the memory region to be registered
* @ key : updated key for this memory region
* @ access : access flags for this memory region
*
* Returns 0 on success .
*/
int rvt_fast_reg_mr ( struct rvt_qp * qp , struct ib_mr * ibmr , u32 key ,
int access )
{
struct rvt_mr * mr = to_imr ( ibmr ) ;
if ( qp - > ibqp . pd ! = mr - > mr . pd )
return - EACCES ;
/* not applicable to dma MR or user MR */
if ( ! mr - > mr . lkey | | mr - > umem )
return - EINVAL ;
if ( ( key & 0xFFFFFF00 ) ! = ( mr - > mr . lkey & 0xFFFFFF00 ) )
return - EINVAL ;
ibmr - > lkey = key ;
ibmr - > rkey = key ;
mr - > mr . lkey = key ;
mr - > mr . access_flags = access ;
2019-04-15 11:34:22 -07:00
mr - > mr . iova = ibmr - > iova ;
2016-07-25 13:38:19 -07:00
atomic_set ( & mr - > mr . lkey_invalid , 0 ) ;
return 0 ;
}
EXPORT_SYMBOL ( rvt_fast_reg_mr ) ;
/**
* rvt_invalidate_rkey - invalidate an MR rkey
* @ qp : queue pair associated with the invalidate op
* @ rkey : rkey to invalidate
*
* Returns 0 on success .
*/
int rvt_invalidate_rkey ( struct rvt_qp * qp , u32 rkey )
{
struct rvt_dev_info * dev = ib_to_rvt ( qp - > ibqp . device ) ;
struct rvt_lkey_table * rkt = & dev - > lkey_table ;
struct rvt_mregion * mr ;
if ( rkey = = 0 )
return - EINVAL ;
rcu_read_lock ( ) ;
mr = rcu_dereference (
rkt - > table [ ( rkey > > ( 32 - dev - > dparms . lkey_table_size ) ) ] ) ;
if ( unlikely ( ! mr | | mr - > lkey ! = rkey | | qp - > ibqp . pd ! = mr - > pd ) )
goto bail ;
atomic_set ( & mr - > lkey_invalid , 1 ) ;
rcu_read_unlock ( ) ;
return 0 ;
bail :
rcu_read_unlock ( ) ;
return - EINVAL ;
}
EXPORT_SYMBOL ( rvt_invalidate_rkey ) ;
2017-05-12 09:20:31 -07:00
/**
* rvt_sge_adjacent - is isge compressible
* @ last_sge : last outgoing SGE written
* @ sge : SGE to check
*
* If adjacent will update last_sge to add length .
*
* Return : true if isge is adjacent to last sge
*/
2017-07-29 08:43:43 -07:00
static inline bool rvt_sge_adjacent ( struct rvt_sge * last_sge ,
2017-05-12 09:20:31 -07:00
struct ib_sge * sge )
{
if ( last_sge & & sge - > lkey = = last_sge - > mr - > lkey & &
( ( uint64_t ) ( last_sge - > vaddr + last_sge - > length ) = = sge - > addr ) ) {
if ( sge - > lkey ) {
if ( unlikely ( ( sge - > addr - last_sge - > mr - > user_base +
sge - > length > last_sge - > mr - > length ) ) )
return false ; /* overrun, caller will catch */
} else {
last_sge - > length + = sge - > length ;
}
last_sge - > sge_length + = sge - > length ;
trace_rvt_sge_adjacent ( last_sge , sge ) ;
return true ;
}
return false ;
}
2016-01-06 10:03:31 -08:00
/**
* rvt_lkey_ok - check IB SGE for validity and initialize
* @ rkt : table containing lkey to check SGE against
* @ pd : protection domain
* @ isge : outgoing internal SGE
2017-05-12 09:20:31 -07:00
* @ last_sge : last outgoing SGE written
2016-01-06 10:03:31 -08:00
* @ sge : SGE to check
* @ acc : access flags
*
2016-02-14 12:10:29 -08:00
* Check the IB SGE for validity and initialize our internal version
* of it .
*
2017-05-12 09:20:31 -07:00
* Increments the reference count when a new sge is stored .
2016-01-06 10:03:31 -08:00
*
2017-05-12 09:20:31 -07:00
* Return : 0 if compressed , 1 if added , otherwise returns - errno .
2016-01-06 10:03:31 -08:00
*/
int rvt_lkey_ok ( struct rvt_lkey_table * rkt , struct rvt_pd * pd ,
2017-05-12 09:20:31 -07:00
struct rvt_sge * isge , struct rvt_sge * last_sge ,
struct ib_sge * sge , int acc )
2016-01-06 10:03:31 -08:00
{
struct rvt_mregion * mr ;
unsigned n , m ;
size_t off ;
/*
* We use LKEY = = zero for kernel virtual addresses
2020-11-06 19:19:38 +01:00
* ( see rvt_get_dma_mr ( ) ) .
2016-01-06 10:03:31 -08:00
*/
if ( sge - > lkey = = 0 ) {
2016-10-10 06:14:39 -07:00
struct rvt_dev_info * dev = ib_to_rvt ( pd - > ibpd . device ) ;
2016-01-06 10:03:31 -08:00
if ( pd - > user )
2017-05-12 09:20:31 -07:00
return - EINVAL ;
2017-07-29 08:43:43 -07:00
if ( rvt_sge_adjacent ( last_sge , sge ) )
2017-05-12 09:20:31 -07:00
return 0 ;
rcu_read_lock ( ) ;
2016-01-06 10:03:31 -08:00
mr = rcu_dereference ( dev - > dma_mr ) ;
if ( ! mr )
goto bail ;
2016-12-07 19:33:53 -08:00
rvt_get_mr ( mr ) ;
2016-01-06 10:03:31 -08:00
rcu_read_unlock ( ) ;
isge - > mr = mr ;
isge - > vaddr = ( void * ) sge - > addr ;
isge - > length = sge - > length ;
isge - > sge_length = sge - > length ;
isge - > m = 0 ;
isge - > n = 0 ;
goto ok ;
}
2017-07-29 08:43:43 -07:00
if ( rvt_sge_adjacent ( last_sge , sge ) )
2017-05-12 09:20:31 -07:00
return 0 ;
rcu_read_lock ( ) ;
2016-10-10 06:14:39 -07:00
mr = rcu_dereference ( rkt - > table [ sge - > lkey > > rkt - > shift ] ) ;
2017-03-20 17:26:26 -07:00
if ( ! mr )
2016-01-06 10:03:31 -08:00
goto bail ;
2017-03-20 17:26:26 -07:00
rvt_get_mr ( mr ) ;
if ( ! READ_ONCE ( mr - > lkey_published ) )
goto bail_unref ;
if ( unlikely ( atomic_read ( & mr - > lkey_invalid ) | |
mr - > lkey ! = sge - > lkey | | mr - > pd ! = & pd - > ibpd ) )
goto bail_unref ;
2016-01-06 10:03:31 -08:00
off = sge - > addr - mr - > user_base ;
if ( unlikely ( sge - > addr < mr - > user_base | |
off + sge - > length > mr - > length | |
( mr - > access_flags & acc ) ! = acc ) )
2017-03-20 17:26:26 -07:00
goto bail_unref ;
2016-01-06 10:03:31 -08:00
rcu_read_unlock ( ) ;
off + = mr - > offset ;
if ( mr - > page_shift ) {
/*
* page sizes are uniform power of 2 so no loop is necessary
* entries_spanned_by_off is the number of times the loop below
* would have executed .
*/
size_t entries_spanned_by_off ;
entries_spanned_by_off = off > > mr - > page_shift ;
off - = ( entries_spanned_by_off < < mr - > page_shift ) ;
m = entries_spanned_by_off / RVT_SEGSZ ;
n = entries_spanned_by_off % RVT_SEGSZ ;
} else {
m = 0 ;
n = 0 ;
while ( off > = mr - > map [ m ] - > segs [ n ] . length ) {
off - = mr - > map [ m ] - > segs [ n ] . length ;
n + + ;
if ( n > = RVT_SEGSZ ) {
m + + ;
n = 0 ;
}
}
}
isge - > mr = mr ;
isge - > vaddr = mr - > map [ m ] - > segs [ n ] . vaddr + off ;
isge - > length = mr - > map [ m ] - > segs [ n ] . length - off ;
isge - > sge_length = sge - > length ;
isge - > m = m ;
isge - > n = n ;
ok :
2017-05-12 09:20:31 -07:00
trace_rvt_sge_new ( isge , sge ) ;
2016-01-06 10:03:31 -08:00
return 1 ;
2017-03-20 17:26:26 -07:00
bail_unref :
rvt_put_mr ( mr ) ;
2016-01-06 10:03:31 -08:00
bail :
rcu_read_unlock ( ) ;
2017-05-12 09:20:31 -07:00
return - EINVAL ;
2016-01-06 10:03:31 -08:00
}
EXPORT_SYMBOL ( rvt_lkey_ok ) ;
/**
* rvt_rkey_ok - check the IB virtual address , length , and RKEY
* @ qp : qp for validation
* @ sge : SGE state
* @ len : length of data
* @ vaddr : virtual address to place data
* @ rkey : rkey to check
* @ acc : access flags
*
2016-02-14 12:10:29 -08:00
* Return : 1 if successful , otherwise 0.
2016-01-06 10:03:31 -08:00
*
* increments the reference count upon success
*/
int rvt_rkey_ok ( struct rvt_qp * qp , struct rvt_sge * sge ,
u32 len , u64 vaddr , u32 rkey , int acc )
{
struct rvt_dev_info * dev = ib_to_rvt ( qp - > ibqp . device ) ;
struct rvt_lkey_table * rkt = & dev - > lkey_table ;
struct rvt_mregion * mr ;
unsigned n , m ;
size_t off ;
/*
* We use RKEY = = zero for kernel virtual addresses
2020-11-06 19:19:38 +01:00
* ( see rvt_get_dma_mr ( ) ) .
2016-01-06 10:03:31 -08:00
*/
rcu_read_lock ( ) ;
if ( rkey = = 0 ) {
struct rvt_pd * pd = ibpd_to_rvtpd ( qp - > ibqp . pd ) ;
struct rvt_dev_info * rdi = ib_to_rvt ( pd - > ibpd . device ) ;
if ( pd - > user )
goto bail ;
mr = rcu_dereference ( rdi - > dma_mr ) ;
if ( ! mr )
goto bail ;
2016-12-07 19:33:53 -08:00
rvt_get_mr ( mr ) ;
2016-01-06 10:03:31 -08:00
rcu_read_unlock ( ) ;
sge - > mr = mr ;
sge - > vaddr = ( void * ) vaddr ;
sge - > length = len ;
sge - > sge_length = len ;
sge - > m = 0 ;
sge - > n = 0 ;
goto ok ;
}
2016-10-10 06:14:39 -07:00
mr = rcu_dereference ( rkt - > table [ rkey > > rkt - > shift ] ) ;
2017-03-20 17:26:26 -07:00
if ( ! mr )
2016-01-06 10:03:31 -08:00
goto bail ;
2017-03-20 17:26:26 -07:00
rvt_get_mr ( mr ) ;
/* insure mr read is before test */
if ( ! READ_ONCE ( mr - > lkey_published ) )
goto bail_unref ;
if ( unlikely ( atomic_read ( & mr - > lkey_invalid ) | |
mr - > lkey ! = rkey | | qp - > ibqp . pd ! = mr - > pd ) )
goto bail_unref ;
2016-01-06 10:03:31 -08:00
off = vaddr - mr - > iova ;
if ( unlikely ( vaddr < mr - > iova | | off + len > mr - > length | |
( mr - > access_flags & acc ) = = 0 ) )
2017-03-20 17:26:26 -07:00
goto bail_unref ;
2016-01-06 10:03:31 -08:00
rcu_read_unlock ( ) ;
off + = mr - > offset ;
if ( mr - > page_shift ) {
/*
* page sizes are uniform power of 2 so no loop is necessary
* entries_spanned_by_off is the number of times the loop below
* would have executed .
*/
size_t entries_spanned_by_off ;
entries_spanned_by_off = off > > mr - > page_shift ;
off - = ( entries_spanned_by_off < < mr - > page_shift ) ;
m = entries_spanned_by_off / RVT_SEGSZ ;
n = entries_spanned_by_off % RVT_SEGSZ ;
} else {
m = 0 ;
n = 0 ;
while ( off > = mr - > map [ m ] - > segs [ n ] . length ) {
off - = mr - > map [ m ] - > segs [ n ] . length ;
n + + ;
if ( n > = RVT_SEGSZ ) {
m + + ;
n = 0 ;
}
}
}
sge - > mr = mr ;
sge - > vaddr = mr - > map [ m ] - > segs [ n ] . vaddr + off ;
sge - > length = mr - > map [ m ] - > segs [ n ] . length - off ;
sge - > sge_length = len ;
sge - > m = m ;
sge - > n = n ;
ok :
return 1 ;
2017-03-20 17:26:26 -07:00
bail_unref :
rvt_put_mr ( mr ) ;
2016-01-06 10:03:31 -08:00
bail :
rcu_read_unlock ( ) ;
return 0 ;
2016-01-06 09:57:21 -08:00
}
2016-01-06 10:03:31 -08:00
EXPORT_SYMBOL ( rvt_rkey_ok ) ;