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 ] ;
} ;
2007-10-18 17:36:43 +02:00
enum {
MLX4_IB_MIN_SQ_STRIDE = 6
} ;
2007-05-08 18:00:38 -07:00
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 )
{
2008-02-06 21:07:54 -08:00
return mlx4_buf_offset ( & qp - > buf , offset ) ;
2007-05-08 18:00:38 -07:00
}
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 ) ) ;
}
2007-06-18 08:13:48 -07:00
/*
* Stamp a SQ WQE so that it is invalid if prefetched by marking the
* first four bytes of every 64 byte chunk with 0xffffffff , except for
* the very first chunk of the WQE .
*/
static void stamp_send_wqe ( struct mlx4_ib_qp * qp , int n )
{
u32 * wqe = get_send_wqe ( qp , n ) ;
int i ;
for ( i = 16 ; i < 1 < < ( qp - > sq . wqe_shift - 2 ) ; i + = 16 )
wqe [ i ] = 0xffffffff ;
}
2007-05-08 18:00:38 -07:00
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 +
2007-06-18 09:23:47 -07:00
DIV_ROUND_UP ( MLX4_IB_UD_HEADER_SIZE ,
MLX4_INLINE_ALIGN ) *
2007-05-08 18:00:38 -07:00
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 ) ;
}
}
2007-05-17 10:32:41 +03:00
static int set_rq_size ( struct mlx4_ib_dev * dev , struct ib_qp_cap * cap ,
2007-06-07 23:24:39 -07:00
int is_user , int has_srq , struct mlx4_ib_qp * qp )
2007-05-08 18:00:38 -07:00
{
2007-05-17 10:32:41 +03:00
/* Sanity check RQ size before proceeding */
if ( cap - > max_recv_wr > dev - > dev - > caps . max_wqes | |
cap - > max_recv_sge > dev - > dev - > caps . max_rq_sg )
return - EINVAL ;
2007-06-07 23:24:39 -07:00
if ( has_srq ) {
/* QPs attached to an SRQ should have no RQ */
if ( cap - > max_recv_wr )
return - EINVAL ;
2007-05-17 10:32:41 +03:00
2007-06-18 08:13:48 -07:00
qp - > rq . wqe_cnt = qp - > rq . max_gs = 0 ;
2007-06-07 23:24:39 -07:00
} else {
/* HW requires >= 1 RQ entry with >= 1 gather entry */
if ( is_user & & ( ! cap - > max_recv_wr | | ! cap - > max_recv_sge ) )
return - EINVAL ;
2007-06-18 08:13:48 -07:00
qp - > rq . wqe_cnt = roundup_pow_of_two ( max ( 1U , cap - > max_recv_wr ) ) ;
2007-06-12 10:52:02 -07:00
qp - > rq . max_gs = roundup_pow_of_two ( max ( 1U , cap - > max_recv_sge ) ) ;
2007-06-07 23:24:39 -07:00
qp - > rq . wqe_shift = ilog2 ( qp - > rq . max_gs * sizeof ( struct mlx4_wqe_data_seg ) ) ;
}
2007-05-17 10:32:41 +03:00
2007-06-18 08:13:48 -07:00
cap - > max_recv_wr = qp - > rq . max_post = qp - > rq . wqe_cnt ;
2007-05-17 10:32:41 +03:00
cap - > max_recv_sge = qp - > rq . max_gs ;
return 0 ;
}
static int set_kernel_sq_size ( struct mlx4_ib_dev * dev , struct ib_qp_cap * cap ,
enum ib_qp_type type , struct mlx4_ib_qp * qp )
{
/* Sanity check SQ size before proceeding */
2007-05-08 18:00:38 -07:00
if ( cap - > max_send_wr > dev - > dev - > caps . max_wqes | |
cap - > max_send_sge > dev - > dev - > caps . max_sq_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 - > 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 ) ;
2007-06-18 08:13:48 -07:00
/*
* We need to leave 2 KB + 1 WQE of headroom in the SQ to
* allow HW to prefetch .
*/
qp - > sq_spare_wqes = ( 2048 > > qp - > sq . wqe_shift ) + 1 ;
qp - > sq . wqe_cnt = roundup_pow_of_two ( cap - > max_send_wr + qp - > sq_spare_wqes ) ;
qp - > buf_size = ( qp - > rq . wqe_cnt < < qp - > rq . wqe_shift ) +
( qp - > sq . wqe_cnt < < qp - > sq . wqe_shift ) ;
2007-05-08 18:00:38 -07:00
if ( qp - > rq . wqe_shift > qp - > sq . wqe_shift ) {
qp - > rq . offset = 0 ;
2007-06-18 08:13:48 -07:00
qp - > sq . offset = qp - > rq . wqe_cnt < < qp - > rq . wqe_shift ;
2007-05-08 18:00:38 -07:00
} else {
2007-06-18 08:13:48 -07:00
qp - > rq . offset = qp - > sq . wqe_cnt < < qp - > sq . wqe_shift ;
2007-05-08 18:00:38 -07:00
qp - > sq . offset = 0 ;
}
2007-06-18 08:13:48 -07:00
cap - > max_send_wr = qp - > sq . max_post = qp - > sq . wqe_cnt - qp - > sq_spare_wqes ;
cap - > max_send_sge = qp - > sq . max_gs ;
2007-06-18 08:13:53 -07:00
/* We don't support inline sends for kernel QPs (yet) */
cap - > max_inline_data = 0 ;
2007-05-08 18:00:38 -07:00
return 0 ;
}
2007-10-18 17:36:43 +02:00
static int set_user_sq_size ( struct mlx4_ib_dev * dev ,
struct mlx4_ib_qp * qp ,
2007-05-17 10:32:41 +03:00
struct mlx4_ib_create_qp * ucmd )
{
2007-10-18 17:36:43 +02:00
/* Sanity check SQ size before proceeding */
if ( ( 1 < < ucmd - > log_sq_bb_count ) > dev - > dev - > caps . max_wqes | |
ucmd - > log_sq_stride >
ilog2 ( roundup_pow_of_two ( dev - > dev - > caps . max_sq_desc_sz ) ) | |
ucmd - > log_sq_stride < MLX4_IB_MIN_SQ_STRIDE )
return - EINVAL ;
2007-06-18 08:13:48 -07:00
qp - > sq . wqe_cnt = 1 < < ucmd - > log_sq_bb_count ;
2007-05-17 10:32:41 +03:00
qp - > sq . wqe_shift = ucmd - > log_sq_stride ;
2007-06-18 08:13:48 -07:00
qp - > buf_size = ( qp - > rq . wqe_cnt < < qp - > rq . wqe_shift ) +
( qp - > sq . wqe_cnt < < qp - > sq . wqe_shift ) ;
2007-05-17 10:32:41 +03:00
return 0 ;
}
2007-05-08 18:00:38 -07:00
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 )
{
int err ;
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 ;
2007-06-07 23:24:39 -07:00
err = set_rq_size ( dev , & init_attr - > cap , ! ! pd - > uobject , ! ! init_attr - > srq , qp ) ;
2007-05-08 18:00:38 -07:00
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 ;
}
2007-06-18 08:13:48 -07:00
qp - > sq_no_prefetch = ucmd . sq_no_prefetch ;
2007-10-18 17:36:43 +02:00
err = set_user_sq_size ( dev , qp , & ucmd ) ;
2007-05-17 10:32:41 +03:00
if ( err )
goto err ;
2007-05-08 18:00:38 -07:00
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 ;
2007-05-23 15:16:08 -07:00
if ( ! init_attr - > srq ) {
err = mlx4_ib_db_map_user ( to_mucontext ( pd - > uobject - > context ) ,
ucmd . db_addr , & qp - > db ) ;
if ( err )
goto err_mtt ;
}
2007-05-08 18:00:38 -07:00
} else {
2007-06-18 08:13:48 -07:00
qp - > sq_no_prefetch = 0 ;
2007-05-17 10:32:41 +03:00
err = set_kernel_sq_size ( dev , & init_attr - > cap , init_attr - > qp_type , qp ) ;
if ( err )
goto err ;
2007-05-23 15:16:08 -07:00
if ( ! init_attr - > srq ) {
err = mlx4_ib_db_alloc ( dev , & qp - > db , 0 ) ;
if ( err )
goto err ;
2007-05-08 18:00:38 -07:00
2007-05-23 15:16:08 -07:00
* qp - > db . db = 0 ;
}
2007-05-08 18:00:38 -07:00
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 ;
2007-06-18 08:13:48 -07:00
qp - > sq . wrid = kmalloc ( qp - > sq . wqe_cnt * sizeof ( u64 ) , GFP_KERNEL ) ;
qp - > rq . wrid = kmalloc ( qp - > rq . wqe_cnt * sizeof ( u64 ) , GFP_KERNEL ) ;
2007-05-08 18:00:38 -07:00
if ( ! qp - > sq . wrid | | ! qp - > rq . wrid ) {
err = - ENOMEM ;
goto err_wrid ;
}
}
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 :
2007-07-20 21:19:43 -07:00
if ( pd - > uobject ) {
if ( ! init_attr - > srq )
mlx4_ib_db_unmap_user ( to_mucontext ( pd - > uobject - > context ) ,
& qp - > db ) ;
} else {
2007-05-08 18:00:38 -07:00
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 :
2007-05-23 15:16:08 -07:00
if ( ! pd - > uobject & & ! init_attr - > srq )
2007-05-08 18:00:38 -07:00
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 ) {
2007-05-23 15:16:08 -07:00
if ( ! qp - > ibqp . srq )
mlx4_ib_db_unmap_user ( to_mucontext ( qp - > ibqp . uobject - > context ) ,
& qp - > db ) ;
2007-05-08 18:00:38 -07:00
ib_umem_release ( qp - > umem ) ;
} else {
kfree ( qp - > sq . wrid ) ;
kfree ( qp - > rq . wrid ) ;
mlx4_buf_free ( dev - > dev , qp - > buf_size , & qp - > buf ) ;
2007-05-23 15:16:08 -07:00
if ( ! qp - > ibqp . srq )
mlx4_ib_db_free ( dev , & qp - > db ) ;
2007-05-08 18:00:38 -07:00
}
}
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 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 ;
}
}
2007-05-14 07:26:51 +03:00
static __be32 to_mlx4_access_flags ( struct mlx4_ib_qp * qp , const struct ib_qp_attr * attr ,
2007-05-08 18:00:38 -07:00
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 ) ;
}
2007-05-14 07:26:51 +03:00
static void store_sqp_attrs ( struct mlx4_ib_sqp * sqp , const struct ib_qp_attr * attr ,
2007-05-08 18:00:38 -07:00
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 ) ;
}
2007-05-14 07:26:51 +03:00
static int mlx4_set_path ( struct mlx4_ib_dev * dev , const struct ib_ah_attr * ah ,
2007-05-08 18:00:38 -07:00
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 ) {
2007-06-18 08:15:02 -07:00
if ( ah - > grh . sgid_index > = dev - > dev - > caps . gid_table_len [ port ] ) {
2007-05-08 18:00:38 -07:00
printk ( KERN_ERR " sgid_index (%u) too large. max is %d \n " ,
2007-06-18 08:15:02 -07:00
ah - > grh . sgid_index , dev - > dev - > caps . gid_table_len [ port ] - 1 ) ;
2007-05-08 18:00:38 -07:00
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 ;
}
2007-05-14 07:26:51 +03:00
static int __mlx4_ib_modify_qp ( struct ib_qp * ibqp ,
const struct ib_qp_attr * attr , int attr_mask ,
enum ib_qp_state cur_state , enum ib_qp_state new_state )
2007-05-08 18:00:38 -07:00
{
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 ;
int sqd_event ;
int err = - EINVAL ;
context = kzalloc ( sizeof * context , GFP_KERNEL ) ;
if ( ! context )
return - ENOMEM ;
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 ) ;
2007-07-19 15:58:09 -04:00
goto out ;
2007-05-08 18:00:38 -07:00
}
context - > mtu_msgmax = ( attr - > path_mtu < < 5 ) | 31 ;
}
2007-06-18 08:13:48 -07:00
if ( qp - > rq . wqe_cnt )
context - > rq_size_stride = ilog2 ( qp - > rq . wqe_cnt ) < < 3 ;
2007-05-08 18:00:38 -07:00
context - > rq_size_stride | = qp - > rq . wqe_shift - 4 ;
2007-06-18 08:13:48 -07:00
if ( qp - > sq . wqe_cnt )
context - > sq_size_stride = ilog2 ( qp - > sq . wqe_cnt ) < < 3 ;
2007-05-08 18:00:38 -07:00
context - > sq_size_stride | = qp - > sq . wqe_shift - 4 ;
2007-06-18 08:13:48 -07:00
if ( cur_state = = IB_QPS_RESET & & new_state = = IB_QPS_INIT )
context - > sq_size_stride | = ! ! qp - > sq_no_prefetch < < 7 ;
2007-05-08 18:00:38 -07:00
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_AV ) {
if ( mlx4_set_path ( dev , & attr - > ah_attr , & context - > pri_path ,
2007-07-19 15:58:09 -04:00
attr_mask & IB_QP_PORT ? attr - > port_num : qp - > port ) )
2007-05-08 18:00:38 -07:00
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_port_num = = 0 | |
attr - > alt_port_num > dev - > dev - > caps . num_ports )
2007-07-19 15:58:09 -04:00
goto out ;
2007-05-08 18:00:38 -07:00
2007-06-18 08:15:02 -07:00
if ( attr - > alt_pkey_index > =
dev - > dev - > caps . pkey_table_len [ attr - > alt_port_num ] )
2007-07-19 15:58:09 -04:00
goto out ;
2007-06-18 08:15:02 -07:00
2007-05-08 18:00:38 -07:00
if ( mlx4_set_path ( dev , & attr - > alt_ah_attr , & context - > alt_path ,
attr - > alt_port_num ) )
2007-07-19 15:58:09 -04:00
goto out ;
2007-05-08 18:00:38 -07:00
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 ) ;
2007-06-06 19:35:04 +03:00
if ( attr_mask & IB_QP_RNR_RETRY ) {
context - > params1 | = cpu_to_be32 ( attr - > rnr_retry < < 13 ) ;
optpar | = MLX4_QP_OPTPAR_RNR_RETRY ;
}
2007-05-08 18:00:38 -07:00
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 ) ;
2007-05-23 15:16:08 -07:00
if ( ! ibqp - > srq & & cur_state = = IB_QPS_RESET & & new_state = = IB_QPS_INIT )
2007-05-08 18:00:38 -07:00
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 ;
2007-05-24 16:05:01 +03:00
/*
* Before passing a kernel QP to the HW , make sure that the
2007-06-18 08:13:48 -07:00
* ownership bits of the send queue are set and the SQ
* headroom is stamped so that the hardware doesn ' t start
* processing stale work requests .
2007-05-24 16:05:01 +03:00
*/
if ( ! ibqp - > uobject & & cur_state = = IB_QPS_RESET & & new_state = = IB_QPS_INIT ) {
struct mlx4_wqe_ctrl_seg * ctrl ;
int i ;
2007-06-18 08:13:48 -07:00
for ( i = 0 ; i < qp - > sq . wqe_cnt ; + + i ) {
2007-05-24 16:05:01 +03:00
ctrl = get_send_wqe ( qp , i ) ;
ctrl - > owner_opcode = cpu_to_be32 ( 1 < < 31 ) ;
2007-06-18 08:13:48 -07:00
stamp_send_wqe ( qp , i ) ;
2007-05-24 16:05:01 +03:00
}
}
2007-05-08 18:00:38 -07:00
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 )
2007-06-18 08:15:02 -07:00
if ( mlx4_INIT_PORT ( dev - > dev , qp - > port ) )
printk ( KERN_WARNING " INIT_PORT failed for port %d \n " ,
qp - > port ) ;
2007-05-08 18:00:38 -07:00
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 ;
2007-05-23 15:16:08 -07:00
if ( ! ibqp - > srq )
* qp - > db . db = 0 ;
2007-05-08 18:00:38 -07:00
}
out :
kfree ( context ) ;
return err ;
}
2007-05-14 07:26:51 +03:00
static const struct ib_qp_attr mlx4_ib_qp_attr = { . port_num = 1 } ;
static const int mlx4_ib_qp_attr_mask_table [ IB_QPT_UD + 1 ] = {
[ IB_QPT_UD ] = ( IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY ) ,
[ IB_QPT_UC ] = ( IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS ) ,
[ IB_QPT_RC ] = ( IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS ) ,
[ IB_QPT_SMI ] = ( IB_QP_PKEY_INDEX |
IB_QP_QKEY ) ,
[ IB_QPT_GSI ] = ( IB_QP_PKEY_INDEX |
IB_QP_QKEY ) ,
} ;
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 ) ;
enum ib_qp_state cur_state , new_state ;
int err = - EINVAL ;
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_PORT ) & &
( attr - > port_num = = 0 | | attr - > port_num > dev - > dev - > caps . num_ports ) ) {
goto out ;
}
2007-06-18 08:15:02 -07:00
if ( attr_mask & IB_QP_PKEY_INDEX ) {
int p = attr_mask & IB_QP_PORT ? attr - > port_num : qp - > port ;
if ( attr - > pkey_index > = dev - > dev - > caps . pkey_table_len [ p ] )
goto out ;
}
2007-05-14 07:26:51 +03:00
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 & &
attr - > max_dest_rd_atomic > dev - > dev - > caps . max_qp_dest_rdma ) {
goto out ;
}
if ( cur_state = = new_state & & cur_state = = IB_QPS_RESET ) {
err = 0 ;
goto out ;
}
if ( cur_state = = IB_QPS_RESET & & new_state = = IB_QPS_ERR ) {
err = __mlx4_ib_modify_qp ( ibqp , & mlx4_ib_qp_attr ,
mlx4_ib_qp_attr_mask_table [ ibqp - > qp_type ] ,
IB_QPS_RESET , IB_QPS_INIT ) ;
if ( err )
goto out ;
cur_state = IB_QPS_INIT ;
}
err = __mlx4_ib_modify_qp ( ibqp , attr , attr_mask , cur_state , new_state ) ;
out :
mutex_unlock ( & qp - > mutex ) ;
return err ;
}
2007-05-08 18:00:38 -07:00
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 ;
2007-06-18 09:23:47 -07:00
int spc ;
2007-05-08 18:00:38 -07:00
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 ) ;
2007-05-19 08:51:57 -07:00
sqp - > ud_header . grh . hop_limit = ah - > av . hop_limit ;
2007-05-08 18:00:38 -07:00
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 " ) ;
}
2007-06-18 09:23:47 -07:00
/*
* Inline data segments may not cross a 64 byte boundary . If
* our UD header is bigger than the space available up to the
* next 64 byte boundary in the WQE , use two inline data
* segments to hold the UD header .
*/
spc = MLX4_INLINE_ALIGN -
( ( unsigned long ) ( inl + 1 ) & ( MLX4_INLINE_ALIGN - 1 ) ) ;
if ( header_size < = spc ) {
inl - > byte_count = cpu_to_be32 ( 1 < < 31 | header_size ) ;
memcpy ( inl + 1 , sqp - > header_buf , header_size ) ;
i = 1 ;
} else {
inl - > byte_count = cpu_to_be32 ( 1 < < 31 | spc ) ;
memcpy ( inl + 1 , sqp - > header_buf , spc ) ;
inl = ( void * ) ( inl + 1 ) + spc ;
memcpy ( inl + 1 , sqp - > header_buf + spc , header_size - spc ) ;
/*
* Need a barrier here to make sure all the data is
* visible before the byte_count field is set .
* Otherwise the HCA prefetcher could grab the 64 - byte
* chunk with this inline segment and get a valid ( ! =
* 0xffffffff ) byte count but stale data , and end up
* generating a packet with bad headers .
*
* The first inline segment ' s byte_count field doesn ' t
* need a barrier , because it comes after a
* control / MLX segment and therefore is at an offset
* of 16 mod 64.
*/
wmb ( ) ;
inl - > byte_count = cpu_to_be32 ( 1 < < 31 | ( header_size - spc ) ) ;
i = 2 ;
}
2007-05-08 18:00:38 -07:00
2007-06-18 09:23:47 -07:00
return ALIGN ( i * sizeof ( struct mlx4_wqe_inline_seg ) + header_size , 16 ) ;
2007-05-08 18:00:38 -07:00
}
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 ;
2007-06-18 08:13:48 -07:00
if ( likely ( cur + nreq < wq - > max_post ) )
2007-05-08 18:00:38 -07:00
return 0 ;
cq = to_mcq ( ib_cq ) ;
spin_lock ( & cq - > lock ) ;
cur = wq - > head - wq - > tail ;
spin_unlock ( & cq - > lock ) ;
2007-06-18 08:13:48 -07:00
return cur + nreq > = wq - > max_post ;
2007-05-08 18:00:38 -07:00
}
2007-07-18 11:47:55 -07:00
static __always_inline void set_raddr_seg ( struct mlx4_wqe_raddr_seg * rseg ,
u64 remote_addr , u32 rkey )
{
rseg - > raddr = cpu_to_be64 ( remote_addr ) ;
rseg - > rkey = cpu_to_be32 ( rkey ) ;
rseg - > reserved = 0 ;
}
static void set_atomic_seg ( struct mlx4_wqe_atomic_seg * aseg , struct ib_send_wr * wr )
{
if ( wr - > opcode = = IB_WR_ATOMIC_CMP_AND_SWP ) {
aseg - > swap_add = cpu_to_be64 ( wr - > wr . atomic . swap ) ;
aseg - > compare = cpu_to_be64 ( wr - > wr . atomic . compare_add ) ;
} else {
aseg - > swap_add = cpu_to_be64 ( wr - > wr . atomic . compare_add ) ;
aseg - > compare = 0 ;
}
}
static void set_datagram_seg ( struct mlx4_wqe_datagram_seg * dseg ,
struct ib_send_wr * wr )
{
memcpy ( dseg - > av , & to_mah ( wr - > wr . ud . ah ) - > av , sizeof ( struct mlx4_av ) ) ;
dseg - > dqpn = cpu_to_be32 ( wr - > wr . ud . remote_qpn ) ;
dseg - > qkey = cpu_to_be32 ( wr - > wr . ud . remote_qkey ) ;
}
2007-09-19 09:52:25 -07:00
static void set_mlx_icrc_seg ( void * dseg )
{
u32 * t = dseg ;
struct mlx4_wqe_inline_seg * iseg = dseg ;
t [ 1 ] = 0 ;
/*
* Need a barrier here before writing the byte_count field to
* make sure that all the data is visible before the
* byte_count field is set . Otherwise , if the segment begins
* a new cacheline , the HCA prefetcher could grab the 64 - byte
* chunk and get a valid ( ! = * 0xffffffff ) byte count but
* stale data , and end up sending the wrong data .
*/
wmb ( ) ;
iseg - > byte_count = cpu_to_be32 ( ( 1 < < 31 ) | 4 ) ;
}
static void set_data_seg ( struct mlx4_wqe_data_seg * dseg , struct ib_sge * sg )
2007-07-18 11:46:27 -07:00
{
dseg - > lkey = cpu_to_be32 ( sg - > lkey ) ;
dseg - > addr = cpu_to_be64 ( sg - > addr ) ;
2007-09-19 09:52:25 -07:00
/*
* Need a barrier here before writing the byte_count field to
* make sure that all the data is visible before the
* byte_count field is set . Otherwise , if the segment begins
* a new cacheline , the HCA prefetcher could grab the 64 - byte
* chunk and get a valid ( ! = * 0xffffffff ) byte count but
* stale data , and end up sending the wrong data .
*/
wmb ( ) ;
dseg - > byte_count = cpu_to_be32 ( sg - > length ) ;
2007-07-18 11:46:27 -07:00
}
2007-10-09 19:59:05 -07:00
static void __set_data_seg ( struct mlx4_wqe_data_seg * dseg , struct ib_sge * sg )
{
dseg - > byte_count = cpu_to_be32 ( sg - > length ) ;
dseg - > lkey = cpu_to_be32 ( sg - > lkey ) ;
dseg - > addr = cpu_to_be64 ( sg - > addr ) ;
}
2007-05-08 18:00:38 -07:00
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 ;
2007-09-19 09:52:25 -07:00
struct mlx4_wqe_data_seg * dseg ;
2007-05-08 18:00:38 -07:00
unsigned long flags ;
int nreq ;
int err = 0 ;
int ind ;
int size ;
int i ;
2007-10-30 10:53:54 -07:00
spin_lock_irqsave ( & qp - > sq . lock , flags ) ;
2007-05-08 18:00:38 -07:00
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 ;
}
2007-06-18 08:13:48 -07:00
ctrl = wqe = get_send_wqe ( qp , ind & ( qp - > sq . wqe_cnt - 1 ) ) ;
qp - > sq . wrid [ ind & ( qp - > sq . wqe_cnt - 1 ) ] = wr - > wr_id ;
2007-05-08 18:00:38 -07:00
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 :
2007-07-18 11:47:55 -07:00
set_raddr_seg ( wqe , wr - > wr . atomic . remote_addr ,
wr - > wr . atomic . rkey ) ;
2007-05-08 18:00:38 -07:00
wqe + = sizeof ( struct mlx4_wqe_raddr_seg ) ;
2007-07-18 11:47:55 -07:00
set_atomic_seg ( wqe , wr ) ;
2007-05-08 18:00:38 -07:00
wqe + = sizeof ( struct mlx4_wqe_atomic_seg ) ;
2007-07-18 11:47:55 -07:00
2007-05-08 18:00:38 -07:00
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 :
2007-07-18 11:47:55 -07:00
set_raddr_seg ( wqe , wr - > wr . rdma . remote_addr ,
wr - > wr . rdma . rkey ) ;
2007-05-08 18:00:38 -07:00
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 :
2007-07-18 11:47:55 -07:00
set_datagram_seg ( wqe , wr ) ;
2007-05-08 18:00:38 -07:00
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 ;
}
2007-09-19 09:52:25 -07:00
/*
* Write data segments in reverse order , so as to
* overwrite cacheline stamp last within each
* cacheline . This avoids issues with WQE
* prefetching .
*/
2007-05-08 18:00:38 -07:00
2007-09-19 09:52:25 -07:00
dseg = wqe ;
dseg + = wr - > num_sge - 1 ;
size + = wr - > num_sge * ( sizeof ( struct mlx4_wqe_data_seg ) / 16 ) ;
2007-05-08 18:00:38 -07:00
/* Add one more inline data segment for ICRC for MLX sends */
2007-09-19 09:52:25 -07:00
if ( unlikely ( qp - > ibqp . qp_type = = IB_QPT_SMI | |
qp - > ibqp . qp_type = = IB_QPT_GSI ) ) {
set_mlx_icrc_seg ( dseg + 1 ) ;
2007-05-08 18:00:38 -07:00
size + = sizeof ( struct mlx4_wqe_data_seg ) / 16 ;
}
2007-09-19 09:52:25 -07:00
for ( i = wr - > num_sge - 1 ; i > = 0 ; - - i , - - dseg )
set_data_seg ( dseg , wr - > sg_list + i ) ;
2007-05-08 18:00:38 -07:00
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 ( ) ;
2007-05-19 08:51:58 -07:00
if ( wr - > opcode < 0 | | wr - > opcode > = ARRAY_SIZE ( mlx4_ib_opcode ) ) {
2007-05-08 18:00:38 -07:00
err = - EINVAL ;
goto out ;
}
ctrl - > owner_opcode = mlx4_ib_opcode [ wr - > opcode ] |
2007-06-18 08:13:48 -07:00
( ind & qp - > sq . wqe_cnt ? cpu_to_be32 ( 1 < < 31 ) : 0 ) ;
/*
* We can improve latency by not stamping the last
* send queue WQE until after ringing the doorbell , so
* only stamp here if there are still more WQEs to post .
*/
if ( wr - > next )
stamp_send_wqe ( qp , ( ind + qp - > sq_spare_wqes ) &
( qp - > sq . wqe_cnt - 1 ) ) ;
2007-05-08 18:00:38 -07:00
+ + 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 ( ) ;
2007-06-18 08:13:48 -07:00
stamp_send_wqe ( qp , ( ind + qp - > sq_spare_wqes - 1 ) &
( qp - > sq . wqe_cnt - 1 ) ) ;
2007-05-08 18:00:38 -07:00
}
2007-10-30 10:53:54 -07:00
spin_unlock_irqrestore ( & qp - > sq . lock , flags ) ;
2007-05-08 18:00:38 -07:00
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 ) ;
2007-06-18 08:13:48 -07:00
ind = qp - > rq . head & ( qp - > rq . wqe_cnt - 1 ) ;
2007-05-08 18:00:38 -07:00
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 ) ;
2007-10-09 19:59:05 -07:00
for ( i = 0 ; i < wr - > num_sge ; + + i )
__set_data_seg ( scat + i , wr - > sg_list + i ) ;
2007-05-08 18:00:38 -07:00
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 ;
2007-06-18 08:13:48 -07:00
ind = ( ind + 1 ) & ( qp - > rq . wqe_cnt - 1 ) ;
2007-05-08 18:00:38 -07:00
}
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 ;
}
2007-06-21 12:27:47 +03:00
static inline enum ib_qp_state to_ib_qp_state ( enum mlx4_qp_state mlx4_state )
{
switch ( mlx4_state ) {
case MLX4_QP_STATE_RST : return IB_QPS_RESET ;
case MLX4_QP_STATE_INIT : return IB_QPS_INIT ;
case MLX4_QP_STATE_RTR : return IB_QPS_RTR ;
case MLX4_QP_STATE_RTS : return IB_QPS_RTS ;
case MLX4_QP_STATE_SQ_DRAINING :
case MLX4_QP_STATE_SQD : return IB_QPS_SQD ;
case MLX4_QP_STATE_SQER : return IB_QPS_SQE ;
case MLX4_QP_STATE_ERR : return IB_QPS_ERR ;
default : return - 1 ;
}
}
static inline enum ib_mig_state to_ib_mig_state ( int mlx4_mig_state )
{
switch ( mlx4_mig_state ) {
case MLX4_QP_PM_ARMED : return IB_MIG_ARMED ;
case MLX4_QP_PM_REARM : return IB_MIG_REARM ;
case MLX4_QP_PM_MIGRATED : return IB_MIG_MIGRATED ;
default : return - 1 ;
}
}
static int to_ib_qp_access_flags ( int mlx4_flags )
{
int ib_flags = 0 ;
if ( mlx4_flags & MLX4_QP_BIT_RRE )
ib_flags | = IB_ACCESS_REMOTE_READ ;
if ( mlx4_flags & MLX4_QP_BIT_RWE )
ib_flags | = IB_ACCESS_REMOTE_WRITE ;
if ( mlx4_flags & MLX4_QP_BIT_RAE )
ib_flags | = IB_ACCESS_REMOTE_ATOMIC ;
return ib_flags ;
}
static void to_ib_ah_attr ( struct mlx4_dev * dev , struct ib_ah_attr * ib_ah_attr ,
struct mlx4_qp_path * path )
{
2007-07-15 15:00:09 +03:00
memset ( ib_ah_attr , 0 , sizeof * ib_ah_attr ) ;
2007-06-21 12:27:47 +03:00
ib_ah_attr - > port_num = path - > sched_queue & 0x40 ? 2 : 1 ;
if ( ib_ah_attr - > port_num = = 0 | | ib_ah_attr - > port_num > dev - > caps . num_ports )
return ;
ib_ah_attr - > dlid = be16_to_cpu ( path - > rlid ) ;
ib_ah_attr - > sl = ( path - > sched_queue > > 2 ) & 0xf ;
ib_ah_attr - > src_path_bits = path - > grh_mylmc & 0x7f ;
ib_ah_attr - > static_rate = path - > static_rate ? path - > static_rate - 5 : 0 ;
ib_ah_attr - > ah_flags = ( path - > grh_mylmc & ( 1 < < 7 ) ) ? IB_AH_GRH : 0 ;
if ( ib_ah_attr - > ah_flags ) {
ib_ah_attr - > grh . sgid_index = path - > mgid_index ;
ib_ah_attr - > grh . hop_limit = path - > hop_limit ;
ib_ah_attr - > grh . traffic_class =
( be32_to_cpu ( path - > tclass_flowlabel ) > > 20 ) & 0xff ;
ib_ah_attr - > grh . flow_label =
2007-07-17 18:37:38 -07:00
be32_to_cpu ( path - > tclass_flowlabel ) & 0xfffff ;
2007-06-21 12:27:47 +03:00
memcpy ( ib_ah_attr - > grh . dgid . raw ,
path - > rgid , sizeof ib_ah_attr - > grh . dgid . raw ) ;
}
}
int mlx4_ib_query_qp ( struct ib_qp * ibqp , struct ib_qp_attr * qp_attr , int qp_attr_mask ,
struct ib_qp_init_attr * qp_init_attr )
{
struct mlx4_ib_dev * dev = to_mdev ( ibqp - > device ) ;
struct mlx4_ib_qp * qp = to_mqp ( ibqp ) ;
struct mlx4_qp_context context ;
int mlx4_state ;
int err ;
if ( qp - > state = = IB_QPS_RESET ) {
qp_attr - > qp_state = IB_QPS_RESET ;
goto done ;
}
err = mlx4_qp_query ( dev - > dev , & qp - > mqp , & context ) ;
if ( err )
return - EINVAL ;
mlx4_state = be32_to_cpu ( context . flags ) > > 28 ;
qp_attr - > qp_state = to_ib_qp_state ( mlx4_state ) ;
qp_attr - > path_mtu = context . mtu_msgmax > > 5 ;
qp_attr - > path_mig_state =
to_ib_mig_state ( ( be32_to_cpu ( context . flags ) > > 11 ) & 0x3 ) ;
qp_attr - > qkey = be32_to_cpu ( context . qkey ) ;
qp_attr - > rq_psn = be32_to_cpu ( context . rnr_nextrecvpsn ) & 0xffffff ;
qp_attr - > sq_psn = be32_to_cpu ( context . next_send_psn ) & 0xffffff ;
qp_attr - > dest_qp_num = be32_to_cpu ( context . remote_qpn ) & 0xffffff ;
qp_attr - > qp_access_flags =
to_ib_qp_access_flags ( be32_to_cpu ( context . params2 ) ) ;
if ( qp - > ibqp . qp_type = = IB_QPT_RC | | qp - > ibqp . qp_type = = IB_QPT_UC ) {
to_ib_ah_attr ( dev - > dev , & qp_attr - > ah_attr , & context . pri_path ) ;
to_ib_ah_attr ( dev - > dev , & qp_attr - > alt_ah_attr , & context . alt_path ) ;
qp_attr - > alt_pkey_index = context . alt_path . pkey_index & 0x7f ;
qp_attr - > alt_port_num = qp_attr - > alt_ah_attr . port_num ;
}
qp_attr - > pkey_index = context . pri_path . pkey_index & 0x7f ;
2007-07-17 18:37:38 -07:00
if ( qp_attr - > qp_state = = IB_QPS_INIT )
qp_attr - > port_num = qp - > port ;
else
qp_attr - > port_num = context . pri_path . sched_queue & 0x40 ? 2 : 1 ;
2007-06-21 12:27:47 +03:00
/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
qp_attr - > sq_draining = mlx4_state = = MLX4_QP_STATE_SQ_DRAINING ;
qp_attr - > max_rd_atomic = 1 < < ( ( be32_to_cpu ( context . params1 ) > > 21 ) & 0x7 ) ;
qp_attr - > max_dest_rd_atomic =
1 < < ( ( be32_to_cpu ( context . params2 ) > > 21 ) & 0x7 ) ;
qp_attr - > min_rnr_timer =
( be32_to_cpu ( context . rnr_nextrecvpsn ) > > 24 ) & 0x1f ;
qp_attr - > timeout = context . pri_path . ackto > > 3 ;
qp_attr - > retry_cnt = ( be32_to_cpu ( context . params1 ) > > 16 ) & 0x7 ;
qp_attr - > rnr_retry = ( be32_to_cpu ( context . params1 ) > > 13 ) & 0x7 ;
qp_attr - > alt_timeout = context . alt_path . ackto > > 3 ;
done :
qp_attr - > cur_qp_state = qp_attr - > qp_state ;
2007-07-17 20:59:02 -07:00
qp_attr - > cap . max_recv_wr = qp - > rq . wqe_cnt ;
qp_attr - > cap . max_recv_sge = qp - > rq . max_gs ;
2007-06-21 12:27:47 +03:00
if ( ! ibqp - > uobject ) {
2007-07-17 20:59:02 -07:00
qp_attr - > cap . max_send_wr = qp - > sq . wqe_cnt ;
qp_attr - > cap . max_send_sge = qp - > sq . max_gs ;
} else {
qp_attr - > cap . max_send_wr = 0 ;
qp_attr - > cap . max_send_sge = 0 ;
2007-06-21 12:27:47 +03:00
}
2007-07-17 20:59:02 -07:00
/*
* We don ' t support inline sends for kernel QPs ( yet ) , and we
* don ' t know what userspace ' s value should be .
*/
qp_attr - > cap . max_inline_data = 0 ;
qp_init_attr - > cap = qp_attr - > cap ;
2007-06-21 12:27:47 +03:00
return 0 ;
}