From: Yonatan Nachum Date: Thu, 9 Apr 2026 07:49:05 +0000 (+0000) Subject: RDMA/efa: Add checksum support for admin responses X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7de165740ce8d006cbe80bca9d8207ba05a4cfc5;p=thirdparty%2Fkernel%2Flinux.git RDMA/efa: Add checksum support for admin responses EFA devices added support for CRC16 checksum on admin responses and to expose it to the driver the API version increased to 0.2. Add a check for support on device init and if supported validate the checksum on each admin response the driver receives. If the checksum validation failed, drop the CQE. Add the CRC16 module to Kconfig to have the in-tree dependency. Reviewed-by: Firas Jahjah Reviewed-by: Michael Margolin Signed-off-by: Yonatan Nachum Link: https://patch.msgid.link/20260409074905.3126023-1-ynachum@amazon.com Signed-off-by: Leon Romanovsky --- diff --git a/drivers/infiniband/hw/efa/Kconfig b/drivers/infiniband/hw/efa/Kconfig index 457e18ba1d570..ff7f7c0870b3a 100644 --- a/drivers/infiniband/hw/efa/Kconfig +++ b/drivers/infiniband/hw/efa/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause -# Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All rights reserved. +# Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved. # # Amazon fabric device configuration # @@ -8,6 +8,7 @@ config INFINIBAND_EFA tristate "Amazon Elastic Fabric Adapter (EFA) support" depends on PCI_MSI && 64BIT && !CPU_BIG_ENDIAN depends on INFINIBAND_USER_ACCESS + select CRC16 help This driver supports Amazon Elastic Fabric Adapter (EFA). diff --git a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h index ad34ea5da6b07..826790ca9d839 100644 --- a/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h +++ b/drivers/infiniband/hw/efa/efa_admin_cmds_defs.h @@ -6,9 +6,6 @@ #ifndef _EFA_ADMIN_CMDS_H_ #define _EFA_ADMIN_CMDS_H_ -#define EFA_ADMIN_API_VERSION_MAJOR 0 -#define EFA_ADMIN_API_VERSION_MINOR 1 - /* EFA admin queue opcodes */ enum efa_admin_aq_opcode { EFA_ADMIN_CREATE_QP = 1, diff --git a/drivers/infiniband/hw/efa/efa_admin_defs.h b/drivers/infiniband/hw/efa/efa_admin_defs.h index 35700c93e639e..02f86edabed86 100644 --- a/drivers/infiniband/hw/efa/efa_admin_defs.h +++ b/drivers/infiniband/hw/efa/efa_admin_defs.h @@ -1,18 +1,20 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* - * Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef _EFA_ADMIN_H_ #define _EFA_ADMIN_H_ +#define EFA_ADMIN_API_VERSION_MAJOR 0 +#define EFA_ADMIN_API_VERSION_MINOR 2 + enum efa_admin_aq_completion_status { EFA_ADMIN_SUCCESS = 0, EFA_ADMIN_RESOURCE_ALLOCATION_FAILURE = 1, EFA_ADMIN_BAD_OPCODE = 2, EFA_ADMIN_UNSUPPORTED_OPCODE = 3, EFA_ADMIN_MALFORMED_REQUEST = 4, - /* Additional status is provided in ACQ entry extended_status */ EFA_ADMIN_ILLEGAL_PARAMETER = 5, EFA_ADMIN_UNKNOWN_ERROR = 6, EFA_ADMIN_RESOURCE_BUSY = 7, @@ -78,13 +80,10 @@ struct efa_admin_acq_common_desc { */ u8 flags; - u16 extended_status; + /* Poly 0x8005 CRC16 with initial value 0xFFFF and final XOR of 0xFFFF */ + u16 checksum; - /* - * indicates to the driver which AQ entry has been consumed by the - * device and could be reused - */ - u16 sq_head_indx; + u16 reserved; }; struct efa_admin_acq_entry { diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c index e97b5f0d70038..7cc3f4af0bb9d 100644 --- a/drivers/infiniband/hw/efa/efa_com.c +++ b/drivers/infiniband/hw/efa/efa_com.c @@ -3,6 +3,7 @@ * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved. */ +#include #include #include "efa_com.h" @@ -22,6 +23,14 @@ #define EFA_CTRL_MINOR 0 #define EFA_CTRL_SUB_MINOR 1 +#define EFA_CRC16_INIT_VAL 0xffff + +#define EFA_CRC_MIN_ADMIN_API_VERSION_MAJOR 0 +#define EFA_CRC_MIN_ADMIN_API_VERSION_MINOR 2 + +#define EFA_MIN_ADMIN_API_VERSION_MAJOR 0 +#define EFA_MIN_ADMIN_API_VERSION_MINOR 1 + enum efa_cmd_status { EFA_CMD_UNUSED, EFA_CMD_ALLOCATED, @@ -167,9 +176,8 @@ static int efa_com_admin_init_cq(struct efa_com_dev *edev) struct efa_com_admin_queue *aq = &edev->aq; struct efa_com_admin_cq *cq = &aq->cq; u16 size = aq->depth * sizeof(*cq->entries); - u32 acq_caps = 0; - u32 addr_high; - u32 addr_low; + u32 acq_caps = 0, crc_min_ver = 0; + u32 addr_high, addr_low; cq->entries = dma_alloc_coherent(aq->dmadev, size, &cq->dma_addr, GFP_KERNEL); @@ -178,6 +186,11 @@ static int efa_com_admin_init_cq(struct efa_com_dev *edev) spin_lock_init(&cq->lock); + EFA_SET(&crc_min_ver, EFA_REGS_VERSION_MAJOR_VERSION, EFA_CRC_MIN_ADMIN_API_VERSION_MAJOR); + EFA_SET(&crc_min_ver, EFA_REGS_VERSION_MINOR_VERSION, EFA_CRC_MIN_ADMIN_API_VERSION_MINOR); + if (edev->dev_api_ver >= crc_min_ver) + cq->validate_checksum = true; + cq->cc = 0; cq->phase = 1; @@ -409,12 +422,35 @@ static int efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq, return 0; } +static bool efa_com_cqe_checksum_valid(struct efa_com_admin_queue *aq, + struct efa_admin_acq_entry *cqe) +{ + u16 cqe_checksum = cqe->acq_common_descriptor.checksum; + u16 calc_checksum; + + cqe->acq_common_descriptor.checksum = 0; + + calc_checksum = crc16(EFA_CRC16_INIT_VAL, (u8 *)cqe, sizeof(*cqe)) ^ EFA_CRC16_INIT_VAL; + if (calc_checksum != cqe_checksum) { + ibdev_err(aq->efa_dev, + "Received completion with invalid checksum, cqe[%u], calc[%u], sq producer[%d], sq consumer[%d], cq consumer[%d]\n", + cqe_checksum, calc_checksum, aq->sq.pc, aq->sq.cc, + aq->cq.cc); + return false; + } + + return true; +} + static int efa_com_handle_single_admin_completion(struct efa_com_admin_queue *aq, struct efa_admin_acq_entry *cqe) { struct efa_comp_ctx *comp_ctx; u16 cmd_id; + if (aq->cq.validate_checksum && !efa_com_cqe_checksum_valid(aq, cqe)) + return -EINVAL; + cmd_id = EFA_GET(&cqe->acq_common_descriptor.command, EFA_ADMIN_ACQ_COMMON_DESC_COMMAND_ID); @@ -954,16 +990,16 @@ int efa_com_validate_version(struct efa_com_dev *edev) EFA_GET(&ver, EFA_REGS_VERSION_MAJOR_VERSION), EFA_GET(&ver, EFA_REGS_VERSION_MINOR_VERSION)); - EFA_SET(&min_ver, EFA_REGS_VERSION_MAJOR_VERSION, - EFA_ADMIN_API_VERSION_MAJOR); - EFA_SET(&min_ver, EFA_REGS_VERSION_MINOR_VERSION, - EFA_ADMIN_API_VERSION_MINOR); + EFA_SET(&min_ver, EFA_REGS_VERSION_MAJOR_VERSION, EFA_MIN_ADMIN_API_VERSION_MAJOR); + EFA_SET(&min_ver, EFA_REGS_VERSION_MINOR_VERSION, EFA_MIN_ADMIN_API_VERSION_MINOR); if (ver < min_ver) { ibdev_err(edev->efa_dev, "EFA version is lower than the minimal version the driver supports\n"); return -EOPNOTSUPP; } + edev->dev_api_ver = ver; + ibdev_dbg( edev->efa_dev, "efa controller version: %d.%d.%d implementation version %d\n", diff --git a/drivers/infiniband/hw/efa/efa_com.h b/drivers/infiniband/hw/efa/efa_com.h index 4d9ca97e42962..f8c692b0e092e 100644 --- a/drivers/infiniband/hw/efa/efa_com.h +++ b/drivers/infiniband/hw/efa/efa_com.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* - * Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef _EFA_COM_H_ @@ -25,6 +25,7 @@ struct efa_com_admin_cq { struct efa_admin_acq_entry *entries; dma_addr_t dma_addr; spinlock_t lock; /* Protects ACQ */ + bool validate_checksum; u16 cc; /* consumer counter */ u8 phase; @@ -112,6 +113,7 @@ struct efa_com_dev { u32 supported_features; u32 dma_addr_bits; + u32 dev_api_ver; struct efa_com_mmio_read mmio_read; };