root/drivers/infiniband/hw/ionic/ionic_fw.h
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */

#ifndef _IONIC_FW_H_
#define _IONIC_FW_H_

#include <linux/kernel.h>
#include <rdma/ib_verbs.h>

/* common for ib spec */

#define IONIC_EXP_DBELL_SZ              8

enum ionic_mrid_bits {
        IONIC_MRID_INDEX_SHIFT          = 8,
};

static inline u32 ionic_mrid(u32 index, u8 key)
{
        return (index << IONIC_MRID_INDEX_SHIFT) | key;
}

static inline u32 ionic_mrid_index(u32 lrkey)
{
        return lrkey >> IONIC_MRID_INDEX_SHIFT;
}

/* common to all versions */

/* wqe scatter gather element */
struct ionic_sge {
        __be64                          va;
        __be32                          len;
        __be32                          lkey;
};

/* admin queue mr type */
enum ionic_mr_flags {
        /* bits that determine mr access */
        IONIC_MRF_LOCAL_WRITE           = BIT(0),
        IONIC_MRF_REMOTE_WRITE          = BIT(1),
        IONIC_MRF_REMOTE_READ           = BIT(2),
        IONIC_MRF_REMOTE_ATOMIC         = BIT(3),
        IONIC_MRF_MW_BIND               = BIT(4),
        IONIC_MRF_ZERO_BASED            = BIT(5),
        IONIC_MRF_ON_DEMAND             = BIT(6),
        IONIC_MRF_PB                    = BIT(7),
        IONIC_MRF_ACCESS_MASK           = BIT(12) - 1,

        /* bits that determine mr type */
        IONIC_MRF_UKEY_EN               = BIT(13),
        IONIC_MRF_IS_MW                 = BIT(14),
        IONIC_MRF_INV_EN                = BIT(15),

        /* base flags combinations for mr types */
        IONIC_MRF_USER_MR               = 0,
        IONIC_MRF_PHYS_MR               = (IONIC_MRF_UKEY_EN |
                                           IONIC_MRF_INV_EN),
        IONIC_MRF_MW_1                  = (IONIC_MRF_UKEY_EN |
                                           IONIC_MRF_IS_MW),
        IONIC_MRF_MW_2                  = (IONIC_MRF_UKEY_EN |
                                           IONIC_MRF_IS_MW |
                                           IONIC_MRF_INV_EN),
};

static inline int to_ionic_mr_flags(int access)
{
        int flags = 0;

        if (access & IB_ACCESS_LOCAL_WRITE)
                flags |= IONIC_MRF_LOCAL_WRITE;

        if (access & IB_ACCESS_REMOTE_READ)
                flags |= IONIC_MRF_REMOTE_READ;

        if (access & IB_ACCESS_REMOTE_WRITE)
                flags |= IONIC_MRF_REMOTE_WRITE;

        if (access & IB_ACCESS_REMOTE_ATOMIC)
                flags |= IONIC_MRF_REMOTE_ATOMIC;

        if (access & IB_ACCESS_MW_BIND)
                flags |= IONIC_MRF_MW_BIND;

        if (access & IB_ZERO_BASED)
                flags |= IONIC_MRF_ZERO_BASED;

        return flags;
}

enum ionic_qp_flags {
        /* bits that determine qp access */
        IONIC_QPF_REMOTE_WRITE          = BIT(0),
        IONIC_QPF_REMOTE_READ           = BIT(1),
        IONIC_QPF_REMOTE_ATOMIC         = BIT(2),

        /* bits that determine other qp behavior */
        IONIC_QPF_SQ_PB                 = BIT(6),
        IONIC_QPF_RQ_PB                 = BIT(7),
        IONIC_QPF_SQ_SPEC               = BIT(8),
        IONIC_QPF_RQ_SPEC               = BIT(9),
        IONIC_QPF_REMOTE_PRIVILEGED     = BIT(10),
        IONIC_QPF_SQ_DRAINING           = BIT(11),
        IONIC_QPF_SQD_NOTIFY            = BIT(12),
        IONIC_QPF_SQ_CMB                = BIT(13),
        IONIC_QPF_RQ_CMB                = BIT(14),
        IONIC_QPF_PRIVILEGED            = BIT(15),
};

static inline int from_ionic_qp_flags(int flags)
{
        int access_flags = 0;

        if (flags & IONIC_QPF_REMOTE_WRITE)
                access_flags |= IB_ACCESS_REMOTE_WRITE;

        if (flags & IONIC_QPF_REMOTE_READ)
                access_flags |= IB_ACCESS_REMOTE_READ;

        if (flags & IONIC_QPF_REMOTE_ATOMIC)
                access_flags |= IB_ACCESS_REMOTE_ATOMIC;

        return access_flags;
}

static inline int to_ionic_qp_flags(int access, bool sqd_notify,
                                    bool sq_is_cmb, bool rq_is_cmb,
                                    bool sq_spec, bool rq_spec,
                                    bool privileged, bool remote_privileged)
{
        int flags = 0;

        if (access & IB_ACCESS_REMOTE_WRITE)
                flags |= IONIC_QPF_REMOTE_WRITE;

        if (access & IB_ACCESS_REMOTE_READ)
                flags |= IONIC_QPF_REMOTE_READ;

        if (access & IB_ACCESS_REMOTE_ATOMIC)
                flags |= IONIC_QPF_REMOTE_ATOMIC;

        if (sqd_notify)
                flags |= IONIC_QPF_SQD_NOTIFY;

        if (sq_is_cmb)
                flags |= IONIC_QPF_SQ_CMB;

        if (rq_is_cmb)
                flags |= IONIC_QPF_RQ_CMB;

        if (sq_spec)
                flags |= IONIC_QPF_SQ_SPEC;

        if (rq_spec)
                flags |= IONIC_QPF_RQ_SPEC;

        if (privileged)
                flags |= IONIC_QPF_PRIVILEGED;

        if (remote_privileged)
                flags |= IONIC_QPF_REMOTE_PRIVILEGED;

        return flags;
}

/* cqe non-admin status indicated in status_length field when err bit is set */
enum ionic_status {
        IONIC_STS_OK,
        IONIC_STS_LOCAL_LEN_ERR,
        IONIC_STS_LOCAL_QP_OPER_ERR,
        IONIC_STS_LOCAL_PROT_ERR,
        IONIC_STS_WQE_FLUSHED_ERR,
        IONIC_STS_MEM_MGMT_OPER_ERR,
        IONIC_STS_BAD_RESP_ERR,
        IONIC_STS_LOCAL_ACC_ERR,
        IONIC_STS_REMOTE_INV_REQ_ERR,
        IONIC_STS_REMOTE_ACC_ERR,
        IONIC_STS_REMOTE_OPER_ERR,
        IONIC_STS_RETRY_EXCEEDED,
        IONIC_STS_RNR_RETRY_EXCEEDED,
        IONIC_STS_XRC_VIO_ERR,
        IONIC_STS_LOCAL_SGL_INV_ERR,
};

static inline int ionic_to_ib_status(int sts)
{
        switch (sts) {
        case IONIC_STS_OK:
                return IB_WC_SUCCESS;
        case IONIC_STS_LOCAL_LEN_ERR:
                return IB_WC_LOC_LEN_ERR;
        case IONIC_STS_LOCAL_QP_OPER_ERR:
        case IONIC_STS_LOCAL_SGL_INV_ERR:
                return IB_WC_LOC_QP_OP_ERR;
        case IONIC_STS_LOCAL_PROT_ERR:
                return IB_WC_LOC_PROT_ERR;
        case IONIC_STS_WQE_FLUSHED_ERR:
                return IB_WC_WR_FLUSH_ERR;
        case IONIC_STS_MEM_MGMT_OPER_ERR:
                return IB_WC_MW_BIND_ERR;
        case IONIC_STS_BAD_RESP_ERR:
                return IB_WC_BAD_RESP_ERR;
        case IONIC_STS_LOCAL_ACC_ERR:
                return IB_WC_LOC_ACCESS_ERR;
        case IONIC_STS_REMOTE_INV_REQ_ERR:
                return IB_WC_REM_INV_REQ_ERR;
        case IONIC_STS_REMOTE_ACC_ERR:
                return IB_WC_REM_ACCESS_ERR;
        case IONIC_STS_REMOTE_OPER_ERR:
                return IB_WC_REM_OP_ERR;
        case IONIC_STS_RETRY_EXCEEDED:
                return IB_WC_RETRY_EXC_ERR;
        case IONIC_STS_RNR_RETRY_EXCEEDED:
                return IB_WC_RNR_RETRY_EXC_ERR;
        case IONIC_STS_XRC_VIO_ERR:
        default:
                return IB_WC_GENERAL_ERR;
        }
}

/* admin queue qp type */
enum ionic_qp_type {
        IONIC_QPT_RC,
        IONIC_QPT_UC,
        IONIC_QPT_RD,
        IONIC_QPT_UD,
        IONIC_QPT_SRQ,
        IONIC_QPT_XRC_INI,
        IONIC_QPT_XRC_TGT,
        IONIC_QPT_XRC_SRQ,
};

static inline int to_ionic_qp_type(enum ib_qp_type type)
{
        switch (type) {
        case IB_QPT_GSI:
        case IB_QPT_UD:
                return IONIC_QPT_UD;
        case IB_QPT_RC:
                return IONIC_QPT_RC;
        case IB_QPT_UC:
                return IONIC_QPT_UC;
        case IB_QPT_XRC_INI:
                return IONIC_QPT_XRC_INI;
        case IB_QPT_XRC_TGT:
                return IONIC_QPT_XRC_TGT;
        default:
                return -EINVAL;
        }
}

/* admin queue qp state */
enum ionic_qp_state {
        IONIC_QPS_RESET,
        IONIC_QPS_INIT,
        IONIC_QPS_RTR,
        IONIC_QPS_RTS,
        IONIC_QPS_SQD,
        IONIC_QPS_SQE,
        IONIC_QPS_ERR,
};

static inline int from_ionic_qp_state(enum ionic_qp_state state)
{
        switch (state) {
        case IONIC_QPS_RESET:
                return IB_QPS_RESET;
        case IONIC_QPS_INIT:
                return IB_QPS_INIT;
        case IONIC_QPS_RTR:
                return IB_QPS_RTR;
        case IONIC_QPS_RTS:
                return IB_QPS_RTS;
        case IONIC_QPS_SQD:
                return IB_QPS_SQD;
        case IONIC_QPS_SQE:
                return IB_QPS_SQE;
        case IONIC_QPS_ERR:
                return IB_QPS_ERR;
        default:
                return -EINVAL;
        }
}

static inline int to_ionic_qp_state(enum ib_qp_state state)
{
        switch (state) {
        case IB_QPS_RESET:
                return IONIC_QPS_RESET;
        case IB_QPS_INIT:
                return IONIC_QPS_INIT;
        case IB_QPS_RTR:
                return IONIC_QPS_RTR;
        case IB_QPS_RTS:
                return IONIC_QPS_RTS;
        case IB_QPS_SQD:
                return IONIC_QPS_SQD;
        case IB_QPS_SQE:
                return IONIC_QPS_SQE;
        case IB_QPS_ERR:
                return IONIC_QPS_ERR;
        default:
                return 0;
        }
}

static inline int to_ionic_qp_modify_state(enum ib_qp_state to_state,
                                           enum ib_qp_state from_state)
{
        return to_ionic_qp_state(to_state) |
                (to_ionic_qp_state(from_state) << 4);
}

/* fw abi v1 */

/* data payload part of v1 wqe */
union ionic_v1_pld {
        struct ionic_sge        sgl[2];
        __be32                  spec32[8];
        __be16                  spec16[16];
        __u8                    data[32];
};

/* completion queue v1 cqe */
struct ionic_v1_cqe {
        union {
                struct {
                        __be16          cmd_idx;
                        __u8            cmd_op;
                        __u8            rsvd[17];
                        __le16          old_sq_cindex;
                        __le16          old_rq_cq_cindex;
                } admin;
                struct {
                        __u64           wqe_id;
                        __be32          src_qpn_op;
                        __u8            src_mac[6];
                        __be16          vlan_tag;
                        __be32          imm_data_rkey;
                } recv;
                struct {
                        __u8            rsvd[4];
                        __be32          msg_msn;
                        __u8            rsvd2[8];
                        __u64           npg_wqe_id;
                } send;
        };
        __be32                          status_length;
        __be32                          qid_type_flags;
};

/* bits for cqe recv */
enum ionic_v1_cqe_src_qpn_bits {
        IONIC_V1_CQE_RECV_QPN_MASK      = 0xffffff,
        IONIC_V1_CQE_RECV_OP_SHIFT      = 24,

        /* MASK could be 0x3, but need 0x1f for makeshift values:
         * OP_TYPE_RDMA_OPER_WITH_IMM, OP_TYPE_SEND_RCVD
         */
        IONIC_V1_CQE_RECV_OP_MASK       = 0x1f,
        IONIC_V1_CQE_RECV_OP_SEND       = 0,
        IONIC_V1_CQE_RECV_OP_SEND_INV   = 1,
        IONIC_V1_CQE_RECV_OP_SEND_IMM   = 2,
        IONIC_V1_CQE_RECV_OP_RDMA_IMM   = 3,

        IONIC_V1_CQE_RECV_IS_IPV4       = BIT(7 + IONIC_V1_CQE_RECV_OP_SHIFT),
        IONIC_V1_CQE_RECV_IS_VLAN       = BIT(6 + IONIC_V1_CQE_RECV_OP_SHIFT),
};

/* bits for cqe qid_type_flags */
enum ionic_v1_cqe_qtf_bits {
        IONIC_V1_CQE_COLOR              = BIT(0),
        IONIC_V1_CQE_ERROR              = BIT(1),
        IONIC_V1_CQE_TYPE_SHIFT         = 5,
        IONIC_V1_CQE_TYPE_MASK          = 0x7,
        IONIC_V1_CQE_QID_SHIFT          = 8,

        IONIC_V1_CQE_TYPE_ADMIN         = 0,
        IONIC_V1_CQE_TYPE_RECV          = 1,
        IONIC_V1_CQE_TYPE_SEND_MSN      = 2,
        IONIC_V1_CQE_TYPE_SEND_NPG      = 3,
};

static inline bool ionic_v1_cqe_color(struct ionic_v1_cqe *cqe)
{
        return cqe->qid_type_flags & cpu_to_be32(IONIC_V1_CQE_COLOR);
}

static inline bool ionic_v1_cqe_error(struct ionic_v1_cqe *cqe)
{
        return cqe->qid_type_flags & cpu_to_be32(IONIC_V1_CQE_ERROR);
}

static inline bool ionic_v1_cqe_recv_is_ipv4(struct ionic_v1_cqe *cqe)
{
        return cqe->recv.src_qpn_op & cpu_to_be32(IONIC_V1_CQE_RECV_IS_IPV4);
}

static inline bool ionic_v1_cqe_recv_is_vlan(struct ionic_v1_cqe *cqe)
{
        return cqe->recv.src_qpn_op & cpu_to_be32(IONIC_V1_CQE_RECV_IS_VLAN);
}

static inline void ionic_v1_cqe_clean(struct ionic_v1_cqe *cqe)
{
        cqe->qid_type_flags |= cpu_to_be32(~0u << IONIC_V1_CQE_QID_SHIFT);
}

static inline u32 ionic_v1_cqe_qtf(struct ionic_v1_cqe *cqe)
{
        return be32_to_cpu(cqe->qid_type_flags);
}

static inline u8 ionic_v1_cqe_qtf_type(u32 qtf)
{
        return (qtf >> IONIC_V1_CQE_TYPE_SHIFT) & IONIC_V1_CQE_TYPE_MASK;
}

static inline u32 ionic_v1_cqe_qtf_qid(u32 qtf)
{
        return qtf >> IONIC_V1_CQE_QID_SHIFT;
}

/* v1 base wqe header */
struct ionic_v1_base_hdr {
        __u64                           wqe_id;
        __u8                            op;
        __u8                            num_sge_key;
        __be16                          flags;
        __be32                          imm_data_key;
};

/* v1 receive wqe body */
struct ionic_v1_recv_bdy {
        __u8                            rsvd[16];
        union ionic_v1_pld              pld;
};

/* v1 send/rdma wqe body (common, has sgl) */
struct ionic_v1_common_bdy {
        union {
                struct {
                        __be32          ah_id;
                        __be32          dest_qpn;
                        __be32          dest_qkey;
                } send;
                struct {
                        __be32          remote_va_high;
                        __be32          remote_va_low;
                        __be32          remote_rkey;
                } rdma;
        };
        __be32                          length;
        union ionic_v1_pld              pld;
};

/* v1 atomic wqe body */
struct ionic_v1_atomic_bdy {
        __be32                          remote_va_high;
        __be32                          remote_va_low;
        __be32                          remote_rkey;
        __be32                          swap_add_high;
        __be32                          swap_add_low;
        __be32                          compare_high;
        __be32                          compare_low;
        __u8                            rsvd[4];
        struct ionic_sge                sge;
};

/* v1 reg mr wqe body */
struct ionic_v1_reg_mr_bdy {
        __be64                          va;
        __be64                          length;
        __be64                          offset;
        __be64                          dma_addr;
        __be32                          map_count;
        __be16                          flags;
        __u8                            dir_size_log2;
        __u8                            page_size_log2;
        __u8                            rsvd[8];
};

/* v1 bind mw wqe body */
struct ionic_v1_bind_mw_bdy {
        __be64                          va;
        __be64                          length;
        __be32                          lkey;
        __be16                          flags;
        __u8                            rsvd[26];
};

/* v1 send/recv wqe */
struct ionic_v1_wqe {
        struct ionic_v1_base_hdr        base;
        union {
                struct ionic_v1_recv_bdy        recv;
                struct ionic_v1_common_bdy      common;
                struct ionic_v1_atomic_bdy      atomic;
                struct ionic_v1_reg_mr_bdy      reg_mr;
                struct ionic_v1_bind_mw_bdy     bind_mw;
        };
};

/* queue pair v1 send opcodes */
enum ionic_v1_op {
        IONIC_V1_OP_SEND,
        IONIC_V1_OP_SEND_INV,
        IONIC_V1_OP_SEND_IMM,
        IONIC_V1_OP_RDMA_READ,
        IONIC_V1_OP_RDMA_WRITE,
        IONIC_V1_OP_RDMA_WRITE_IMM,
        IONIC_V1_OP_ATOMIC_CS,
        IONIC_V1_OP_ATOMIC_FA,
        IONIC_V1_OP_REG_MR,
        IONIC_V1_OP_LOCAL_INV,
        IONIC_V1_OP_BIND_MW,

        /* flags */
        IONIC_V1_FLAG_FENCE             = BIT(0),
        IONIC_V1_FLAG_SOL               = BIT(1),
        IONIC_V1_FLAG_INL               = BIT(2),
        IONIC_V1_FLAG_SIG               = BIT(3),

        /* flags last four bits for sgl spec format */
        IONIC_V1_FLAG_SPEC32            = (1u << 12),
        IONIC_V1_FLAG_SPEC16            = (2u << 12),
        IONIC_V1_SPEC_FIRST_SGE         = 2,
};

/* queue pair v2 send opcodes */
enum ionic_v2_op {
        IONIC_V2_OPSL_OUT          = 0x20,
        IONIC_V2_OPSL_IMM          = 0x40,
        IONIC_V2_OPSL_INV          = 0x80,

        IONIC_V2_OP_SEND           = 0x0 | IONIC_V2_OPSL_OUT,
        IONIC_V2_OP_SEND_IMM       = IONIC_V2_OP_SEND | IONIC_V2_OPSL_IMM,
        IONIC_V2_OP_SEND_INV       = IONIC_V2_OP_SEND | IONIC_V2_OPSL_INV,

        IONIC_V2_OP_RDMA_WRITE     = 0x1 | IONIC_V2_OPSL_OUT,
        IONIC_V2_OP_RDMA_WRITE_IMM = IONIC_V2_OP_RDMA_WRITE | IONIC_V2_OPSL_IMM,

        IONIC_V2_OP_RDMA_READ      = 0x2,

        IONIC_V2_OP_ATOMIC_CS      = 0x4,
        IONIC_V2_OP_ATOMIC_FA      = 0x5,
        IONIC_V2_OP_REG_MR         = 0x6,
        IONIC_V2_OP_LOCAL_INV      = 0x7,
        IONIC_V2_OP_BIND_MW        = 0x8,
};

static inline size_t ionic_v1_send_wqe_min_size(int min_sge, int min_data,
                                                int spec, bool expdb)
{
        size_t sz_wqe, sz_sgl, sz_data;

        if (spec > IONIC_V1_SPEC_FIRST_SGE)
                min_sge += IONIC_V1_SPEC_FIRST_SGE;

        if (expdb) {
                min_sge += 1;
                min_data += IONIC_EXP_DBELL_SZ;
        }

        sz_wqe = sizeof(struct ionic_v1_wqe);
        sz_sgl = offsetof(struct ionic_v1_wqe, common.pld.sgl[min_sge]);
        sz_data = offsetof(struct ionic_v1_wqe, common.pld.data[min_data]);

        if (sz_sgl > sz_wqe)
                sz_wqe = sz_sgl;

        if (sz_data > sz_wqe)
                sz_wqe = sz_data;

        return sz_wqe;
}

static inline int ionic_v1_send_wqe_max_sge(u8 stride_log2, int spec,
                                            bool expdb)
{
        struct ionic_sge *sge = (void *)(1ull << stride_log2);
        struct ionic_v1_wqe *wqe = (void *)0;
        int num_sge = 0;

        if (expdb)
                sge -= 1;

        if (spec > IONIC_V1_SPEC_FIRST_SGE)
                num_sge = IONIC_V1_SPEC_FIRST_SGE;

        num_sge = sge - &wqe->common.pld.sgl[num_sge];

        if (spec && num_sge > spec)
                num_sge = spec;

        return num_sge;
}

static inline int ionic_v1_send_wqe_max_data(u8 stride_log2, bool expdb)
{
        struct ionic_v1_wqe *wqe = (void *)0;
        __u8 *data = (void *)(1ull << stride_log2);

        if (expdb)
                data -= IONIC_EXP_DBELL_SZ;

        return data - wqe->common.pld.data;
}

static inline size_t ionic_v1_recv_wqe_min_size(int min_sge, int spec,
                                                bool expdb)
{
        size_t sz_wqe, sz_sgl;

        if (spec > IONIC_V1_SPEC_FIRST_SGE)
                min_sge += IONIC_V1_SPEC_FIRST_SGE;

        if (expdb)
                min_sge += 1;

        sz_wqe = sizeof(struct ionic_v1_wqe);
        sz_sgl = offsetof(struct ionic_v1_wqe, recv.pld.sgl[min_sge]);

        if (sz_sgl > sz_wqe)
                sz_wqe = sz_sgl;

        return sz_wqe;
}

static inline int ionic_v1_recv_wqe_max_sge(u8 stride_log2, int spec,
                                            bool expdb)
{
        struct ionic_sge *sge = (void *)(1ull << stride_log2);
        struct ionic_v1_wqe *wqe = (void *)0;
        int num_sge = 0;

        if (expdb)
                sge -= 1;

        if (spec > IONIC_V1_SPEC_FIRST_SGE)
                num_sge = IONIC_V1_SPEC_FIRST_SGE;

        num_sge = sge - &wqe->recv.pld.sgl[num_sge];

        if (spec && num_sge > spec)
                num_sge = spec;

        return num_sge;
}

static inline int ionic_v1_use_spec_sge(int min_sge, int spec)
{
        if (!spec || min_sge > spec)
                return 0;

        if (min_sge <= IONIC_V1_SPEC_FIRST_SGE)
                return IONIC_V1_SPEC_FIRST_SGE;

        return spec;
}

struct ionic_admin_stats_hdr {
        __le64          dma_addr;
        __le32          length;
        __le32          id_ver;
        __u8            type_state;
} __packed;

#define IONIC_ADMIN_STATS_HDRS_IN_V1_LEN 17
static_assert(sizeof(struct ionic_admin_stats_hdr) ==
               IONIC_ADMIN_STATS_HDRS_IN_V1_LEN);

struct ionic_admin_create_ah {
        __le64          dma_addr;
        __le32          length;
        __le32          pd_id;
        __le32          id_ver;
        __le16          dbid_flags;
        __u8            csum_profile;
        __u8            crypto;
} __packed;

#define IONIC_ADMIN_CREATE_AH_IN_V1_LEN 24
static_assert(sizeof(struct ionic_admin_create_ah) ==
               IONIC_ADMIN_CREATE_AH_IN_V1_LEN);

struct ionic_admin_destroy_ah {
        __le32          ah_id;
} __packed;

#define IONIC_ADMIN_DESTROY_AH_IN_V1_LEN 4
static_assert(sizeof(struct ionic_admin_destroy_ah) ==
               IONIC_ADMIN_DESTROY_AH_IN_V1_LEN);

struct ionic_admin_query_ah {
        __le64          dma_addr;
} __packed;

#define IONIC_ADMIN_QUERY_AH_IN_V1_LEN 8
static_assert(sizeof(struct ionic_admin_query_ah) ==
               IONIC_ADMIN_QUERY_AH_IN_V1_LEN);

struct ionic_admin_create_mr {
        __le64          va;
        __le64          length;
        __le32          pd_id;
        __le32          id_ver;
        __le32          tbl_index;
        __le32          map_count;
        __le64          dma_addr;
        __le16          dbid_flags;
        __u8            pt_type;
        __u8            dir_size_log2;
        __u8            page_size_log2;
} __packed;

#define IONIC_ADMIN_CREATE_MR_IN_V1_LEN 45
static_assert(sizeof(struct ionic_admin_create_mr) ==
               IONIC_ADMIN_CREATE_MR_IN_V1_LEN);

struct ionic_admin_destroy_mr {
        __le32          mr_id;
} __packed;

#define IONIC_ADMIN_DESTROY_MR_IN_V1_LEN 4
static_assert(sizeof(struct ionic_admin_destroy_mr) ==
               IONIC_ADMIN_DESTROY_MR_IN_V1_LEN);

struct ionic_admin_create_cq {
        __le32          eq_id;
        __u8            depth_log2;
        __u8            stride_log2;
        __u8            dir_size_log2_rsvd;
        __u8            page_size_log2;
        __le32          cq_flags;
        __le32          id_ver;
        __le32          tbl_index;
        __le32          map_count;
        __le64          dma_addr;
        __le16          dbid_flags;
} __packed;

#define IONIC_ADMIN_CREATE_CQ_IN_V1_LEN 34
static_assert(sizeof(struct ionic_admin_create_cq) ==
               IONIC_ADMIN_CREATE_CQ_IN_V1_LEN);

struct ionic_admin_destroy_cq {
        __le32          cq_id;
} __packed;

#define IONIC_ADMIN_DESTROY_CQ_IN_V1_LEN 4
static_assert(sizeof(struct ionic_admin_destroy_cq) ==
               IONIC_ADMIN_DESTROY_CQ_IN_V1_LEN);

struct ionic_admin_create_qp {
        __le32          pd_id;
        __be32          priv_flags;
        __le32          sq_cq_id;
        __u8            sq_depth_log2;
        __u8            sq_stride_log2;
        __u8            sq_dir_size_log2_rsvd;
        __u8            sq_page_size_log2;
        __le32          sq_tbl_index_xrcd_id;
        __le32          sq_map_count;
        __le64          sq_dma_addr;
        __le32          rq_cq_id;
        __u8            rq_depth_log2;
        __u8            rq_stride_log2;
        __u8            rq_dir_size_log2_rsvd;
        __u8            rq_page_size_log2;
        __le32          rq_tbl_index_srq_id;
        __le32          rq_map_count;
        __le64          rq_dma_addr;
        __le32          id_ver;
        __le16          dbid_flags;
        __u8            type_state;
        __u8            rsvd;
} __packed;

#define IONIC_ADMIN_CREATE_QP_IN_V1_LEN 64
static_assert(sizeof(struct ionic_admin_create_qp) ==
               IONIC_ADMIN_CREATE_QP_IN_V1_LEN);

struct ionic_admin_destroy_qp {
        __le32          qp_id;
} __packed;

#define IONIC_ADMIN_DESTROY_QP_IN_V1_LEN 4
static_assert(sizeof(struct ionic_admin_destroy_qp) ==
               IONIC_ADMIN_DESTROY_QP_IN_V1_LEN);

struct ionic_admin_mod_qp {
        __be32          attr_mask;
        __u8            dcqcn_profile;
        __u8            tfp_csum_profile;
        __be16          access_flags;
        __le32          rq_psn;
        __le32          sq_psn;
        __le32          qkey_dest_qpn;
        __le32          rate_limit_kbps;
        __u8            pmtu;
        __u8            retry;
        __u8            rnr_timer;
        __u8            retry_timeout;
        __u8            rsq_depth;
        __u8            rrq_depth;
        __le16          pkey_id;
        __le32          ah_id_len;
        __u8            en_pcp;
        __u8            ip_dscp;
        __u8            rsvd2;
        __u8            type_state;
        union {
                struct {
                        __le16          rsvd1;
                };
                __le32          rrq_index;
        };
        __le32          rsq_index;
        __le64          dma_addr;
        __le32          id_ver;
} __packed;

#define IONIC_ADMIN_MODIFY_QP_IN_V1_LEN 60
static_assert(sizeof(struct ionic_admin_mod_qp) ==
               IONIC_ADMIN_MODIFY_QP_IN_V1_LEN);

struct ionic_admin_query_qp {
        __le64          hdr_dma_addr;
        __le64          sq_dma_addr;
        __le64          rq_dma_addr;
        __le32          ah_id;
        __le32          id_ver;
        __le16          dbid_flags;
} __packed;

#define IONIC_ADMIN_QUERY_QP_IN_V1_LEN 34
static_assert(sizeof(struct ionic_admin_query_qp) ==
               IONIC_ADMIN_QUERY_QP_IN_V1_LEN);

#define ADMIN_WQE_STRIDE        64
#define ADMIN_WQE_HDR_LEN       4

/* admin queue v1 wqe */
struct ionic_v1_admin_wqe {
        __u8                            op;
        __u8                            rsvd;
        __le16                          len;

        union {
                struct ionic_admin_stats_hdr stats;
                struct ionic_admin_create_ah create_ah;
                struct ionic_admin_destroy_ah destroy_ah;
                struct ionic_admin_query_ah query_ah;
                struct ionic_admin_create_mr create_mr;
                struct ionic_admin_destroy_mr destroy_mr;
                struct ionic_admin_create_cq create_cq;
                struct ionic_admin_destroy_cq destroy_cq;
                struct ionic_admin_create_qp create_qp;
                struct ionic_admin_destroy_qp destroy_qp;
                struct ionic_admin_mod_qp mod_qp;
                struct ionic_admin_query_qp query_qp;
        } cmd;
};

/* side data for query qp */
struct ionic_v1_admin_query_qp_sq {
        __u8                            rnr_timer;
        __u8                            retry_timeout;
        __be16                          access_perms_flags;
        __be16                          rsvd;
        __be16                          pkey_id;
        __be32                          qkey_dest_qpn;
        __be32                          rate_limit_kbps;
        __be32                          rq_psn;
};

struct ionic_v1_admin_query_qp_rq {
        __u8                            state_pmtu;
        __u8                            retry_rnrtry;
        __u8                            rrq_depth;
        __u8                            rsq_depth;
        __be32                          sq_psn;
        __be16                          access_perms_flags;
        __be16                          rsvd;
};

/* admin queue v1 opcodes */
enum ionic_v1_admin_op {
        IONIC_V1_ADMIN_NOOP,
        IONIC_V1_ADMIN_CREATE_CQ,
        IONIC_V1_ADMIN_CREATE_QP,
        IONIC_V1_ADMIN_CREATE_MR,
        IONIC_V1_ADMIN_STATS_HDRS,
        IONIC_V1_ADMIN_STATS_VALS,
        IONIC_V1_ADMIN_DESTROY_MR,
        IONIC_V1_ADMIN_RSVD_7,          /* RESIZE_CQ */
        IONIC_V1_ADMIN_DESTROY_CQ,
        IONIC_V1_ADMIN_MODIFY_QP,
        IONIC_V1_ADMIN_QUERY_QP,
        IONIC_V1_ADMIN_DESTROY_QP,
        IONIC_V1_ADMIN_DEBUG,
        IONIC_V1_ADMIN_CREATE_AH,
        IONIC_V1_ADMIN_QUERY_AH,
        IONIC_V1_ADMIN_MODIFY_DCQCN,
        IONIC_V1_ADMIN_DESTROY_AH,
        IONIC_V1_ADMIN_QP_STATS_HDRS,
        IONIC_V1_ADMIN_QP_STATS_VALS,
        IONIC_V1_ADMIN_OPCODES_MAX,
};

/* admin queue v1 cqe status */
enum ionic_v1_admin_status {
        IONIC_V1_ASTS_OK,
        IONIC_V1_ASTS_BAD_CMD,
        IONIC_V1_ASTS_BAD_INDEX,
        IONIC_V1_ASTS_BAD_STATE,
        IONIC_V1_ASTS_BAD_TYPE,
        IONIC_V1_ASTS_BAD_ATTR,
        IONIC_V1_ASTS_MSG_TOO_BIG,
};

/* event queue v1 eqe */
struct ionic_v1_eqe {
        __be32                          evt;
};

/* bits for cqe queue_type_flags */
enum ionic_v1_eqe_evt_bits {
        IONIC_V1_EQE_COLOR              = BIT(0),
        IONIC_V1_EQE_TYPE_SHIFT         = 1,
        IONIC_V1_EQE_TYPE_MASK          = 0x7,
        IONIC_V1_EQE_CODE_SHIFT         = 4,
        IONIC_V1_EQE_CODE_MASK          = 0xf,
        IONIC_V1_EQE_QID_SHIFT          = 8,

        /* cq events */
        IONIC_V1_EQE_TYPE_CQ            = 0,
        /* cq normal events */
        IONIC_V1_EQE_CQ_NOTIFY          = 0,
        /* cq error events */
        IONIC_V1_EQE_CQ_ERR             = 8,

        /* qp and srq events */
        IONIC_V1_EQE_TYPE_QP            = 1,
        /* qp normal events */
        IONIC_V1_EQE_SRQ_LEVEL          = 0,
        IONIC_V1_EQE_SQ_DRAIN           = 1,
        IONIC_V1_EQE_QP_COMM_EST        = 2,
        IONIC_V1_EQE_QP_LAST_WQE        = 3,
        /* qp error events */
        IONIC_V1_EQE_QP_ERR             = 8,
        IONIC_V1_EQE_QP_ERR_REQUEST     = 9,
        IONIC_V1_EQE_QP_ERR_ACCESS      = 10,
};

enum ionic_tfp_csum_profiles {
        IONIC_TFP_CSUM_PROF_ETH_IPV4_UDP                                = 0,
        IONIC_TFP_CSUM_PROF_ETH_QTAG_IPV4_UDP                           = 1,
        IONIC_TFP_CSUM_PROF_ETH_IPV6_UDP                                = 2,
        IONIC_TFP_CSUM_PROF_ETH_QTAG_IPV6_UDP                           = 3,
        IONIC_TFP_CSUM_PROF_IPV4_UDP_VXLAN_ETH_QTAG_IPV4_UDP            = 4,
        IONIC_TFP_CSUM_PROF_IPV4_UDP_VXLAN_ETH_QTAG_IPV6_UDP            = 5,
        IONIC_TFP_CSUM_PROF_QTAG_IPV4_UDP_VXLAN_ETH_QTAG_IPV4_UDP       = 6,
        IONIC_TFP_CSUM_PROF_QTAG_IPV4_UDP_VXLAN_ETH_QTAG_IPV6_UDP       = 7,
        IONIC_TFP_CSUM_PROF_ETH_QTAG_IPV4_UDP_ESP_IPV4_UDP              = 8,
        IONIC_TFP_CSUM_PROF_ETH_QTAG_IPV4_ESP_UDP                       = 9,
        IONIC_TFP_CSUM_PROF_ETH_QTAG_IPV4_UDP_ESP_UDP                   = 10,
        IONIC_TFP_CSUM_PROF_ETH_QTAG_IPV6_ESP_UDP                       = 11,
        IONIC_TFP_CSUM_PROF_ETH_QTAG_IPV4_UDP_CSUM                      = 12,
};

static inline bool ionic_v1_eqe_color(struct ionic_v1_eqe *eqe)
{
        return eqe->evt & cpu_to_be32(IONIC_V1_EQE_COLOR);
}

static inline u32 ionic_v1_eqe_evt(struct ionic_v1_eqe *eqe)
{
        return be32_to_cpu(eqe->evt);
}

static inline u8 ionic_v1_eqe_evt_type(u32 evt)
{
        return (evt >> IONIC_V1_EQE_TYPE_SHIFT) & IONIC_V1_EQE_TYPE_MASK;
}

static inline u8 ionic_v1_eqe_evt_code(u32 evt)
{
        return (evt >> IONIC_V1_EQE_CODE_SHIFT) & IONIC_V1_EQE_CODE_MASK;
}

static inline u32 ionic_v1_eqe_evt_qid(u32 evt)
{
        return evt >> IONIC_V1_EQE_QID_SHIFT;
}

enum ionic_v1_stat_bits {
        IONIC_V1_STAT_TYPE_SHIFT        = 28,
        IONIC_V1_STAT_TYPE_NONE         = 0,
        IONIC_V1_STAT_TYPE_8            = 1,
        IONIC_V1_STAT_TYPE_LE16         = 2,
        IONIC_V1_STAT_TYPE_LE32         = 3,
        IONIC_V1_STAT_TYPE_LE64         = 4,
        IONIC_V1_STAT_TYPE_BE16         = 5,
        IONIC_V1_STAT_TYPE_BE32         = 6,
        IONIC_V1_STAT_TYPE_BE64         = 7,
        IONIC_V1_STAT_OFF_MASK          = BIT(IONIC_V1_STAT_TYPE_SHIFT) - 1,
};

struct ionic_v1_stat {
        union {
                __be32          be_type_off;
                u32             type_off;
        };
        char                    name[28];
};

static inline int ionic_v1_stat_type(struct ionic_v1_stat *hdr)
{
        return hdr->type_off >> IONIC_V1_STAT_TYPE_SHIFT;
}

static inline unsigned int ionic_v1_stat_off(struct ionic_v1_stat *hdr)
{
        return hdr->type_off & IONIC_V1_STAT_OFF_MASK;
}

#endif /* _IONIC_FW_H_ */