| /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ | |
| /* | |
| * Copyright (c) 2018-2025 Advanced Micro Devices, Inc. All rights reserved. | |
| */ | |
| #ifndef IONIC_FW_H | |
| #define IONIC_FW_H | |
| #include "ionic_fw_types.h" | |
| static inline int to_ionic_mr_flags(int access) | |
| { | |
| int flags = 0; | |
| if (access & IBV_ACCESS_LOCAL_WRITE) | |
| flags |= IONIC_MRF_LOCAL_WRITE; | |
| if (access & IBV_ACCESS_REMOTE_READ) | |
| flags |= IONIC_MRF_REMOTE_READ; | |
| if (access & IBV_ACCESS_REMOTE_WRITE) | |
| flags |= IONIC_MRF_REMOTE_WRITE; | |
| if (access & IBV_ACCESS_REMOTE_ATOMIC) | |
| flags |= IONIC_MRF_REMOTE_ATOMIC; | |
| if (access & IBV_ACCESS_MW_BIND) | |
| flags |= IONIC_MRF_MW_BIND; | |
| if (access & IBV_ACCESS_ZERO_BASED) | |
| flags |= IONIC_MRF_ZERO_BASED; | |
| return flags; | |
| } | |
| static inline int ionic_to_ibv_status(int sts) | |
| { | |
| switch (sts) { | |
| case IONIC_STS_OK: | |
| return IBV_WC_SUCCESS; | |
| case IONIC_STS_LOCAL_LEN_ERR: | |
| return IBV_WC_LOC_LEN_ERR; | |
| case IONIC_STS_LOCAL_QP_OPER_ERR: | |
| return IBV_WC_LOC_QP_OP_ERR; | |
| case IONIC_STS_LOCAL_PROT_ERR: | |
| return IBV_WC_LOC_PROT_ERR; | |
| case IONIC_STS_WQE_FLUSHED_ERR: | |
| return IBV_WC_WR_FLUSH_ERR; | |
| case IONIC_STS_MEM_MGMT_OPER_ERR: | |
| return IBV_WC_MW_BIND_ERR; | |
| case IONIC_STS_BAD_RESP_ERR: | |
| return IBV_WC_BAD_RESP_ERR; | |
| case IONIC_STS_LOCAL_ACC_ERR: | |
| return IBV_WC_LOC_ACCESS_ERR; | |
| case IONIC_STS_REMOTE_INV_REQ_ERR: | |
| return IBV_WC_REM_INV_REQ_ERR; | |
| case IONIC_STS_REMOTE_ACC_ERR: | |
| return IBV_WC_REM_ACCESS_ERR; | |
| case IONIC_STS_REMOTE_OPER_ERR: | |
| return IBV_WC_REM_OP_ERR; | |
| case IONIC_STS_RETRY_EXCEEDED: | |
| return IBV_WC_RETRY_EXC_ERR; | |
| case IONIC_STS_RNR_RETRY_EXCEEDED: | |
| return IBV_WC_RNR_RETRY_EXC_ERR; | |
| case IONIC_STS_XRC_VIO_ERR: | |
| default: | |
| return IBV_WC_GENERAL_ERR; | |
| } | |
| } | |
| static inline bool ionic_v1_cqe_color(struct ionic_v1_cqe *cqe) | |
| { | |
| return !!(cqe->qid_type_flags & htobe32(IONIC_V1_CQE_COLOR)); | |
| } | |
| static inline bool ionic_v1_cqe_error(struct ionic_v1_cqe *cqe) | |
| { | |
| return !!(cqe->qid_type_flags & htobe32(IONIC_V1_CQE_ERROR)); | |
| } | |
| static inline bool ionic_v1_cqe_recv_is_ipv4(struct ionic_v1_cqe *cqe) | |
| { | |
| return !!(cqe->recv.src_qpn_op & | |
| htobe32(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 & | |
| htobe32(IONIC_V1_CQE_RECV_IS_VLAN)); | |
| } | |
| static inline void ionic_v1_cqe_clean(struct ionic_v1_cqe *cqe) | |
| { | |
| cqe->qid_type_flags |= htobe32(~0u << IONIC_V1_CQE_QID_SHIFT); | |
| } | |
| static inline uint32_t ionic_v1_cqe_qtf(struct ionic_v1_cqe *cqe) | |
| { | |
| return be32toh(cqe->qid_type_flags); | |
| } | |
| static inline uint8_t ionic_v1_cqe_qtf_type(uint32_t qtf) | |
| { | |
| return (qtf >> IONIC_V1_CQE_TYPE_SHIFT) & IONIC_V1_CQE_TYPE_MASK; | |
| } | |
| static inline uint32_t ionic_v1_cqe_qtf_qid(uint32_t qtf) | |
| { | |
| return qtf >> IONIC_V1_CQE_QID_SHIFT; | |
| } | |
| 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 roundup_pow_of_two(sz_wqe); | |
| } | |
| static inline int ionic_v1_send_wqe_max_sge(uint8_t stride_log2, int spec, bool expdb) | |
| { | |
| struct ionic_v1_wqe *wqe = (void *)0; | |
| struct ionic_sge *sge = (void *)(uintptr_t)(1ull << stride_log2); | |
| 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(uint8_t stride_log2, bool expdb) | |
| { | |
| struct ionic_v1_wqe *wqe = (void *)0; | |
| __u8 *data = (void *)(uintptr_t)(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(uint8_t stride_log2, int spec, bool expdb) | |
| { | |
| struct ionic_v1_wqe *wqe = (void *)0; | |
| struct ionic_sge *sge = (void *)(uintptr_t)(1ull << stride_log2); | |
| 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; | |
| } | |
| #endif /* IONIC_FW_H */ |