2007-05-08 18:00:38 -07:00
/*
* Copyright ( c ) 2007 Cisco Systems , Inc . All rights reserved .
*
* 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 <rdma/ib_cache.h>
# include <rdma/ib_pack.h>
# include <linux/mlx4/qp.h>
# include "mlx4_ib.h"
# include "user.h"
enum {
MLX4_IB_ACK_REQ_FREQ = 8 ,
} ;
enum {
MLX4_IB_DEFAULT_SCHED_QUEUE = 0x83 ,
MLX4_IB_DEFAULT_QP0_SCHED_QUEUE = 0x3f
} ;
enum {
/*
* Largest possible UD header : send with GRH and immediate data .
*/
MLX4_IB_UD_HEADER_SIZE = 72
} ;
struct mlx4_ib_sqp {
struct mlx4_ib_qp qp ;
int pkey_index ;
u32 qkey ;
u32 send_psn ;
struct ib_ud_header ud_header ;
u8 header_buf [ MLX4_IB_UD_HEADER_SIZE ] ;
} ;
static const __be32 mlx4_ib_opcode [ ] = {
[ IB_WR_SEND ] = __constant_cpu_to_be32 ( MLX4_OPCODE_SEND ) ,
[ IB_WR_SEND_WITH_IMM ] = __constant_cpu_to_be32 ( MLX4_OPCODE_SEND_IMM ) ,
[ IB_WR_RDMA_WRITE ] = __constant_cpu_to_be32 ( MLX4_OPCODE_RDMA_WRITE ) ,
[ IB_WR_RDMA_WRITE_WITH_IMM ] = __constant_cpu_to_be32 ( MLX4_OPCODE_RDMA_WRITE_IMM ) ,
[ IB_WR_RDMA_READ ] = __constant_cpu_to_be32 ( MLX4_OPCODE_RDMA_READ ) ,
[ IB_WR_ATOMIC_CMP_AND_SWP ] = __constant_cpu_to_be32 ( MLX4_OPCODE_ATOMIC_CS ) ,
[ IB_WR_ATOMIC_FETCH_AND_ADD ] = __constant_cpu_to_be32 ( MLX4_OPCODE_ATOMIC_FA ) ,
} ;
static struct mlx4_ib_sqp * to_msqp ( struct mlx4_ib_qp * mqp )
{
return container_of ( mqp , struct mlx4_ib_sqp , qp ) ;
}
static int is_sqp ( struct mlx4_ib_dev * dev , struct mlx4_ib_qp * qp )
{
return qp - > mqp . qpn > = dev - > dev - > caps . sqp_start & &
qp - > mqp . qpn < = dev - > dev - > caps . sqp_start + 3 ;
}
static int is_qp0 ( struct mlx4_ib_dev * dev , struct mlx4_ib_qp * qp )
{
return qp - > mqp . qpn > = dev - > dev - > caps . sqp_start & &
qp - > mqp . qpn < = dev - > dev - > caps . sqp_start + 1 ;
}
static void * get_wqe ( struct mlx4_ib_qp * qp , int offset )
{
if ( qp - > buf . nbufs = = 1 )
return qp - > buf . u . direct . buf + offset ;
else
return qp - > buf . u . page_list [ offset > > PAGE_SHIFT ] . buf +
( offset & ( PAGE_SIZE - 1 ) ) ;
}
static void * get_recv_wqe ( struct mlx4_ib_qp * qp , int n )
{
return get_wqe ( qp , qp - > rq . offset + ( n < < qp - > rq . wqe_shift ) ) ;
}
static void * get_send_wqe ( struct mlx4_ib_qp * qp , int n )
{
return get_wqe ( qp , qp - > sq . offset + ( n < < qp - > sq . wqe_shift ) ) ;
}
static void mlx4_ib_qp_event ( struct mlx4_qp * qp , enum mlx4_event type )
{
struct ib_event event ;
struct ib_qp * ibqp = & to_mibqp ( qp ) - > ibqp ;
if ( type = = MLX4_EVENT_TYPE_PATH_MIG )
to_mibqp ( qp ) - > port = to_mibqp ( qp ) - > alt_port ;
if ( ibqp - > event_handler ) {
event . device = ibqp - > device ;
event . element . qp = ibqp ;
switch ( type ) {
case MLX4_EVENT_TYPE_PATH_MIG :
event . event = IB_EVENT_PATH_MIG ;
break ;
case MLX4_EVENT_TYPE_COMM_EST :
event . event = IB_EVENT_COMM_EST ;
break ;
case MLX4_EVENT_TYPE_SQ_DRAINED :
event . event = IB_EVENT_SQ_DRAINED ;
break ;
case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE :
event . event = IB_EVENT_QP_LAST_WQE_REACHED ;
break ;
case MLX4_EVENT_TYPE_WQ_CATAS_ERROR :
event . event = IB_EVENT_QP_FATAL ;
break ;
case MLX4_EVENT_TYPE_PATH_MIG_FAILED :
event . event = IB_EVENT_PATH_MIG_ERR ;
break ;
case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR :
event . event = IB_EVENT_QP_REQ_ERR ;
break ;
case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR :
event . event = IB_EVENT_QP_ACCESS_ERR ;
break ;
default :
printk ( KERN_WARNING " mlx4_ib: Unexpected event type %d "
" on QP %06x \n " , type , qp - > qpn ) ;
return ;
}
ibqp - > event_handler ( & event , ibqp - > qp_context ) ;
}
}
static int send_wqe_overhead ( enum ib_qp_type type )
{
/*
* UD WQEs must have a datagram segment .
* RC and UC WQEs might have a remote address segment .
* MLX WQEs need two extra inline data segments ( for the UD
* header and space for the ICRC ) .
*/
switch ( type ) {
case IB_QPT_UD :
return sizeof ( struct mlx4_wqe_ctrl_seg ) +
sizeof ( struct mlx4_wqe_datagram_seg ) ;
case IB_QPT_UC :
return sizeof ( struct mlx4_wqe_ctrl_seg ) +
sizeof ( struct mlx4_wqe_raddr_seg ) ;
case IB_QPT_RC :
return sizeof ( struct mlx4_wqe_ctrl_seg ) +
sizeof ( struct mlx4_wqe_atomic_seg ) +
sizeof ( struct mlx4_wqe_raddr_seg ) ;
case IB_QPT_SMI :
case IB_QPT_GSI :
return sizeof ( struct mlx4_wqe_ctrl_seg ) +
ALIGN ( MLX4_IB_UD_HEADER_SIZE +
sizeof ( struct mlx4_wqe_inline_seg ) ,
sizeof ( struct mlx4_wqe_data_seg ) ) +
ALIGN ( 4 +
sizeof ( struct mlx4_wqe_inline_seg ) ,
sizeof ( struct mlx4_wqe_data_seg ) ) ;
default :
return sizeof ( struct mlx4_wqe_ctrl_seg ) ;
}
}
static int set_qp_size ( struct mlx4_ib_dev * dev , struct ib_qp_cap * cap ,
enum ib_qp_type type , struct mlx4_ib_qp * qp )
{
/* Sanity check QP size before proceeding */
if ( cap - > max_send_wr > dev - > dev - > caps . max_wqes | |
cap - > max_recv_wr > dev - > dev - > caps . max_wqes | |
cap - > max_send_sge > dev - > dev - > caps . max_sq_sg | |
cap - > max_recv_sge > dev - > dev - > caps . max_rq_sg | |
cap - > max_inline_data + send_wqe_overhead ( type ) +
sizeof ( struct mlx4_wqe_inline_seg ) > dev - > dev - > caps . max_sq_desc_sz )
return - EINVAL ;
/*
* For MLX transport we need 2 extra S / G entries :
* one for the header and one for the checksum at the end
*/
if ( ( type = = IB_QPT_SMI | | type = = IB_QPT_GSI ) & &
cap - > max_send_sge + 2 > dev - > dev - > caps . max_sq_sg )
return - EINVAL ;
qp - > rq . max = cap - > max_recv_wr ? roundup_pow_of_two ( cap - > max_recv_wr ) : 0 ;
qp - > sq . max = cap - > max_send_wr ? roundup_pow_of_two ( cap - > max_send_wr ) : 0 ;
qp - > rq . wqe_shift = ilog2 ( roundup_pow_of_two ( cap - > max_recv_sge *
sizeof ( struct mlx4_wqe_data_seg ) ) ) ;
qp - > rq . max_gs = ( 1 < < qp - > rq . wqe_shift ) / sizeof ( struct mlx4_wqe_data_seg ) ;
qp - > sq . wqe_shift = ilog2 ( roundup_pow_of_two ( max ( cap - > max_send_sge *
sizeof ( struct mlx4_wqe_data_seg ) ,
cap - > max_inline_data +
sizeof ( struct mlx4_wqe_inline_seg ) ) +
send_wqe_overhead ( type ) ) ) ;
qp - > sq . max_gs = ( ( 1 < < qp - > sq . wqe_shift ) - send_wqe_overhead ( type ) ) /
sizeof ( struct mlx4_wqe_data_seg ) ;
qp - > buf_size = ( qp - > rq . max < < qp - > rq . wqe_shift ) +
( qp - > sq . max < < qp - > sq . wqe_shift ) ;
if ( qp - > rq . wqe_shift > qp - > sq . wqe_shift ) {
qp - > rq . offset = 0 ;
qp - > sq . offset = qp - > rq . max < < qp - > rq . wqe_shift ;
} else {
qp - > rq . offset = qp - > sq . max < < qp - > sq . wqe_shift ;
qp - > sq . offset = 0 ;
}
cap - > max_send_wr = qp - > sq . max ;
cap - > max_recv_wr = qp - > rq . max ;
cap - > max_send_sge = qp - > sq . max_gs ;
cap - > max_recv_sge = qp - > rq . max_gs ;
cap - > max_inline_data = ( 1 < < qp - > sq . wqe_shift ) - send_wqe_overhead ( type ) -
sizeof ( struct mlx4_wqe_inline_seg ) ;
return 0 ;
}
static int create_qp_common ( struct mlx4_ib_dev * dev , struct ib_pd * pd ,
struct ib_qp_init_attr * init_attr ,
struct ib_udata * udata , int sqpn , struct mlx4_ib_qp * qp )
{
struct mlx4_wqe_ctrl_seg * ctrl ;
int err ;
int i ;
mutex_init ( & qp - > mutex ) ;
spin_lock_init ( & qp - > sq . lock ) ;
spin_lock_init ( & qp - > rq . lock ) ;
qp - > state = IB_QPS_RESET ;
qp - > atomic_rd_en = 0 ;
qp - > resp_depth = 0 ;
qp - > rq . head = 0 ;
qp - > rq . tail = 0 ;
qp - > sq . head = 0 ;
qp - > sq . tail = 0 ;
err = set_qp_size ( dev , & init_attr - > cap , init_attr - > qp_type , qp ) ;
if ( err )
goto err ;
if ( pd - > uobject ) {
struct mlx4_ib_create_qp ucmd ;
if ( ib_copy_from_udata ( & ucmd , udata , sizeof ucmd ) ) {
err = - EFAULT ;
goto err ;
}
qp - > umem = ib_umem_get ( pd - > uobject - > context , ucmd . buf_addr ,
qp - > buf_size , 0 ) ;
if ( IS_ERR ( qp - > umem ) ) {
err = PTR_ERR ( qp - > umem ) ;
goto err ;
}
err = mlx4_mtt_init ( dev - > dev , ib_umem_page_count ( qp - > umem ) ,
ilog2 ( qp - > umem - > page_size ) , & qp - > mtt ) ;
if ( err )
goto err_buf ;
err = mlx4_ib_umem_write_mtt ( dev , & qp - > mtt , qp - > umem ) ;
if ( err )
goto err_mtt ;
err = mlx4_ib_db_map_user ( to_mucontext ( pd - > uobject - > context ) ,
ucmd . db_addr , & qp - > db ) ;
if ( err )
goto err_mtt ;
} else {
err = mlx4_ib_db_alloc ( dev , & qp - > db , 0 ) ;
if ( err )
goto err ;
* qp - > db . db = 0 ;
if ( mlx4_buf_alloc ( dev - > dev , qp - > buf_size , PAGE_SIZE * 2 , & qp - > buf ) ) {
err = - ENOMEM ;
goto err_db ;
}
err = mlx4_mtt_init ( dev - > dev , qp - > buf . npages , qp - > buf . page_shift ,
& qp - > mtt ) ;
if ( err )
goto err_buf ;
err = mlx4_buf_write_mtt ( dev - > dev , & qp - > mtt , & qp - > buf ) ;
if ( err )
goto err_mtt ;
for ( i = 0 ; i < qp - > sq . max ; + + i ) {
ctrl = get_send_wqe ( qp , i ) ;
ctrl - > owner_opcode = cpu_to_be32 ( 1 < < 31 ) ;
}
qp - > sq . wrid = kmalloc ( qp - > sq . max * sizeof ( u64 ) , GFP_KERNEL ) ;
qp - > rq . wrid = kmalloc ( qp - > rq . max * sizeof ( u64 ) , GFP_KERNEL ) ;
if ( ! qp - > sq . wrid | | ! qp - > rq . wrid ) {
err = - ENOMEM ;
goto err_wrid ;
}
/* We don't support inline sends for kernel QPs (yet) */
init_attr - > cap . max_inline_data = 0 ;
}
err = mlx4_qp_alloc ( dev - > dev , sqpn , & qp - > mqp ) ;
if ( err )
goto err_wrid ;
/*
* Hardware wants QPN written in big - endian order ( after
* shifting ) for send doorbell . Precompute this value to save
* a little bit when posting sends .
*/
qp - > doorbell_qpn = swab32 ( qp - > mqp . qpn < < 8 ) ;
if ( init_attr - > sq_sig_type = = IB_SIGNAL_ALL_WR )
qp - > sq_signal_bits = cpu_to_be32 ( MLX4_WQE_CTRL_CQ_UPDATE ) ;
else
qp - > sq_signal_bits = 0 ;
qp - > mqp . event = mlx4_ib_qp_event ;
return 0 ;
err_wrid :
if ( pd - > uobject )
mlx4_ib_db_unmap_user ( to_mucontext ( pd - > uobject - > context ) , & qp - > db ) ;
else {
kfree ( qp - > sq . wrid ) ;
kfree ( qp - > rq . wrid ) ;
}
err_mtt :
mlx4_mtt_cleanup ( dev - > dev , & qp - > mtt ) ;
err_buf :
if ( pd - > uobject )
ib_umem_release ( qp - > umem ) ;
else
mlx4_buf_free ( dev - > dev , qp - > buf_size , & qp - > buf ) ;
err_db :
if ( ! pd - > uobject )
mlx4_ib_db_free ( dev , & qp - > db ) ;
err :
return err ;
}
static enum mlx4_qp_state to_mlx4_state ( enum ib_qp_state state )
{
switch ( state ) {
case IB_QPS_RESET : return MLX4_QP_STATE_RST ;
case IB_QPS_INIT : return MLX4_QP_STATE_INIT ;
case IB_QPS_RTR : return MLX4_QP_STATE_RTR ;
case IB_QPS_RTS : return MLX4_QP_STATE_RTS ;
case IB_QPS_SQD : return MLX4_QP_STATE_SQD ;
case IB_QPS_SQE : return MLX4_QP_STATE_SQER ;
case IB_QPS_ERR : return MLX4_QP_STATE_ERR ;
default : return - 1 ;
}
}
static void mlx4_ib_lock_cqs ( struct mlx4_ib_cq * send_cq , struct mlx4_ib_cq * recv_cq )
{
if ( send_cq = = recv_cq )
spin_lock_irq ( & send_cq - > lock ) ;
else if ( send_cq - > mcq . cqn < recv_cq - > mcq . cqn ) {
spin_lock_irq ( & send_cq - > lock ) ;
spin_lock_nested ( & recv_cq - > lock , SINGLE_DEPTH_NESTING ) ;
} else {
spin_lock_irq ( & recv_cq - > lock ) ;
spin_lock_nested ( & send_cq - > lock , SINGLE_DEPTH_NESTING ) ;
}
}
static void mlx4_ib_unlock_cqs ( struct mlx4_ib_cq * send_cq , struct mlx4_ib_cq * recv_cq )
{
if ( send_cq = = recv_cq )
spin_unlock_irq ( & send_cq - > lock ) ;
else if ( send_cq - > mcq . cqn < recv_cq - > mcq . cqn ) {
spin_unlock ( & recv_cq - > lock ) ;
spin_unlock_irq ( & send_cq - > lock ) ;
} else {
spin_unlock ( & send_cq - > lock ) ;
spin_unlock_irq ( & recv_cq - > lock ) ;
}
}
static void destroy_qp_common ( struct mlx4_ib_dev * dev , struct mlx4_ib_qp * qp ,
int is_user )
{
struct mlx4_ib_cq * send_cq , * recv_cq ;
if ( qp - > state ! = IB_QPS_RESET )
if ( mlx4_qp_modify ( dev - > dev , NULL , to_mlx4_state ( qp - > state ) ,
MLX4_QP_STATE_RST , NULL , 0 , 0 , & qp - > mqp ) )
printk ( KERN_WARNING " mlx4_ib: modify QP %06x to RESET failed. \n " ,
qp - > mqp . qpn ) ;
send_cq = to_mcq ( qp - > ibqp . send_cq ) ;
recv_cq = to_mcq ( qp - > ibqp . recv_cq ) ;
mlx4_ib_lock_cqs ( send_cq , recv_cq ) ;
if ( ! is_user ) {
__mlx4_ib_cq_clean ( recv_cq , qp - > mqp . qpn ,
qp - > ibqp . srq ? to_msrq ( qp - > ibqp . srq ) : NULL ) ;
if ( send_cq ! = recv_cq )
__mlx4_ib_cq_clean ( send_cq , qp - > mqp . qpn , NULL ) ;
}
mlx4_qp_remove ( dev - > dev , & qp - > mqp ) ;
mlx4_ib_unlock_cqs ( send_cq , recv_cq ) ;
mlx4_qp_free ( dev - > dev , & qp - > mqp ) ;
mlx4_mtt_cleanup ( dev - > dev , & qp - > mtt ) ;
if ( is_user ) {
mlx4_ib_db_unmap_user ( to_mucontext ( qp - > ibqp . uobject - > context ) ,
& qp - > db ) ;
ib_umem_release ( qp - > umem ) ;
} else {
kfree ( qp - > sq . wrid ) ;
kfree ( qp - > rq . wrid ) ;
mlx4_buf_free ( dev - > dev , qp - > buf_size , & qp - > buf ) ;
mlx4_ib_db_free ( dev , & qp - > db ) ;
}
}
struct ib_qp * mlx4_ib_create_qp ( struct ib_pd * pd ,
struct ib_qp_init_attr * init_attr ,
struct ib_udata * udata )
{
struct mlx4_ib_dev * dev = to_mdev ( pd - > device ) ;
struct mlx4_ib_sqp * sqp ;
struct mlx4_ib_qp * qp ;
int err ;
switch ( init_attr - > qp_type ) {
case IB_QPT_RC :
case IB_QPT_UC :
case IB_QPT_UD :
{
qp = kmalloc ( sizeof * qp , GFP_KERNEL ) ;
if ( ! qp )
return ERR_PTR ( - ENOMEM ) ;
err = create_qp_common ( dev , pd , init_attr , udata , 0 , qp ) ;
if ( err ) {
kfree ( qp ) ;
return ERR_PTR ( err ) ;
}
qp - > ibqp . qp_num = qp - > mqp . qpn ;
break ;
}
case IB_QPT_SMI :
case IB_QPT_GSI :
{
/* Userspace is not allowed to create special QPs: */
if ( pd - > uobject )
return ERR_PTR ( - EINVAL ) ;
sqp = kmalloc ( sizeof * sqp , GFP_KERNEL ) ;
if ( ! sqp )
return ERR_PTR ( - ENOMEM ) ;
qp = & sqp - > qp ;
err = create_qp_common ( dev , pd , init_attr , udata ,
dev - > dev - > caps . sqp_start +
( init_attr - > qp_type = = IB_QPT_SMI ? 0 : 2 ) +
init_attr - > port_num - 1 ,
qp ) ;
if ( err ) {
kfree ( sqp ) ;
return ERR_PTR ( err ) ;
}
qp - > port = init_attr - > port_num ;
qp - > ibqp . qp_num = init_attr - > qp_type = = IB_QPT_SMI ? 0 : 1 ;
break ;
}
default :
/* Don't support raw QPs */
return ERR_PTR ( - EINVAL ) ;
}
return & qp - > ibqp ;
}
int mlx4_ib_destroy_qp ( struct ib_qp * qp )
{
struct mlx4_ib_dev * dev = to_mdev ( qp - > device ) ;
struct mlx4_ib_qp * mqp = to_mqp ( qp ) ;
if ( is_qp0 ( dev , mqp ) )
mlx4_CLOSE_PORT ( dev - > dev , mqp - > port ) ;
destroy_qp_common ( dev , mqp , ! ! qp - > pd - > uobject ) ;
if ( is_sqp ( dev , mqp ) )
kfree ( to_msqp ( mqp ) ) ;
else
kfree ( mqp ) ;
return 0 ;
}
static void init_port ( struct mlx4_ib_dev * dev , int port )
{
struct mlx4_init_port_param param ;
int err ;
memset ( & param , 0 , sizeof param ) ;
param . port_width_cap = dev - > dev - > caps . port_width_cap ;
param . vl_cap = dev - > dev - > caps . vl_cap ;
param . mtu = ib_mtu_enum_to_int ( dev - > dev - > caps . mtu_cap ) ;
param . max_gid = dev - > dev - > caps . gid_table_len ;
param . max_pkey = dev - > dev - > caps . pkey_table_len ;
err = mlx4_INIT_PORT ( dev - > dev , & param , port ) ;
if ( err )
printk ( KERN_WARNING " INIT_PORT failed, return code %d. \n " , err ) ;
}
static int to_mlx4_st ( enum ib_qp_type type )
{
switch ( type ) {
case IB_QPT_RC : return MLX4_QP_ST_RC ;
case IB_QPT_UC : return MLX4_QP_ST_UC ;
case IB_QPT_UD : return MLX4_QP_ST_UD ;
case IB_QPT_SMI :
case IB_QPT_GSI : return MLX4_QP_ST_MLX ;
default : return - 1 ;
}
}
static __be32 to_mlx4_access_flags ( struct mlx4_ib_qp * qp , struct ib_qp_attr * attr ,
int attr_mask )
{
u8 dest_rd_atomic ;
u32 access_flags ;
u32 hw_access_flags = 0 ;
if ( attr_mask & IB_QP_MAX_DEST_RD_ATOMIC )
dest_rd_atomic = attr - > max_dest_rd_atomic ;
else
dest_rd_atomic = qp - > resp_depth ;
if ( attr_mask & IB_QP_ACCESS_FLAGS )
access_flags = attr - > qp_access_flags ;
else
access_flags = qp - > atomic_rd_en ;
if ( ! dest_rd_atomic )
access_flags & = IB_ACCESS_REMOTE_WRITE ;
if ( access_flags & IB_ACCESS_REMOTE_READ )
hw_access_flags | = MLX4_QP_BIT_RRE ;
if ( access_flags & IB_ACCESS_REMOTE_ATOMIC )
hw_access_flags | = MLX4_QP_BIT_RAE ;
if ( access_flags & IB_ACCESS_REMOTE_WRITE )
hw_access_flags | = MLX4_QP_BIT_RWE ;
return cpu_to_be32 ( hw_access_flags ) ;
}
static void store_sqp_attrs ( struct mlx4_ib_sqp * sqp , struct ib_qp_attr * attr ,
int attr_mask )
{
if ( attr_mask & IB_QP_PKEY_INDEX )
sqp - > pkey_index = attr - > pkey_index ;
if ( attr_mask & IB_QP_QKEY )
sqp - > qkey = attr - > qkey ;
if ( attr_mask & IB_QP_SQ_PSN )
sqp - > send_psn = attr - > sq_psn ;
}
static void mlx4_set_sched ( struct mlx4_qp_path * path , u8 port )
{
path - > sched_queue = ( path - > sched_queue & 0xbf ) | ( ( port - 1 ) < < 6 ) ;
}
static int mlx4_set_path ( struct mlx4_ib_dev * dev , struct ib_ah_attr * ah ,
struct mlx4_qp_path * path , u8 port )
{
path - > grh_mylmc = ah - > src_path_bits & 0x7f ;
path - > rlid = cpu_to_be16 ( ah - > dlid ) ;
if ( ah - > static_rate ) {
path - > static_rate = ah - > static_rate + MLX4_STAT_RATE_OFFSET ;
while ( path - > static_rate > IB_RATE_2_5_GBPS + MLX4_STAT_RATE_OFFSET & &
! ( 1 < < path - > static_rate & dev - > dev - > caps . stat_rate_support ) )
- - path - > static_rate ;
} else
path - > static_rate = 0 ;
path - > counter_index = 0xff ;
if ( ah - > ah_flags & IB_AH_GRH ) {
if ( ah - > grh . sgid_index > = dev - > dev - > caps . gid_table_len ) {
printk ( KERN_ERR " sgid_index (%u) too large. max is %d \n " ,
ah - > grh . sgid_index , dev - > dev - > caps . gid_table_len - 1 ) ;
return - 1 ;
}
path - > grh_mylmc | = 1 < < 7 ;
path - > mgid_index = ah - > grh . sgid_index ;
path - > hop_limit = ah - > grh . hop_limit ;
path - > tclass_flowlabel =
cpu_to_be32 ( ( ah - > grh . traffic_class < < 20 ) |
( ah - > grh . flow_label ) ) ;
memcpy ( path - > rgid , ah - > grh . dgid . raw , 16 ) ;
}
path - > sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
( ( port - 1 ) < < 6 ) | ( ( ah - > sl & 0xf ) < < 2 ) ;
return 0 ;
}
int mlx4_ib_modify_qp ( struct ib_qp * ibqp , struct ib_qp_attr * attr ,
int attr_mask , struct ib_udata * udata )
{
struct mlx4_ib_dev * dev = to_mdev ( ibqp - > device ) ;
struct mlx4_ib_qp * qp = to_mqp ( ibqp ) ;
struct mlx4_qp_context * context ;
enum mlx4_qp_optpar optpar = 0 ;
enum ib_qp_state cur_state , new_state ;
int sqd_event ;
int err = - EINVAL ;
context = kzalloc ( sizeof * context , GFP_KERNEL ) ;
if ( ! context )
return - ENOMEM ;
mutex_lock ( & qp - > mutex ) ;
cur_state = attr_mask & IB_QP_CUR_STATE ? attr - > cur_qp_state : qp - > state ;
new_state = attr_mask & IB_QP_STATE ? attr - > qp_state : cur_state ;
if ( ! ib_modify_qp_is_ok ( cur_state , new_state , ibqp - > qp_type , attr_mask ) )
goto out ;
if ( ( attr_mask & IB_QP_PKEY_INDEX ) & &
attr - > pkey_index > = dev - > dev - > caps . pkey_table_len ) {
goto out ;
}
if ( ( attr_mask & IB_QP_PORT ) & &
( attr - > port_num = = 0 | | attr - > port_num > dev - > dev - > caps . num_ports ) ) {
goto out ;
}
if ( attr_mask & IB_QP_MAX_QP_RD_ATOMIC & &
attr - > max_rd_atomic > dev - > dev - > caps . max_qp_init_rdma ) {
goto out ;
}
if ( attr_mask & IB_QP_MAX_DEST_RD_ATOMIC & &
2007-05-17 16:32:39 +03:00
attr - > max_dest_rd_atomic > dev - > dev - > caps . max_qp_dest_rdma ) {
2007-05-08 18:00:38 -07:00
goto out ;
}
context - > flags = cpu_to_be32 ( ( to_mlx4_state ( new_state ) < < 28 ) |
( to_mlx4_st ( ibqp - > qp_type ) < < 16 ) ) ;
context - > flags | = cpu_to_be32 ( 1 < < 8 ) ; /* DE? */
if ( ! ( attr_mask & IB_QP_PATH_MIG_STATE ) )
context - > flags | = cpu_to_be32 ( MLX4_QP_PM_MIGRATED < < 11 ) ;
else {
optpar | = MLX4_QP_OPTPAR_PM_STATE ;
switch ( attr - > path_mig_state ) {
case IB_MIG_MIGRATED :
context - > flags | = cpu_to_be32 ( MLX4_QP_PM_MIGRATED < < 11 ) ;
break ;
case IB_MIG_REARM :
context - > flags | = cpu_to_be32 ( MLX4_QP_PM_REARM < < 11 ) ;
break ;
case IB_MIG_ARMED :
context - > flags | = cpu_to_be32 ( MLX4_QP_PM_ARMED < < 11 ) ;
break ;
}
}
if ( ibqp - > qp_type = = IB_QPT_GSI | | ibqp - > qp_type = = IB_QPT_SMI | |
ibqp - > qp_type = = IB_QPT_UD )
context - > mtu_msgmax = ( IB_MTU_4096 < < 5 ) | 11 ;
else if ( attr_mask & IB_QP_PATH_MTU ) {
if ( attr - > path_mtu < IB_MTU_256 | | attr - > path_mtu > IB_MTU_4096 ) {
printk ( KERN_ERR " path MTU (%u) is invalid \n " ,
attr - > path_mtu ) ;
return - EINVAL ;
}
context - > mtu_msgmax = ( attr - > path_mtu < < 5 ) | 31 ;
}
if ( qp - > rq . max )
context - > rq_size_stride = ilog2 ( qp - > rq . max ) < < 3 ;
context - > rq_size_stride | = qp - > rq . wqe_shift - 4 ;
if ( qp - > sq . max )
context - > sq_size_stride = ilog2 ( qp - > sq . max ) < < 3 ;
context - > sq_size_stride | = qp - > sq . wqe_shift - 4 ;
if ( qp - > ibqp . uobject )
context - > usr_page = cpu_to_be32 ( to_mucontext ( ibqp - > uobject - > context ) - > uar . index ) ;
else
context - > usr_page = cpu_to_be32 ( dev - > priv_uar . index ) ;
if ( attr_mask & IB_QP_DEST_QPN )
context - > remote_qpn = cpu_to_be32 ( attr - > dest_qp_num ) ;
if ( attr_mask & IB_QP_PORT ) {
if ( cur_state = = IB_QPS_SQD & & new_state = = IB_QPS_SQD & &
! ( attr_mask & IB_QP_AV ) ) {
mlx4_set_sched ( & context - > pri_path , attr - > port_num ) ;
optpar | = MLX4_QP_OPTPAR_SCHED_QUEUE ;
}
}
if ( attr_mask & IB_QP_PKEY_INDEX ) {
context - > pri_path . pkey_index = attr - > pkey_index ;
optpar | = MLX4_QP_OPTPAR_PKEY_INDEX ;
}
if ( attr_mask & IB_QP_RNR_RETRY ) {
context - > params1 | = cpu_to_be32 ( attr - > rnr_retry < < 13 ) ;
optpar | = MLX4_QP_OPTPAR_RNR_RETRY ;
}
if ( attr_mask & IB_QP_AV ) {
if ( mlx4_set_path ( dev , & attr - > ah_attr , & context - > pri_path ,
attr_mask & IB_QP_PORT ? attr - > port_num : qp - > port ) ) {
err = - EINVAL ;
goto out ;
}
optpar | = ( MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH |
MLX4_QP_OPTPAR_SCHED_QUEUE ) ;
}
if ( attr_mask & IB_QP_TIMEOUT ) {
context - > pri_path . ackto = attr - > timeout < < 3 ;
optpar | = MLX4_QP_OPTPAR_ACK_TIMEOUT ;
}
if ( attr_mask & IB_QP_ALT_PATH ) {
if ( attr - > alt_pkey_index > = dev - > dev - > caps . pkey_table_len )
return - EINVAL ;
if ( attr - > alt_port_num = = 0 | |
attr - > alt_port_num > dev - > dev - > caps . num_ports )
return - EINVAL ;
if ( mlx4_set_path ( dev , & attr - > alt_ah_attr , & context - > alt_path ,
attr - > alt_port_num ) )
return - EINVAL ;
context - > alt_path . pkey_index = attr - > alt_pkey_index ;
context - > alt_path . ackto = attr - > alt_timeout < < 3 ;
optpar | = MLX4_QP_OPTPAR_ALT_ADDR_PATH ;
}
context - > pd = cpu_to_be32 ( to_mpd ( ibqp - > pd ) - > pdn ) ;
context - > params1 = cpu_to_be32 ( MLX4_IB_ACK_REQ_FREQ < < 28 ) ;
if ( attr_mask & IB_QP_RETRY_CNT ) {
context - > params1 | = cpu_to_be32 ( attr - > retry_cnt < < 16 ) ;
optpar | = MLX4_QP_OPTPAR_RETRY_COUNT ;
}
if ( attr_mask & IB_QP_MAX_QP_RD_ATOMIC ) {
if ( attr - > max_rd_atomic )
context - > params1 | =
cpu_to_be32 ( fls ( attr - > max_rd_atomic - 1 ) < < 21 ) ;
optpar | = MLX4_QP_OPTPAR_SRA_MAX ;
}
if ( attr_mask & IB_QP_SQ_PSN )
context - > next_send_psn = cpu_to_be32 ( attr - > sq_psn ) ;
context - > cqn_send = cpu_to_be32 ( to_mcq ( ibqp - > send_cq ) - > mcq . cqn ) ;
if ( attr_mask & IB_QP_MAX_DEST_RD_ATOMIC ) {
if ( attr - > max_dest_rd_atomic )
context - > params2 | =
cpu_to_be32 ( fls ( attr - > max_dest_rd_atomic - 1 ) < < 21 ) ;
optpar | = MLX4_QP_OPTPAR_RRA_MAX ;
}
if ( attr_mask & ( IB_QP_ACCESS_FLAGS | IB_QP_MAX_DEST_RD_ATOMIC ) ) {
context - > params2 | = to_mlx4_access_flags ( qp , attr , attr_mask ) ;
optpar | = MLX4_QP_OPTPAR_RWE | MLX4_QP_OPTPAR_RRE | MLX4_QP_OPTPAR_RAE ;
}
if ( ibqp - > srq )
context - > params2 | = cpu_to_be32 ( MLX4_QP_BIT_RIC ) ;
if ( attr_mask & IB_QP_MIN_RNR_TIMER ) {
context - > rnr_nextrecvpsn | = cpu_to_be32 ( attr - > min_rnr_timer < < 24 ) ;
optpar | = MLX4_QP_OPTPAR_RNR_TIMEOUT ;
}
if ( attr_mask & IB_QP_RQ_PSN )
context - > rnr_nextrecvpsn | = cpu_to_be32 ( attr - > rq_psn ) ;
context - > cqn_recv = cpu_to_be32 ( to_mcq ( ibqp - > recv_cq ) - > mcq . cqn ) ;
if ( attr_mask & IB_QP_QKEY ) {
context - > qkey = cpu_to_be32 ( attr - > qkey ) ;
optpar | = MLX4_QP_OPTPAR_Q_KEY ;
}
if ( ibqp - > srq )
context - > srqn = cpu_to_be32 ( 1 < < 24 | to_msrq ( ibqp - > srq ) - > msrq . srqn ) ;
if ( cur_state = = IB_QPS_RESET & & new_state = = IB_QPS_INIT )
context - > db_rec_addr = cpu_to_be64 ( qp - > db . dma ) ;
if ( cur_state = = IB_QPS_INIT & &
new_state = = IB_QPS_RTR & &
( ibqp - > qp_type = = IB_QPT_GSI | | ibqp - > qp_type = = IB_QPT_SMI | |
ibqp - > qp_type = = IB_QPT_UD ) ) {
context - > pri_path . sched_queue = ( qp - > port - 1 ) < < 6 ;
if ( is_qp0 ( dev , qp ) )
context - > pri_path . sched_queue | = MLX4_IB_DEFAULT_QP0_SCHED_QUEUE ;
else
context - > pri_path . sched_queue | = MLX4_IB_DEFAULT_SCHED_QUEUE ;
}
if ( cur_state = = IB_QPS_RTS & & new_state = = IB_QPS_SQD & &
attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY & & attr - > en_sqd_async_notify )
sqd_event = 1 ;
else
sqd_event = 0 ;
err = mlx4_qp_modify ( dev - > dev , & qp - > mtt , to_mlx4_state ( cur_state ) ,
to_mlx4_state ( new_state ) , context , optpar ,
sqd_event , & qp - > mqp ) ;
if ( err )
goto out ;
qp - > state = new_state ;
if ( attr_mask & IB_QP_ACCESS_FLAGS )
qp - > atomic_rd_en = attr - > qp_access_flags ;
if ( attr_mask & IB_QP_MAX_DEST_RD_ATOMIC )
qp - > resp_depth = attr - > max_dest_rd_atomic ;
if ( attr_mask & IB_QP_PORT )
qp - > port = attr - > port_num ;
if ( attr_mask & IB_QP_ALT_PATH )
qp - > alt_port = attr - > alt_port_num ;
if ( is_sqp ( dev , qp ) )
store_sqp_attrs ( to_msqp ( qp ) , attr , attr_mask ) ;
/*
* If we moved QP0 to RTR , bring the IB link up ; if we moved
* QP0 to RESET or ERROR , bring the link back down .
*/
if ( is_qp0 ( dev , qp ) ) {
if ( cur_state ! = IB_QPS_RTR & & new_state = = IB_QPS_RTR )
init_port ( dev , qp - > port ) ;
if ( cur_state ! = IB_QPS_RESET & & cur_state ! = IB_QPS_ERR & &
( new_state = = IB_QPS_RESET | | new_state = = IB_QPS_ERR ) )
mlx4_CLOSE_PORT ( dev - > dev , qp - > port ) ;
}
/*
* If we moved a kernel QP to RESET , clean up all old CQ
* entries and reinitialize the QP .
*/
if ( new_state = = IB_QPS_RESET & & ! ibqp - > uobject ) {
mlx4_ib_cq_clean ( to_mcq ( ibqp - > recv_cq ) , qp - > mqp . qpn ,
ibqp - > srq ? to_msrq ( ibqp - > srq ) : NULL ) ;
if ( ibqp - > send_cq ! = ibqp - > recv_cq )
mlx4_ib_cq_clean ( to_mcq ( ibqp - > send_cq ) , qp - > mqp . qpn , NULL ) ;
qp - > rq . head = 0 ;
qp - > rq . tail = 0 ;
qp - > sq . head = 0 ;
qp - > sq . tail = 0 ;
* qp - > db . db = 0 ;
}
out :
mutex_unlock ( & qp - > mutex ) ;
kfree ( context ) ;
return err ;
}
static int build_mlx_header ( struct mlx4_ib_sqp * sqp , struct ib_send_wr * wr ,
void * wqe )
{
struct ib_device * ib_dev = & to_mdev ( sqp - > qp . ibqp . device ) - > ib_dev ;
struct mlx4_wqe_mlx_seg * mlx = wqe ;
struct mlx4_wqe_inline_seg * inl = wqe + sizeof * mlx ;
struct mlx4_ib_ah * ah = to_mah ( wr - > wr . ud . ah ) ;
u16 pkey ;
int send_size ;
int header_size ;
int i ;
send_size = 0 ;
for ( i = 0 ; i < wr - > num_sge ; + + i )
send_size + = wr - > sg_list [ i ] . length ;
ib_ud_header_init ( send_size , mlx4_ib_ah_grh_present ( ah ) , & sqp - > ud_header ) ;
sqp - > ud_header . lrh . service_level =
be32_to_cpu ( ah - > av . sl_tclass_flowlabel ) > > 28 ;
sqp - > ud_header . lrh . destination_lid = ah - > av . dlid ;
sqp - > ud_header . lrh . source_lid = cpu_to_be16 ( ah - > av . g_slid & 0x7f ) ;
if ( mlx4_ib_ah_grh_present ( ah ) ) {
sqp - > ud_header . grh . traffic_class =
( be32_to_cpu ( ah - > av . sl_tclass_flowlabel ) > > 20 ) & 0xff ;
sqp - > ud_header . grh . flow_label =
ah - > av . sl_tclass_flowlabel & cpu_to_be32 ( 0xfffff ) ;
ib_get_cached_gid ( ib_dev , be32_to_cpu ( ah - > av . port_pd ) > > 24 ,
ah - > av . gid_index , & sqp - > ud_header . grh . source_gid ) ;
memcpy ( sqp - > ud_header . grh . destination_gid . raw ,
ah - > av . dgid , 16 ) ;
}
mlx - > flags & = cpu_to_be32 ( MLX4_WQE_CTRL_CQ_UPDATE ) ;
mlx - > flags | = cpu_to_be32 ( ( ! sqp - > qp . ibqp . qp_num ? MLX4_WQE_MLX_VL15 : 0 ) |
( sqp - > ud_header . lrh . destination_lid = =
IB_LID_PERMISSIVE ? MLX4_WQE_MLX_SLR : 0 ) |
( sqp - > ud_header . lrh . service_level < < 8 ) ) ;
mlx - > rlid = sqp - > ud_header . lrh . destination_lid ;
switch ( wr - > opcode ) {
case IB_WR_SEND :
sqp - > ud_header . bth . opcode = IB_OPCODE_UD_SEND_ONLY ;
sqp - > ud_header . immediate_present = 0 ;
break ;
case IB_WR_SEND_WITH_IMM :
sqp - > ud_header . bth . opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE ;
sqp - > ud_header . immediate_present = 1 ;
sqp - > ud_header . immediate_data = wr - > imm_data ;
break ;
default :
return - EINVAL ;
}
sqp - > ud_header . lrh . virtual_lane = ! sqp - > qp . ibqp . qp_num ? 15 : 0 ;
if ( sqp - > ud_header . lrh . destination_lid = = IB_LID_PERMISSIVE )
sqp - > ud_header . lrh . source_lid = IB_LID_PERMISSIVE ;
sqp - > ud_header . bth . solicited_event = ! ! ( wr - > send_flags & IB_SEND_SOLICITED ) ;
if ( ! sqp - > qp . ibqp . qp_num )
ib_get_cached_pkey ( ib_dev , sqp - > qp . port , sqp - > pkey_index , & pkey ) ;
else
ib_get_cached_pkey ( ib_dev , sqp - > qp . port , wr - > wr . ud . pkey_index , & pkey ) ;
sqp - > ud_header . bth . pkey = cpu_to_be16 ( pkey ) ;
sqp - > ud_header . bth . destination_qpn = cpu_to_be32 ( wr - > wr . ud . remote_qpn ) ;
sqp - > ud_header . bth . psn = cpu_to_be32 ( ( sqp - > send_psn + + ) & ( ( 1 < < 24 ) - 1 ) ) ;
sqp - > ud_header . deth . qkey = cpu_to_be32 ( wr - > wr . ud . remote_qkey & 0x80000000 ?
sqp - > qkey : wr - > wr . ud . remote_qkey ) ;
sqp - > ud_header . deth . source_qpn = cpu_to_be32 ( sqp - > qp . ibqp . qp_num ) ;
header_size = ib_ud_header_pack ( & sqp - > ud_header , sqp - > header_buf ) ;
if ( 0 ) {
printk ( KERN_ERR " built UD header of size %d: \n " , header_size ) ;
for ( i = 0 ; i < header_size / 4 ; + + i ) {
if ( i % 8 = = 0 )
printk ( " [%02x] " , i * 4 ) ;
printk ( " %08x " ,
be32_to_cpu ( ( ( __be32 * ) sqp - > header_buf ) [ i ] ) ) ;
if ( ( i + 1 ) % 8 = = 0 )
printk ( " \n " ) ;
}
printk ( " \n " ) ;
}
inl - > byte_count = cpu_to_be32 ( 1 < < 31 | header_size ) ;
memcpy ( inl + 1 , sqp - > header_buf , header_size ) ;
return ALIGN ( sizeof ( struct mlx4_wqe_inline_seg ) + header_size , 16 ) ;
}
static int mlx4_wq_overflow ( struct mlx4_ib_wq * wq , int nreq , struct ib_cq * ib_cq )
{
unsigned cur ;
struct mlx4_ib_cq * cq ;
cur = wq - > head - wq - > tail ;
if ( likely ( cur + nreq < wq - > max ) )
return 0 ;
cq = to_mcq ( ib_cq ) ;
spin_lock ( & cq - > lock ) ;
cur = wq - > head - wq - > tail ;
spin_unlock ( & cq - > lock ) ;
return cur + nreq > = wq - > max ;
}
int mlx4_ib_post_send ( struct ib_qp * ibqp , struct ib_send_wr * wr ,
struct ib_send_wr * * bad_wr )
{
struct mlx4_ib_qp * qp = to_mqp ( ibqp ) ;
void * wqe ;
struct mlx4_wqe_ctrl_seg * ctrl ;
unsigned long flags ;
int nreq ;
int err = 0 ;
int ind ;
int size ;
int i ;
spin_lock_irqsave ( & qp - > rq . lock , flags ) ;
ind = qp - > sq . head ;
for ( nreq = 0 ; wr ; + + nreq , wr = wr - > next ) {
if ( mlx4_wq_overflow ( & qp - > sq , nreq , qp - > ibqp . send_cq ) ) {
err = - ENOMEM ;
* bad_wr = wr ;
goto out ;
}
if ( unlikely ( wr - > num_sge > qp - > sq . max_gs ) ) {
err = - EINVAL ;
* bad_wr = wr ;
goto out ;
}
ctrl = wqe = get_send_wqe ( qp , ind & ( qp - > sq . max - 1 ) ) ;
qp - > sq . wrid [ ind & ( qp - > sq . max - 1 ) ] = wr - > wr_id ;
ctrl - > srcrb_flags =
( wr - > send_flags & IB_SEND_SIGNALED ?
cpu_to_be32 ( MLX4_WQE_CTRL_CQ_UPDATE ) : 0 ) |
( wr - > send_flags & IB_SEND_SOLICITED ?
cpu_to_be32 ( MLX4_WQE_CTRL_SOLICITED ) : 0 ) |
qp - > sq_signal_bits ;
if ( wr - > opcode = = IB_WR_SEND_WITH_IMM | |
wr - > opcode = = IB_WR_RDMA_WRITE_WITH_IMM )
ctrl - > imm = wr - > imm_data ;
else
ctrl - > imm = 0 ;
wqe + = sizeof * ctrl ;
size = sizeof * ctrl / 16 ;
switch ( ibqp - > qp_type ) {
case IB_QPT_RC :
case IB_QPT_UC :
switch ( wr - > opcode ) {
case IB_WR_ATOMIC_CMP_AND_SWP :
case IB_WR_ATOMIC_FETCH_AND_ADD :
( ( struct mlx4_wqe_raddr_seg * ) wqe ) - > raddr =
cpu_to_be64 ( wr - > wr . atomic . remote_addr ) ;
( ( struct mlx4_wqe_raddr_seg * ) wqe ) - > rkey =
cpu_to_be32 ( wr - > wr . atomic . rkey ) ;
( ( struct mlx4_wqe_raddr_seg * ) wqe ) - > reserved = 0 ;
wqe + = sizeof ( struct mlx4_wqe_raddr_seg ) ;
if ( wr - > opcode = = IB_WR_ATOMIC_CMP_AND_SWP ) {
( ( struct mlx4_wqe_atomic_seg * ) wqe ) - > swap_add =
cpu_to_be64 ( wr - > wr . atomic . swap ) ;
( ( struct mlx4_wqe_atomic_seg * ) wqe ) - > compare =
cpu_to_be64 ( wr - > wr . atomic . compare_add ) ;
} else {
( ( struct mlx4_wqe_atomic_seg * ) wqe ) - > swap_add =
cpu_to_be64 ( wr - > wr . atomic . compare_add ) ;
( ( struct mlx4_wqe_atomic_seg * ) wqe ) - > compare = 0 ;
}
wqe + = sizeof ( struct mlx4_wqe_atomic_seg ) ;
size + = ( sizeof ( struct mlx4_wqe_raddr_seg ) +
sizeof ( struct mlx4_wqe_atomic_seg ) ) / 16 ;
break ;
case IB_WR_RDMA_READ :
case IB_WR_RDMA_WRITE :
case IB_WR_RDMA_WRITE_WITH_IMM :
( ( struct mlx4_wqe_raddr_seg * ) wqe ) - > raddr =
cpu_to_be64 ( wr - > wr . rdma . remote_addr ) ;
( ( struct mlx4_wqe_raddr_seg * ) wqe ) - > rkey =
cpu_to_be32 ( wr - > wr . rdma . rkey ) ;
( ( struct mlx4_wqe_raddr_seg * ) wqe ) - > reserved = 0 ;
wqe + = sizeof ( struct mlx4_wqe_raddr_seg ) ;
size + = sizeof ( struct mlx4_wqe_raddr_seg ) / 16 ;
break ;
default :
/* No extra segments required for sends */
break ;
}
break ;
case IB_QPT_UD :
memcpy ( ( ( struct mlx4_wqe_datagram_seg * ) wqe ) - > av ,
& to_mah ( wr - > wr . ud . ah ) - > av , sizeof ( struct mlx4_av ) ) ;
( ( struct mlx4_wqe_datagram_seg * ) wqe ) - > dqpn =
cpu_to_be32 ( wr - > wr . ud . remote_qpn ) ;
( ( struct mlx4_wqe_datagram_seg * ) wqe ) - > qkey =
cpu_to_be32 ( wr - > wr . ud . remote_qkey ) ;
wqe + = sizeof ( struct mlx4_wqe_datagram_seg ) ;
size + = sizeof ( struct mlx4_wqe_datagram_seg ) / 16 ;
break ;
case IB_QPT_SMI :
case IB_QPT_GSI :
err = build_mlx_header ( to_msqp ( qp ) , wr , ctrl ) ;
if ( err < 0 ) {
* bad_wr = wr ;
goto out ;
}
wqe + = err ;
size + = err / 16 ;
err = 0 ;
break ;
default :
break ;
}
for ( i = 0 ; i < wr - > num_sge ; + + i ) {
( ( struct mlx4_wqe_data_seg * ) wqe ) - > byte_count =
cpu_to_be32 ( wr - > sg_list [ i ] . length ) ;
( ( struct mlx4_wqe_data_seg * ) wqe ) - > lkey =
cpu_to_be32 ( wr - > sg_list [ i ] . lkey ) ;
( ( struct mlx4_wqe_data_seg * ) wqe ) - > addr =
cpu_to_be64 ( wr - > sg_list [ i ] . addr ) ;
wqe + = sizeof ( struct mlx4_wqe_data_seg ) ;
size + = sizeof ( struct mlx4_wqe_data_seg ) / 16 ;
}
/* Add one more inline data segment for ICRC for MLX sends */
if ( qp - > ibqp . qp_type = = IB_QPT_SMI | | qp - > ibqp . qp_type = = IB_QPT_GSI ) {
( ( struct mlx4_wqe_inline_seg * ) wqe ) - > byte_count =
cpu_to_be32 ( ( 1 < < 31 ) | 4 ) ;
( ( u32 * ) wqe ) [ 1 ] = 0 ;
wqe + = sizeof ( struct mlx4_wqe_data_seg ) ;
size + = sizeof ( struct mlx4_wqe_data_seg ) / 16 ;
}
ctrl - > fence_size = ( wr - > send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0 ) | size ;
/*
* Make sure descriptor is fully written before
* setting ownership bit ( because HW can start
* executing as soon as we do ) .
*/
wmb ( ) ;
if ( wr - > opcode < 0 | | wr - > opcode > ARRAY_SIZE ( mlx4_ib_opcode ) ) {
err = - EINVAL ;
goto out ;
}
ctrl - > owner_opcode = mlx4_ib_opcode [ wr - > opcode ] |
( ind & qp - > sq . max ? cpu_to_be32 ( 1 < < 31 ) : 0 ) ;
+ + ind ;
}
out :
if ( likely ( nreq ) ) {
qp - > sq . head + = nreq ;
/*
* Make sure that descriptors are written before
* doorbell record .
*/
wmb ( ) ;
writel ( qp - > doorbell_qpn ,
to_mdev ( ibqp - > device ) - > uar_map + MLX4_SEND_DOORBELL ) ;
/*
* Make sure doorbells don ' t leak out of SQ spinlock
* and reach the HCA out of order .
*/
mmiowb ( ) ;
}
spin_unlock_irqrestore ( & qp - > rq . lock , flags ) ;
return err ;
}
int mlx4_ib_post_recv ( struct ib_qp * ibqp , struct ib_recv_wr * wr ,
struct ib_recv_wr * * bad_wr )
{
struct mlx4_ib_qp * qp = to_mqp ( ibqp ) ;
struct mlx4_wqe_data_seg * scat ;
unsigned long flags ;
int err = 0 ;
int nreq ;
int ind ;
int i ;
spin_lock_irqsave ( & qp - > rq . lock , flags ) ;
ind = qp - > rq . head & ( qp - > rq . max - 1 ) ;
for ( nreq = 0 ; wr ; + + nreq , wr = wr - > next ) {
if ( mlx4_wq_overflow ( & qp - > rq , nreq , qp - > ibqp . send_cq ) ) {
err = - ENOMEM ;
* bad_wr = wr ;
goto out ;
}
if ( unlikely ( wr - > num_sge > qp - > rq . max_gs ) ) {
err = - EINVAL ;
* bad_wr = wr ;
goto out ;
}
scat = get_recv_wqe ( qp , ind ) ;
for ( i = 0 ; i < wr - > num_sge ; + + i ) {
scat [ i ] . byte_count = cpu_to_be32 ( wr - > sg_list [ i ] . length ) ;
scat [ i ] . lkey = cpu_to_be32 ( wr - > sg_list [ i ] . lkey ) ;
scat [ i ] . addr = cpu_to_be64 ( wr - > sg_list [ i ] . addr ) ;
}
if ( i < qp - > rq . max_gs ) {
scat [ i ] . byte_count = 0 ;
scat [ i ] . lkey = cpu_to_be32 ( MLX4_INVALID_LKEY ) ;
scat [ i ] . addr = 0 ;
}
qp - > rq . wrid [ ind ] = wr - > wr_id ;
ind = ( ind + 1 ) & ( qp - > rq . max - 1 ) ;
}
out :
if ( likely ( nreq ) ) {
qp - > rq . head + = nreq ;
/*
* Make sure that descriptors are written before
* doorbell record .
*/
wmb ( ) ;
* qp - > db . db = cpu_to_be32 ( qp - > rq . head & 0xffff ) ;
}
spin_unlock_irqrestore ( & qp - > rq . lock , flags ) ;
return err ;
}