2016-01-06 09:50:24 -08:00
/*
2016-01-22 13:04:58 -08:00
* Copyright ( c ) 2016 Intel Corporation .
2016-01-06 09:50:24 -08:00
*
* This file is provided under a dual BSD / GPLv2 license . When using or
* redistributing this file , you may do so under either license .
*
* GPL LICENSE SUMMARY
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* BSD LICENSE
*
* 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 .
* - Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include "vt.h"
2016-01-22 13:00:28 -08:00
# include "trace.h"
2016-01-06 09:50:24 -08:00
2016-01-22 13:01:01 -08:00
# define RVT_UVERBS_ABI_VERSION 2
2016-01-06 09:50:24 -08:00
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
MODULE_DESCRIPTION ( " RDMA Verbs Transport Library " ) ;
static int rvt_init ( void )
{
/* Do any work needed prior to drivers calling for registration*/
return 0 ;
}
module_init ( rvt_init ) ;
static void rvt_cleanup ( void )
{
}
module_exit ( rvt_cleanup ) ;
2016-01-22 13:04:45 -08:00
struct rvt_dev_info * rvt_alloc_device ( size_t size , int nports )
{
struct rvt_dev_info * rdi = ERR_PTR ( - ENOMEM ) ;
rdi = ( struct rvt_dev_info * ) ib_alloc_device ( size ) ;
if ( ! rdi )
return rdi ;
rdi - > ports = kcalloc ( nports ,
sizeof ( struct rvt_ibport * * ) ,
GFP_KERNEL ) ;
if ( ! rdi - > ports )
ib_dealloc_device ( & rdi - > ibdev ) ;
return rdi ;
}
EXPORT_SYMBOL ( rvt_alloc_device ) ;
2016-01-06 09:53:05 -08:00
static int rvt_query_device ( struct ib_device * ibdev ,
struct ib_device_attr * props ,
struct ib_udata * uhw )
{
2016-01-22 12:50:36 -08:00
struct rvt_dev_info * rdi = ib_to_rvt ( ibdev ) ;
if ( uhw - > inlen | | uhw - > outlen )
return - EINVAL ;
2016-01-06 09:53:05 -08:00
/*
2016-01-22 12:50:36 -08:00
* Return rvt_dev_info . dparms . props contents
2016-01-06 09:53:05 -08:00
*/
2016-01-22 12:50:36 -08:00
* props = rdi - > dparms . props ;
return 0 ;
2016-01-06 09:53:05 -08:00
}
static int rvt_modify_device ( struct ib_device * device ,
int device_modify_mask ,
struct ib_device_modify * device_modify )
{
/*
* Change dev props . Planned support is for node desc change and sys
* guid change only . This matches hfi1 and qib behavior . Other drivers
* that support existing modifications will need to add their support .
*/
/*
* VT - DRIVER - API : node_desc_change ( )
* VT - DRIVER - API : sys_guid_change ( )
*/
return - EOPNOTSUPP ;
}
2016-01-06 09:54:07 -08:00
/**
* rvt_query_port : Passes the query port call to the driver
* @ ibdev : Verbs IB dev
* @ port : port number
* @ props : structure to hold returned properties
*
* Returns 0 on success
*/
static int rvt_query_port ( struct ib_device * ibdev , u8 port ,
struct ib_port_attr * props )
{
/*
* VT - DRIVER - API : query_port_state ( )
* driver returns pretty much everything in ib_port_attr
*/
return - EOPNOTSUPP ;
}
/**
* rvt_modify_port
* @ ibdev : Verbs IB dev
* @ port : Port number
* @ port_modify_mask : How to change the port
* @ props : Structure to fill in
*
* Returns 0 on success
*/
static int rvt_modify_port ( struct ib_device * ibdev , u8 port ,
int port_modify_mask , struct ib_port_modify * props )
{
/*
* VT - DRIVER - API : set_link_state ( )
* driver will set the link state using the IB enumeration
*
* VT - DRIVER - API : clear_qkey_violations ( )
* clears driver private qkey counter
*
* VT - DRIVER - API : get_lid ( )
* driver needs to return the LID
*
* TBD : send_trap ( ) and post_mad_send ( ) need examined to see where they
* fit in .
*/
return - EOPNOTSUPP ;
}
2016-01-06 09:54:16 -08:00
/**
* rvt_query_pkey - Return a pkey from the table at a given index
* @ ibdev : Verbs IB dev
* @ port : Port number
* @ intex : Index into pkey table
*
* Returns 0 on failure pkey otherwise
*/
static int rvt_query_pkey ( struct ib_device * ibdev , u8 port , u16 index ,
u16 * pkey )
{
/*
* Driver will be responsible for keeping rvt_dev_info . pkey_table up to
* date . This function will just return that value . There is no need to
* lock , if a stale value is read and sent to the user so be it there is
* no way to protect against that anyway .
*/
2016-01-06 10:05:12 -08:00
struct rvt_dev_info * rdi = ib_to_rvt ( ibdev ) ;
int port_index ;
if ( index > = rvt_get_npkeys ( rdi ) )
return - EINVAL ;
port_index = port - 1 ; /* IB ports start at 1 our array at 0 */
if ( ( port_index < 0 ) | | ( port_index > = rdi - > dparms . nports ) )
return - EINVAL ;
* pkey = rvt_get_pkey ( rdi , port_index , index ) ;
2016-01-06 09:54:16 -08:00
return 0 ;
}
2016-01-06 09:54:50 -08:00
/**
* rvt_query_gid - Return a gid from the table
* @ ibdev : Verbs IB dev
* @ port : Port number
* @ index : = Index in table
* @ gid : Gid to return
*
* Returns 0 on success
*/
static int rvt_query_gid ( struct ib_device * ibdev , u8 port ,
int index , union ib_gid * gid )
{
/*
* Driver is responsible for updating the guid table . Which will be used
* to craft the return value . This will work similar to how query_pkey ( )
* is being done .
*/
return - EOPNOTSUPP ;
}
2016-01-22 12:50:05 -08:00
struct rvt_ucontext {
struct ib_ucontext ibucontext ;
} ;
static inline struct rvt_ucontext * to_iucontext ( struct ib_ucontext
* ibucontext )
{
return container_of ( ibucontext , struct rvt_ucontext , ibucontext ) ;
}
2016-01-06 09:55:39 -08:00
/**
* rvt_alloc_ucontext - Allocate a user context
* @ ibdev : Vers IB dev
* @ data : User data allocated
*/
static struct ib_ucontext * rvt_alloc_ucontext ( struct ib_device * ibdev ,
struct ib_udata * udata )
{
2016-01-22 12:50:05 -08:00
struct rvt_ucontext * context ;
context = kmalloc ( sizeof ( * context ) , GFP_KERNEL ) ;
if ( ! context )
return ERR_PTR ( - ENOMEM ) ;
return & context - > ibucontext ;
2016-01-06 09:55:39 -08:00
}
/**
* rvt_dealloc_ucontext - Free a user context
* @ context - Free this
*/
static int rvt_dealloc_ucontext ( struct ib_ucontext * context )
{
2016-01-22 12:50:05 -08:00
kfree ( to_iucontext ( context ) ) ;
return 0 ;
2016-01-06 09:55:39 -08:00
}
2016-01-06 09:59:38 -08:00
static int rvt_get_port_immutable ( struct ib_device * ibdev , u8 port_num ,
struct ib_port_immutable * immutable )
{
return - EOPNOTSUPP ;
}
2016-01-06 09:52:40 -08:00
/*
* Check driver override . If driver passes a value use it , otherwise we use our
* own value .
*/
# define CHECK_DRIVER_OVERRIDE(rdi, x) \
rdi - > ibdev . x = rdi - > ibdev . x ? : rvt_ # # x
2016-01-06 09:50:24 -08:00
int rvt_register_device ( struct rvt_dev_info * rdi )
{
2016-01-06 10:02:59 -08:00
/* Validate that drivers have provided the right information */
2016-01-06 10:03:31 -08:00
int ret = 0 ;
2016-01-06 09:50:24 -08:00
if ( ! rdi )
return - EINVAL ;
2016-01-06 10:02:59 -08:00
if ( ( ! rdi - > driver_f . port_callback ) | |
( ! rdi - > driver_f . get_card_name ) | |
2016-01-06 10:03:59 -08:00
( ! rdi - > driver_f . get_pci_dev ) | |
( ! rdi - > driver_f . check_ah ) ) {
2016-01-06 10:04:46 -08:00
pr_err ( " Driver not supporting req func \n " ) ;
2016-01-06 10:02:59 -08:00
return - EINVAL ;
}
2016-01-22 13:00:28 -08:00
/* Once we get past here we can use rvt_pr macros and tracepoints */
trace_rvt_dbg ( rdi , " Driver attempting registration " ) ;
2016-01-06 10:04:57 -08:00
rvt_mmap_init ( rdi ) ;
2016-01-06 10:02:59 -08:00
2016-01-06 09:53:05 -08:00
/* Dev Ops */
CHECK_DRIVER_OVERRIDE ( rdi , query_device ) ;
CHECK_DRIVER_OVERRIDE ( rdi , modify_device ) ;
2016-01-06 09:54:07 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , query_port ) ;
CHECK_DRIVER_OVERRIDE ( rdi , modify_port ) ;
2016-01-06 09:54:16 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , query_pkey ) ;
2016-01-06 09:54:50 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , query_gid ) ;
2016-01-06 09:55:39 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , alloc_ucontext ) ;
CHECK_DRIVER_OVERRIDE ( rdi , dealloc_ucontext ) ;
2016-01-06 09:59:38 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , get_port_immutable ) ;
2016-01-06 09:53:05 -08:00
2016-01-06 09:56:15 -08:00
/* Queue Pairs */
2016-01-06 10:04:46 -08:00
ret = rvt_driver_qp_init ( rdi ) ;
if ( ret ) {
pr_err ( " Error in driver QP init. \n " ) ;
return - EINVAL ;
}
2016-01-06 09:56:15 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , create_qp ) ;
CHECK_DRIVER_OVERRIDE ( rdi , modify_qp ) ;
CHECK_DRIVER_OVERRIDE ( rdi , destroy_qp ) ;
CHECK_DRIVER_OVERRIDE ( rdi , query_qp ) ;
2016-01-06 10:01:17 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , post_send ) ;
CHECK_DRIVER_OVERRIDE ( rdi , post_recv ) ;
CHECK_DRIVER_OVERRIDE ( rdi , post_srq_recv ) ;
2016-01-06 09:56:15 -08:00
2016-01-06 09:56:41 -08:00
/* Address Handle */
CHECK_DRIVER_OVERRIDE ( rdi , create_ah ) ;
CHECK_DRIVER_OVERRIDE ( rdi , destroy_ah ) ;
CHECK_DRIVER_OVERRIDE ( rdi , modify_ah ) ;
CHECK_DRIVER_OVERRIDE ( rdi , query_ah ) ;
2016-01-06 10:03:59 -08:00
spin_lock_init ( & rdi - > n_ahs_lock ) ;
rdi - > n_ahs_allocated = 0 ;
2016-01-06 09:56:41 -08:00
2016-01-06 09:57:58 -08:00
/* Shared Receive Queue */
CHECK_DRIVER_OVERRIDE ( rdi , create_srq ) ;
CHECK_DRIVER_OVERRIDE ( rdi , modify_srq ) ;
CHECK_DRIVER_OVERRIDE ( rdi , destroy_srq ) ;
CHECK_DRIVER_OVERRIDE ( rdi , query_srq ) ;
2016-01-06 09:58:23 -08:00
/* Multicast */
2016-01-22 13:00:55 -08:00
rvt_driver_mcast_init ( rdi ) ;
2016-01-06 09:58:23 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , attach_mcast ) ;
CHECK_DRIVER_OVERRIDE ( rdi , detach_mcast ) ;
2016-01-06 09:57:21 -08:00
/* Mem Region */
2016-01-06 10:03:31 -08:00
ret = rvt_driver_mr_init ( rdi ) ;
if ( ret ) {
2016-01-06 10:03:39 -08:00
pr_err ( " Error in driver MR init. \n " ) ;
2016-01-06 10:03:31 -08:00
goto bail_no_mr ;
}
2016-01-06 09:57:21 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , get_dma_mr ) ;
CHECK_DRIVER_OVERRIDE ( rdi , reg_user_mr ) ;
CHECK_DRIVER_OVERRIDE ( rdi , dereg_mr ) ;
CHECK_DRIVER_OVERRIDE ( rdi , alloc_mr ) ;
CHECK_DRIVER_OVERRIDE ( rdi , alloc_fmr ) ;
CHECK_DRIVER_OVERRIDE ( rdi , map_phys_fmr ) ;
CHECK_DRIVER_OVERRIDE ( rdi , unmap_fmr ) ;
CHECK_DRIVER_OVERRIDE ( rdi , dealloc_fmr ) ;
2016-01-06 09:59:04 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , mmap ) ;
2016-01-06 09:57:21 -08:00
2016-01-06 10:00:42 -08:00
/* Completion queues */
2016-01-22 13:00:15 -08:00
ret = rvt_driver_cq_init ( rdi ) ;
if ( ret ) {
pr_err ( " Error in driver CQ init. \n " ) ;
goto bail_mr ;
}
2016-01-06 10:00:42 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , create_cq ) ;
CHECK_DRIVER_OVERRIDE ( rdi , destroy_cq ) ;
CHECK_DRIVER_OVERRIDE ( rdi , poll_cq ) ;
CHECK_DRIVER_OVERRIDE ( rdi , req_notify_cq ) ;
CHECK_DRIVER_OVERRIDE ( rdi , resize_cq ) ;
2016-01-06 09:51:48 -08:00
/* DMA Operations */
2016-01-06 09:51:18 -08:00
rdi - > ibdev . dma_ops =
rdi - > ibdev . dma_ops ? : & rvt_default_dma_mapping_ops ;
2016-01-06 09:51:48 -08:00
/* Protection Domain */
2016-01-06 09:52:40 -08:00
CHECK_DRIVER_OVERRIDE ( rdi , alloc_pd ) ;
CHECK_DRIVER_OVERRIDE ( rdi , dealloc_pd ) ;
2016-01-06 09:51:48 -08:00
spin_lock_init ( & rdi - > n_pds_lock ) ;
rdi - > n_pds_allocated = 0 ;
2016-01-22 13:01:01 -08:00
/*
* There are some things which could be set by underlying drivers but
* really should be up to rdmavt to set . For instance drivers can ' t know
* exactly which functions rdmavt supports , nor do they know the ABI
* version , so we do all of this sort of stuff here .
*/
rdi - > ibdev . uverbs_abi_ver = RVT_UVERBS_ABI_VERSION ;
rdi - > ibdev . uverbs_cmd_mask =
( 1ull < < IB_USER_VERBS_CMD_GET_CONTEXT ) |
( 1ull < < IB_USER_VERBS_CMD_QUERY_DEVICE ) |
( 1ull < < IB_USER_VERBS_CMD_QUERY_PORT ) |
( 1ull < < IB_USER_VERBS_CMD_ALLOC_PD ) |
( 1ull < < IB_USER_VERBS_CMD_DEALLOC_PD ) |
( 1ull < < IB_USER_VERBS_CMD_CREATE_AH ) |
( 1ull < < IB_USER_VERBS_CMD_MODIFY_AH ) |
( 1ull < < IB_USER_VERBS_CMD_QUERY_AH ) |
( 1ull < < IB_USER_VERBS_CMD_DESTROY_AH ) |
( 1ull < < IB_USER_VERBS_CMD_REG_MR ) |
( 1ull < < IB_USER_VERBS_CMD_DEREG_MR ) |
( 1ull < < IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL ) |
( 1ull < < IB_USER_VERBS_CMD_CREATE_CQ ) |
( 1ull < < IB_USER_VERBS_CMD_RESIZE_CQ ) |
( 1ull < < IB_USER_VERBS_CMD_DESTROY_CQ ) |
( 1ull < < IB_USER_VERBS_CMD_POLL_CQ ) |
( 1ull < < IB_USER_VERBS_CMD_REQ_NOTIFY_CQ ) |
( 1ull < < IB_USER_VERBS_CMD_CREATE_QP ) |
( 1ull < < IB_USER_VERBS_CMD_QUERY_QP ) |
( 1ull < < IB_USER_VERBS_CMD_MODIFY_QP ) |
( 1ull < < IB_USER_VERBS_CMD_DESTROY_QP ) |
( 1ull < < IB_USER_VERBS_CMD_POST_SEND ) |
( 1ull < < IB_USER_VERBS_CMD_POST_RECV ) |
( 1ull < < IB_USER_VERBS_CMD_ATTACH_MCAST ) |
( 1ull < < IB_USER_VERBS_CMD_DETACH_MCAST ) |
( 1ull < < IB_USER_VERBS_CMD_CREATE_SRQ ) |
( 1ull < < IB_USER_VERBS_CMD_MODIFY_SRQ ) |
( 1ull < < IB_USER_VERBS_CMD_QUERY_SRQ ) |
( 1ull < < IB_USER_VERBS_CMD_DESTROY_SRQ ) |
( 1ull < < IB_USER_VERBS_CMD_POST_SRQ_RECV ) ;
rdi - > ibdev . node_type = RDMA_NODE_IB_CA ;
rdi - > ibdev . num_comp_vectors = 1 ;
2016-01-06 10:03:31 -08:00
/* We are now good to announce we exist */
ret = ib_register_device ( & rdi - > ibdev , rdi - > driver_f . port_callback ) ;
if ( ret ) {
rvt_pr_err ( rdi , " Failed to register driver with ib core. \n " ) ;
2016-01-22 13:00:15 -08:00
goto bail_cq ;
2016-01-06 10:03:31 -08:00
}
2016-01-22 13:04:51 -08:00
rvt_create_mad_agents ( rdi ) ;
2016-01-06 10:02:59 -08:00
rvt_pr_info ( rdi , " Registration with rdmavt done. \n " ) ;
2016-01-06 10:03:31 -08:00
return ret ;
2016-01-06 10:02:52 -08:00
2016-01-22 13:00:15 -08:00
bail_cq :
rvt_cq_exit ( rdi ) ;
2016-01-06 10:03:31 -08:00
bail_mr :
rvt_mr_exit ( rdi ) ;
bail_no_mr :
2016-01-06 10:04:46 -08:00
rvt_qp_exit ( rdi ) ;
2016-01-06 10:03:31 -08:00
return ret ;
2016-01-06 09:50:24 -08:00
}
EXPORT_SYMBOL ( rvt_register_device ) ;
void rvt_unregister_device ( struct rvt_dev_info * rdi )
{
2016-01-22 13:00:28 -08:00
trace_rvt_dbg ( rdi , " Driver is unregistering. " ) ;
2016-01-06 09:50:24 -08:00
if ( ! rdi )
return ;
2016-01-22 13:04:51 -08:00
rvt_free_mad_agents ( rdi ) ;
2016-01-06 09:50:24 -08:00
ib_unregister_device ( & rdi - > ibdev ) ;
2016-01-22 13:00:15 -08:00
rvt_cq_exit ( rdi ) ;
2016-01-06 10:03:31 -08:00
rvt_mr_exit ( rdi ) ;
2016-01-22 12:50:17 -08:00
rvt_qp_exit ( rdi ) ;
2016-01-06 09:50:24 -08:00
}
EXPORT_SYMBOL ( rvt_unregister_device ) ;
2016-01-06 10:04:13 -08:00
/*
* Keep track of a list of ports . No need to have a detach port .
* They persist until the driver goes away .
*/
2016-01-06 10:05:12 -08:00
int rvt_init_port ( struct rvt_dev_info * rdi , struct rvt_ibport * port ,
int portnum , u16 * pkey_table )
2016-01-06 10:04:13 -08:00
{
2016-01-06 10:05:12 -08:00
2016-01-06 10:04:13 -08:00
rdi - > ports [ portnum ] = port ;
2016-01-06 10:05:12 -08:00
rdi - > ports [ portnum ] - > pkey_table = pkey_table ;
return 0 ;
2016-01-06 10:04:13 -08:00
}
2016-01-06 10:05:12 -08:00
EXPORT_SYMBOL ( rvt_init_port ) ;