root/usr/src/uts/common/sys/ib/adapters/tavor/tavor_qp.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_IB_ADAPTERS_TAVOR_QP_H
#define _SYS_IB_ADAPTERS_TAVOR_QP_H

/*
 * tavor_qp.h
 *    Contains all of the prototypes, #defines, and structures necessary
 *    for all of the Queue Pair Processing routines.
 *    Specifically it contains the various flags, structures used for managing
 *    Tavor queue pairs, and prototypes for many of the functions consumed by
 *    other parts of the Tavor driver (including those routines directly
 *    exposed through the IBTF CI interface).
 */

#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

#ifdef __cplusplus
extern "C" {
#endif


/*
 * The following defines specify the default number of Queue Pairs (QP) and
 * their maximum size.  Settings exist for the supported DDR DIMM sizes of
 * 128MB and 256MB.  If a DIMM greater than 256 is found, then the 256MB
 * profile is used.  See tavor_cfg.c for more discussion on config profiles.
 *
 * For manual configuration (not using config profiles), these values are
 * controllable through the "tavor_log_max_qp_sz" and "tavor_log_num_qp"
 * configuration variables, respectively. To override config profile settings
 * the 'tavor_alt_config_enable' configuration variable must first be set.
 *
 * Note: We also have a define for the minimum size of a QP.  QPs allocated
 * with size 0, 1, 2, or 3 will always get back a QP of size 4.  This is the
 * smallest size that Tavor hardware and software can correctly handle.
 */
#define TAVOR_NUM_QP_SHIFT_128          0x10
#define TAVOR_NUM_QP_SHIFT_256          0x11
#define TAVOR_QP_SZ_SHIFT               0x10
#define TAVOR_QP_SZ                     (1 << TAVOR_QP_SZ_SHIFT)
#define TAVOR_QP_MIN_SIZE               0x4

/*
 * Minimal configuration values.
 */
#define TAVOR_NUM_QP_SHIFT_MIN          0xD
#define TAVOR_QP_SZ_SHIFT_MIN           0x9

/*
 * The following macro determines whether the contents of QP memory (WQEs)
 * need to be sync'd (with ddi_dma_sync()).  This decision is based on whether
 * the QP memory is in DDR memory (no sync) or system memory (sync required).
 * And it also supports the possibility that if a CQ in system memory is mapped
 * DDI_DMA_CONSISTENT, it can be configured to not be sync'd because of the
 * "sync override" parameter in the config profile.
 */
#define TAVOR_QP_IS_SYNC_REQ(state, wqinfo)                             \
        ((((((state)->ts_cfg_profile->cp_streaming_consistent) &&       \
        ((state)->ts_cfg_profile->cp_consistent_syncoverride))) ||      \
        ((wqinfo).qa_location == TAVOR_QUEUE_LOCATION_INDDR))           \
        ? 0 : 1)

/*
 * The following defines specify the size of the individual Queue Pair
 * Context (QPC) entries.  Below we also specify the size of the "Extended
 * QPC entries as well.
 */
#define TAVOR_QPC_SIZE_SHIFT            0x8
#define TAVOR_QPC_SIZE                  (1 << TAVOR_QPC_SIZE_SHIFT)
#define TAVOR_EQPC_SIZE_SHIFT           0x5
#define TAVOR_EQPC_SIZE                 (1 << TAVOR_EQPC_SIZE_SHIFT)

/*
 * The following defines specify the default number of Tavor RDMA Backing
 * entries (RDB).  Settings exist for the supported DDR DIMM sizes of 128MB and
 * 256MB.  If a DIMM greater than 256 is found, then the 256MB profile is used.
 * See tavor_cfg.c for more discussion on config profiles.
 *
 * For manual configuration (not using config profiles), this value is
 * controllable through the "tavor_log_num_rdb" configuration variable.  To
 * override config profile settings the 'tavor_alt_config_enable' configuration
 * variable must first be set.
 *
 * Below we also include the defines that are used to specify four (4)
 * outstanding RDMA Reads/Atomics per QP.
 */

#define TAVOR_NUM_RDB_SHIFT_128         0x12
#define TAVOR_NUM_RDB_SHIFT_256         0x13

#define TAVOR_HCA_MAX_RDMA_IN_QP        0x4
#define TAVOR_HCA_MAX_RDMA_OUT_QP       0x4

/*
 * Minimal configuration value.
 */
#define TAVOR_NUM_RDB_SHIFT_MIN         0xC

/*
 * The following defines specify the size of the individual RDMA Backing
 * entries (RDB).
 */
#define TAVOR_RDB_SIZE_SHIFT            0x5
#define TAVOR_RDB_SIZE                  (1 << TAVOR_RDB_SIZE_SHIFT)

/*
 * This defines the maximum number of SGLs per WQE.  This value is
 * controllable through the "tavor_wqe_max_sgl" configuration variable (but
 * should not be set larger than this value).
 */
#define TAVOR_NUM_WQE_SGL               0x10

/* Define for maximum QP number mask (QP number is 24 bits) */
#define TAVOR_QP_MAXNUMBER_MSK          0xFFFFFF

/*
 * This define and the following macro are used to find a schedule queue for
 * a new QP based on its queue pair number.  Note:  This is a rather simple
 * method that we use today.  We simply choose from the schedule queue based
 * on the 4 least significant bits of the QP number.
 */
#define TAVOR_QP_TO_SCHEDQ_MASK         0xF
#define TAVOR_QP_SCHEDQ_GET(qpnum)      ((qpnum) & TAVOR_QP_TO_SCHEDQ_MASK)

/*
 * This define determines the frequency with which the AckReq bit will be
 * set in outgoing RC packets.  By default it is set to five (5) or 2^5 = 32.
 * So AckReq will be set once every 32 packets sent.  This value is
 * controllable through the "tavor_qp_ackreq_freq" configuration variable.
 */
#define TAVOR_QP_ACKREQ_FREQ            0x5

/*
 * Define the maximum message size (log 2).  Note: This value corresponds
 * to the maximum allowable message sized as defined by the IBA spec.
 */
#define TAVOR_QP_LOG_MAX_MSGSZ          0x1F

/*
 * This macro is used to determine the appropriate alignment for a Tavor
 * work queue (see tavor_qp_alloc() and tavor_special_qp_alloc()).  Note:
 * Tavor work queues are aligned on their combined size (i.e. combined size
 * of send queue and receive queue) because of certain hardware limitations
 * (i.e. work queue memory cannot cross a 32-bit boundary).
 */
#define TAVOR_QP_WQ_ALIGN(qp_size)                                      \
        (1 << ((((qp_size) & ((qp_size) - 1)) == 0) ?                   \
        highbit((qp_size)) - 1 : highbit((qp_size))))

/*
 * This macro is used to determine if the tavor known QP type (qp_serv) is the
 * same as the caller passed in IBT type (qp_trans).  This is used in QP modify
 * to ensure the types match.
 */
#define TAVOR_QP_TYPE_VALID(qp_trans, qp_serv)                          \
        ((qp_trans == IBT_UD_SRV && qp_serv == TAVOR_QP_UD) ||          \
        (qp_trans == IBT_RC_SRV && qp_serv == TAVOR_QP_RC) ||           \
        (qp_trans == IBT_UC_SRV && qp_serv == TAVOR_QP_UC))

/*
 * The following enumerated type is used to capture all the various types
 * of Tavor work queue types.  Note: It is specifically used as an argument
 * to the tavor_qp_sgl_to_logwqesz() routine.
 * The defines below are also used by the tavor_qp_sgl_to_logwqesz() routine
 * they indicate the amount of overhead (in WQE header size) consumed by
 * each of the following types of WQEs.  This information is used to round
 * the WQE size to the next largest power-of-2 (and to determine the number
 * of SGLs that are supported for the given WQE type).  There is also a define
 * below used to specify the minimum size for a WQE.  The minimum size is set
 * to 64 bytes (a single cacheline).
 */
typedef enum {
        TAVOR_QP_WQ_TYPE_SENDQ,
        TAVOR_QP_WQ_TYPE_RECVQ,
        TAVOR_QP_WQ_TYPE_SENDMLX_QP0,
        TAVOR_QP_WQ_TYPE_SENDMLX_QP1
} tavor_qp_wq_type_t;
#define TAVOR_QP_WQE_MAX_SIZE           0x3F0
#define TAVOR_QP_WQE_MLX_SND_HDRS       0x40
#define TAVOR_QP_WQE_MLX_RCV_HDRS       0x10
#define TAVOR_QP_WQE_MLX_QP0_HDRS       0x40
#define TAVOR_QP_WQE_MLX_QP1_HDRS       0x70
#define TAVOR_QP_WQE_LOG_MINIMUM        0x6


/*
 * The tavor_qp_info_t structure is used internally by the Tavor driver to
 * pass information to and from the tavor_qp_alloc() and
 * tavor_special_qp_alloc() routines.  It contains placeholders for all of the
 * potential inputs and outputs that either routine can take.
 */
typedef struct tavor_qp_info_s {
        ibt_qp_alloc_attr_t     *qpi_attrp;
        uint_t                  qpi_type;
        uint_t                  qpi_port;
        ibtl_qp_hdl_t           qpi_ibt_qphdl;
        ibt_chan_sizes_t        *qpi_queueszp;
        ib_qpn_t                *qpi_qpn;
        tavor_qphdl_t           qpi_qphdl;
} tavor_qp_info_t;

/*
 * The QPN entry which is stored in the AVL tree
 */
typedef struct tavor_qpn_entry_s {
        avl_node_t              qpn_avlnode;
        uint_t                  qpn_refcnt;
        uint_t                  qpn_counter;
        uint_t                  qpn_indx;
        tavor_rsrc_t            *qpn_qpc;
} tavor_qpn_entry_t;
#define TAVOR_QPN_NOFLAG                0x0
#define TAVOR_QPN_RELEASE               0x1
#define TAVOR_QPN_FREE_ONLY             0x2

/*
 * The tavor_sw_qp_s structure is also referred to using the "tavor_qphdl_t"
 * typedef (see tavor_typedef.h).  It encodes all the information necessary
 * to track the various resources needed to allocate, query, modify, and
 * (later) free both normal QP and special QP.
 *
 * Specifically, it has a lock to ensure single threaded access to the QP.
 * It has QP state, type, and number, pointers to the PD, MR, and CQ handles
 * associated with the QP, and pointers to the buffer where the work queues
 * come from.
 *
 * It has two pointers (one per work queue) to the workQ headers for the WRID
 * list, as well as pointers to the last WQE on each chain (used when
 * connecting a new chain of WQEs to a previously executing chain - see
 * tavor_wr.c).  It's also got the real WQE size, real number of SGL per WQE,
 * and the size of each of the work queues (in number of WQEs).
 *
 * Additionally, it has pointers to the resources associated with the QP
 * (including the obligatory backpointer to the resource for the QP handle
 * itself.  But it also has some flags, like "qp_forward_sqd_event" and
 * "qp_sqd_still_draining" (which are used to indicate whether a Send Queue
 * Drained Event should be forwarded to the IBTF) or "qp_is_special",
 * "qp_portnum", and "qp_pkeyindx" (which are used by special QP to store
 * necessary information about the type of the QP, which port it's connected
 * to, and what its current PKey index is set to).
 */
struct tavor_sw_qp_s {
        kmutex_t                qp_lock;
        uint_t                  qp_state;
        uint32_t                qp_qpnum;
        tavor_pdhdl_t           qp_pdhdl;
        uint_t                  qp_serv_type;
        uint_t                  qp_sync;
        tavor_mrhdl_t           qp_mrhdl;
        uint_t                  qp_sq_sigtype;
        uint_t                  qp_is_special;
        uint_t                  qp_is_umap;
        uint32_t                qp_uarpg;
        devmap_cookie_t         qp_umap_dhp;
        uint_t                  qp_portnum;
        uint_t                  qp_pkeyindx;

        /* Send Work Queue */
        tavor_cqhdl_t           qp_sq_cqhdl;
        uint64_t                *qp_sq_lastwqeaddr;
        tavor_workq_hdr_t       *qp_sq_wqhdr;
        uint32_t                *qp_sq_buf;
        uint32_t                qp_sq_bufsz;
        uint32_t                qp_sq_log_wqesz;
        uint32_t                qp_sq_sgl;

        /* Receive Work Queue */
        tavor_cqhdl_t           qp_rq_cqhdl;
        uint64_t                *qp_rq_lastwqeaddr;
        tavor_workq_hdr_t       *qp_rq_wqhdr;
        uint32_t                *qp_rq_buf;
        uint32_t                qp_rq_bufsz;
        uint32_t                qp_rq_log_wqesz;
        uint32_t                qp_rq_sgl;

        uint64_t                qp_desc_off;

        tavor_rsrc_t            *qp_qpcrsrcp;
        tavor_rsrc_t            *qp_rsrcp;
        void                    *qp_hdlrarg;
        tavor_rsrc_t            *qp_rdbrsrcp;
        uint64_t                qp_rdb_ddraddr;
        uint_t                  qp_forward_sqd_event;
        uint_t                  qp_sqd_still_draining;

        /* Shared Receive Queue */
        tavor_srqhdl_t          qp_srqhdl;
        uint_t                  qp_srq_en;

        /* Refcnt of QP belongs to an MCG */
        uint_t                  qp_mcg_refcnt;

        /* save the mtu & srate from init2rtr for future use */
        uint_t                  qp_save_mtu;
        ibt_srate_t             qp_save_srate;
        tavor_qpn_entry_t       *qp_qpn_hdl;

        struct tavor_qalloc_info_s qp_wqinfo;

        struct tavor_hw_qpc_s qpc;
};
_NOTE(READ_ONLY_DATA(tavor_sw_qp_s::qp_qpnum
    tavor_sw_qp_s::qp_sync
    tavor_sw_qp_s::qp_sq_buf
    tavor_sw_qp_s::qp_sq_log_wqesz
    tavor_sw_qp_s::qp_sq_bufsz
    tavor_sw_qp_s::qp_sq_sgl
    tavor_sw_qp_s::qp_rq_buf
    tavor_sw_qp_s::qp_rq_log_wqesz
    tavor_sw_qp_s::qp_rq_bufsz
    tavor_sw_qp_s::qp_rq_sgl
    tavor_sw_qp_s::qp_desc_off
    tavor_sw_qp_s::qp_mrhdl
    tavor_sw_qp_s::qp_wqinfo
    tavor_sw_qp_s::qp_qpcrsrcp
    tavor_sw_qp_s::qp_rsrcp
    tavor_sw_qp_s::qp_hdlrarg
    tavor_sw_qp_s::qp_pdhdl
    tavor_sw_qp_s::qp_sq_cqhdl
    tavor_sw_qp_s::qp_rq_cqhdl
    tavor_sw_qp_s::qp_sq_sigtype
    tavor_sw_qp_s::qp_serv_type
    tavor_sw_qp_s::qp_is_special
    tavor_sw_qp_s::qp_is_umap
    tavor_sw_qp_s::qp_uarpg
    tavor_sw_qp_s::qp_portnum
    tavor_sw_qp_s::qp_qpn_hdl))
_NOTE(MUTEX_PROTECTS_DATA(tavor_sw_qp_s::qp_lock,
    tavor_sw_qp_s::qp_sq_wqhdr
    tavor_sw_qp_s::qp_sq_lastwqeaddr
    tavor_sw_qp_s::qp_rq_wqhdr
    tavor_sw_qp_s::qp_rq_lastwqeaddr
    tavor_sw_qp_s::qp_state
    tavor_sw_qp_s::qp_rdbrsrcp
    tavor_sw_qp_s::qp_rdb_ddraddr
    tavor_sw_qp_s::qpc
    tavor_sw_qp_s::qp_forward_sqd_event
    tavor_sw_qp_s::qp_sqd_still_draining
    tavor_sw_qp_s::qp_mcg_refcnt
    tavor_sw_qp_s::qp_save_mtu
    tavor_sw_qp_s::qp_umap_dhp))

/*
 * The following defines are used to indicate whether a QP is special or
 * not (and what type it is).  They are used in the "qp_is_special" field
 * above.
 */
#define TAVOR_QP_SMI                    0x1
#define TAVOR_QP_GSI                    0x2

/*
 * The tavor_qp_options_t structure is used in the Tavor QP allocation
 * routines to provide additional option functionality.  When a NULL pointer
 * is passed in place of a pointer to this struct, it is a way of specifying
 * the "default" behavior.  Using this structure, however, is a way of
 * controlling any extended behavior.
 *
 * Currently, the only defined "extended" behavior is for specifying whether
 * a given QP's work queues should be allocated from kernel system memory
 * (TAVOR_QUEUE_LOCATION_NORMAL) or should be allocated from local DDR memory
 * (TAVOR_QUEUE_LOCATION_INDDR).  This defaults today to always allocating
 * from kernel system memory but can be changed by using the
 * "tavor_qp_wq_inddr" configuration variable.
 */
typedef struct tavor_qp_options_s {
        uint_t                  qpo_wq_loc;
} tavor_qp_options_t;


/* Defined in tavor_qp.c */
int tavor_qp_alloc(tavor_state_t *state, tavor_qp_info_t *qpinfo,
    uint_t sleepflag, tavor_qp_options_t *op);
int tavor_special_qp_alloc(tavor_state_t *state, tavor_qp_info_t *qpinfo,
    uint_t sleepflag, tavor_qp_options_t *op);
int tavor_qp_free(tavor_state_t *state, tavor_qphdl_t *qphdl,
    ibc_free_qp_flags_t free_qp_flags, ibc_qpn_hdl_t *qpnh, uint_t sleepflag);
int tavor_qp_query(tavor_state_t *state, tavor_qphdl_t qphdl,
    ibt_qp_query_attr_t *attr_p);
tavor_qphdl_t tavor_qphdl_from_qpnum(tavor_state_t *state, uint_t qpnum);
void tavor_qp_release_qpn(tavor_state_t *state, tavor_qpn_entry_t *entry,
    int flags);
void tavor_qpn_avl_init(tavor_state_t *state);
void tavor_qpn_avl_fini(tavor_state_t *state);

/* Defined in tavor_qpmod.c */
int tavor_qp_modify(tavor_state_t *state, tavor_qphdl_t qp,
    ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p,
    ibt_queue_sizes_t *actual_sz);
int tavor_qp_to_reset(tavor_state_t *state, tavor_qphdl_t qp);

#ifdef __cplusplus
}
#endif

#endif  /* _SYS_IB_ADAPTERS_TAVOR_QP_H */