summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/userspace-api/fwctl/bnxt_fwctl.rst74
-rw-r--r--Documentation/userspace-api/fwctl/fwctl.rst1
-rw-r--r--Documentation/userspace-api/fwctl/index.rst1
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/fwctl/Kconfig11
-rw-r--r--drivers/fwctl/Makefile1
-rw-r--r--drivers/fwctl/bnxt/Makefile4
-rw-r--r--drivers/fwctl/bnxt/main.c281
-rw-r--r--drivers/fwctl/main.c2
-rw-r--r--drivers/infiniband/hw/bnxt_re/debugfs.c2
-rw-r--r--drivers/infiniband/hw/bnxt_re/main.c2
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_fp.c2
-rw-r--r--drivers/infiniband/hw/bnxt_re/qplib_res.h2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c49
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h19
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c10
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c2
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c349
-rw-r--r--include/linux/bnxt/ulp.h (renamed from drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h)26
-rw-r--r--include/uapi/fwctl/bnxt.h26
-rw-r--r--include/uapi/fwctl/fwctl.h1
22 files changed, 698 insertions, 177 deletions
diff --git a/Documentation/userspace-api/fwctl/bnxt_fwctl.rst b/Documentation/userspace-api/fwctl/bnxt_fwctl.rst
new file mode 100644
index 000000000000..97c9b095cf21
--- /dev/null
+++ b/Documentation/userspace-api/fwctl/bnxt_fwctl.rst
@@ -0,0 +1,74 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=================
+fwctl bnxt driver
+=================
+
+:Author: Pavan Chebbi
+
+Overview
+========
+
+BNXT driver makes a fwctl service available through an auxiliary_device.
+The bnxt_fwctl driver binds to this device and registers itself with the
+fwctl subsystem.
+
+The bnxt_fwctl driver is agnostic to the device firmware internals. It
+uses the Upper Layer Protocol (ULP) conduit provided by bnxt to send
+HardWare Resource Manager (HWRM) commands to firmware.
+
+These commands can query or change firmware driven device configurations
+and read/write registers that are useful for debugging.
+
+bnxt_fwctl User API
+===================
+
+Each RPC request contains the HWRM input structure in the fwctl_rpc
+'in' buffer while 'out' will contain the response.
+
+A typical user application can send a FWCTL_INFO command using ioctl()
+to discover bnxt_fwctl's RPC capabilities as shown below:
+
+ ioctl(fd, FWCTL_INFO, &fwctl_info_msg);
+
+where fwctl_info_msg (of type struct fwctl_info) describes bnxt_info_msg
+(of type struct fwctl_info_bnxt). fwctl_info_msg is set up as follows:
+
+ size = sizeof(struct fwctl_info);
+ flags = 0;
+ device_data_len = sizeof(bnxt_info_msg);
+ out_device_data = (__aligned_u64)&bnxt_info_msg;
+
+The uctx_caps of bnxt_info_msg represents the capabilities as described
+in fwctl_bnxt_commands of include/uapi/fwctl/bnxt.h
+
+The FW RPC itself, FWCTL_RPC can be sent using ioctl() as:
+
+ ioctl(fd, FWCTL_RPC, &fwctl_rpc_msg);
+
+where fwctl_rpc_msg (of type struct fwctl_rpc) carries the HWRM command
+in its 'in' buffer. The HWRM input structures are described in
+include/linux/bnxt/hsi.h. An example for HWRM_VER_GET is shown below:
+
+ struct hwrm_ver_get_output resp;
+ struct fwctl_rpc fwctl_rpc_msg;
+ struct hwrm_ver_get_input req;
+
+ req.req_type = HWRM_VER_GET;
+ req.hwrm_intf_maj = HWRM_VERSION_MAJOR;
+ req.hwrm_intf_min = HWRM_VERSION_MINOR;
+ req.hwrm_intf_upd = HWRM_VERSION_UPDATE;
+ req.cmpl_ring = -1;
+ req.target_id = -1;
+
+ fwctl_rpc_msg.size = sizeof(struct fwctl_rpc);
+ fwctl_rpc_msg.scope = FWCTL_RPC_DEBUG_READ_ONLY;
+ fwctl_rpc_msg.in_len = sizeof(req);
+ fwctl_rpc_msg.out_len = sizeof(resp);
+ fwctl_rpc_msg.in = (__aligned_u64)&req;
+ fwctl_rpc_msg.out = (__aligned_u64)&resp;
+
+An example python3 program that can exercise this interface can be found in
+the following git repository:
+
+https://github.com/Broadcom/fwctl-tools
diff --git a/Documentation/userspace-api/fwctl/fwctl.rst b/Documentation/userspace-api/fwctl/fwctl.rst
index a74eab8d14c6..826817bfd54d 100644
--- a/Documentation/userspace-api/fwctl/fwctl.rst
+++ b/Documentation/userspace-api/fwctl/fwctl.rst
@@ -148,6 +148,7 @@ area resulting in clashes will be resolved in favour of a kernel implementation.
fwctl User API
==============
+.. kernel-doc:: include/uapi/fwctl/bnxt.h
.. kernel-doc:: include/uapi/fwctl/fwctl.h
.. kernel-doc:: include/uapi/fwctl/mlx5.h
.. kernel-doc:: include/uapi/fwctl/pds.h
diff --git a/Documentation/userspace-api/fwctl/index.rst b/Documentation/userspace-api/fwctl/index.rst
index 316ac456ad3b..8062f7629654 100644
--- a/Documentation/userspace-api/fwctl/index.rst
+++ b/Documentation/userspace-api/fwctl/index.rst
@@ -10,5 +10,6 @@ to securely construct and execute RPCs inside device firmware.
:maxdepth: 1
fwctl
+ bnxt_fwctl
fwctl-cxl
pds_fwctl
diff --git a/MAINTAINERS b/MAINTAINERS
index d41dc26280b1..288866c32ade 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10604,6 +10604,12 @@ F: drivers/fwctl/
F: include/linux/fwctl.h
F: include/uapi/fwctl/
+FWCTL BNXT DRIVER
+M: Pavan Chebbi <pavan.chebbi@broadcom.com>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: drivers/fwctl/bnxt/
+
FWCTL MLX5 DRIVER
M: Saeed Mahameed <saeedm@nvidia.com>
R: Itay Avraham <itayavr@nvidia.com>
diff --git a/drivers/fwctl/Kconfig b/drivers/fwctl/Kconfig
index b5583b12a011..d1b1925bdaec 100644
--- a/drivers/fwctl/Kconfig
+++ b/drivers/fwctl/Kconfig
@@ -9,6 +9,17 @@ menuconfig FWCTL
fit neatly into an existing subsystem.
if FWCTL
+config FWCTL_BNXT
+ tristate "bnxt control fwctl driver"
+ depends on BNXT
+ help
+ BNXT provides interface for the user process to access the debug and
+ configuration registers of the Broadcom NIC hardware family.
+ This will allow configuration and debug tools to work out of the box on
+ mainstream kernel.
+
+ If you don't know what to do here, say N.
+
config FWCTL_MLX5
tristate "mlx5 ConnectX control fwctl driver"
depends on MLX5_CORE
diff --git a/drivers/fwctl/Makefile b/drivers/fwctl/Makefile
index c093b5f661d6..692e4b8d7beb 100644
--- a/drivers/fwctl/Makefile
+++ b/drivers/fwctl/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_FWCTL) += fwctl.o
+obj-$(CONFIG_FWCTL_BNXT) += bnxt/
obj-$(CONFIG_FWCTL_MLX5) += mlx5/
obj-$(CONFIG_FWCTL_PDS) += pds/
diff --git a/drivers/fwctl/bnxt/Makefile b/drivers/fwctl/bnxt/Makefile
new file mode 100644
index 000000000000..b47172761f1e
--- /dev/null
+++ b/drivers/fwctl/bnxt/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_FWCTL_BNXT) += bnxt_fwctl.o
+
+bnxt_fwctl-y += main.o
diff --git a/drivers/fwctl/bnxt/main.c b/drivers/fwctl/bnxt/main.c
new file mode 100644
index 000000000000..951c8ac2e0a1
--- /dev/null
+++ b/drivers/fwctl/bnxt/main.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026, Broadcom Corporation
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/fwctl.h>
+#include <linux/bnxt/hsi.h>
+#include <linux/bnxt/ulp.h>
+#include <uapi/fwctl/fwctl.h>
+#include <uapi/fwctl/bnxt.h>
+
+struct bnxtctl_uctx {
+ struct fwctl_uctx uctx;
+ u32 uctx_caps;
+};
+
+struct bnxtctl_dev {
+ struct fwctl_device fwctl;
+ struct bnxt_aux_priv *aux_priv;
+};
+
+DEFINE_FREE(bnxtctl, struct bnxtctl_dev *, if (_T) fwctl_put(&_T->fwctl))
+
+static int bnxtctl_open_uctx(struct fwctl_uctx *uctx)
+{
+ struct bnxtctl_uctx *bnxtctl_uctx =
+ container_of(uctx, struct bnxtctl_uctx, uctx);
+
+ bnxtctl_uctx->uctx_caps = BIT(FWCTL_BNXT_INLINE_COMMANDS) |
+ BIT(FWCTL_BNXT_QUERY_COMMANDS) |
+ BIT(FWCTL_BNXT_SEND_COMMANDS);
+ return 0;
+}
+
+static void bnxtctl_close_uctx(struct fwctl_uctx *uctx)
+{
+}
+
+static void *bnxtctl_info(struct fwctl_uctx *uctx, size_t *length)
+{
+ struct bnxtctl_uctx *bnxtctl_uctx =
+ container_of(uctx, struct bnxtctl_uctx, uctx);
+ struct fwctl_info_bnxt *info;
+
+ info = kzalloc_obj(*info);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->uctx_caps = bnxtctl_uctx->uctx_caps;
+
+ *length = sizeof(*info);
+ return info;
+}
+
+/* Caller must hold edev->en_dev_lock */
+static bool bnxtctl_validate_rpc(struct bnxt_en_dev *edev,
+ struct bnxt_fw_msg *hwrm_in,
+ enum fwctl_rpc_scope scope)
+{
+ struct input *req = (struct input *)hwrm_in->msg;
+
+ lockdep_assert_held(&edev->en_dev_lock);
+ if (edev->flags & BNXT_EN_FLAG_ULP_STOPPED)
+ return false;
+
+ switch (le16_to_cpu(req->req_type)) {
+ case HWRM_FUNC_RESET:
+ case HWRM_PORT_CLR_STATS:
+ case HWRM_FW_RESET:
+ case HWRM_FW_SYNC:
+ case HWRM_FW_SET_TIME:
+ case HWRM_DBG_LOG_BUFFER_FLUSH:
+ case HWRM_DBG_ERASE_NVM:
+ case HWRM_DBG_CFG:
+ case HWRM_NVM_DEFRAG:
+ case HWRM_NVM_FACTORY_DEFAULTS:
+ case HWRM_NVM_FLUSH:
+ case HWRM_NVM_VERIFY_UPDATE:
+ case HWRM_NVM_ERASE_DIR_ENTRY:
+ case HWRM_NVM_MOD_DIR_ENTRY:
+ case HWRM_NVM_FIND_DIR_ENTRY:
+ return scope >= FWCTL_RPC_CONFIGURATION;
+
+ case HWRM_VER_GET:
+ case HWRM_ERROR_RECOVERY_QCFG:
+ case HWRM_FUNC_QCAPS:
+ case HWRM_FUNC_QCFG:
+ case HWRM_FUNC_QSTATS:
+ case HWRM_PORT_PHY_QCFG:
+ case HWRM_PORT_MAC_QCFG:
+ case HWRM_PORT_PHY_QCAPS:
+ case HWRM_PORT_PHY_I2C_READ:
+ case HWRM_PORT_PHY_MDIO_READ:
+ case HWRM_QUEUE_PRI2COS_QCFG:
+ case HWRM_QUEUE_COS2BW_QCFG:
+ case HWRM_VNIC_RSS_QCFG:
+ case HWRM_QUEUE_GLOBAL_QCFG:
+ case HWRM_QUEUE_ADPTV_QOS_RX_FEATURE_QCFG:
+ case HWRM_QUEUE_ADPTV_QOS_TX_FEATURE_QCFG:
+ case HWRM_QUEUE_QCAPS:
+ case HWRM_QUEUE_ADPTV_QOS_RX_TUNING_QCFG:
+ case HWRM_QUEUE_ADPTV_QOS_TX_TUNING_QCFG:
+ case HWRM_TUNNEL_DST_PORT_QUERY:
+ case HWRM_PORT_TX_FIR_QCFG:
+ case HWRM_FW_LIVEPATCH_QUERY:
+ case HWRM_FW_QSTATUS:
+ case HWRM_FW_HEALTH_CHECK:
+ case HWRM_FW_GET_TIME:
+ case HWRM_PORT_EP_TX_QCFG:
+ case HWRM_PORT_QCFG:
+ case HWRM_PORT_MAC_QCAPS:
+ case HWRM_TEMP_MONITOR_QUERY:
+ case HWRM_REG_POWER_QUERY:
+ case HWRM_CORE_FREQUENCY_QUERY:
+ case HWRM_CFA_REDIRECT_QUERY_TUNNEL_TYPE:
+ case HWRM_CFA_ADV_FLOW_MGNT_QCAPS:
+ case HWRM_FUNC_RESOURCE_QCAPS:
+ case HWRM_FUNC_BACKING_STORE_QCAPS:
+ case HWRM_FUNC_BACKING_STORE_QCFG:
+ case HWRM_FUNC_QSTATS_EXT:
+ case HWRM_FUNC_PTP_PIN_QCFG:
+ case HWRM_FUNC_PTP_EXT_QCFG:
+ case HWRM_FUNC_BACKING_STORE_QCFG_V2:
+ case HWRM_FUNC_BACKING_STORE_QCAPS_V2:
+ case HWRM_FUNC_SYNCE_QCFG:
+ case HWRM_FUNC_TTX_PACING_RATE_PROF_QUERY:
+ case HWRM_PORT_PHY_FDRSTAT:
+ case HWRM_DBG_RING_INFO_GET:
+ case HWRM_DBG_QCAPS:
+ case HWRM_DBG_QCFG:
+ case HWRM_DBG_USEQ_FLUSH:
+ case HWRM_DBG_USEQ_QCAPS:
+ case HWRM_DBG_SIM_CABLE_STATE:
+ case HWRM_DBG_TOKEN_QUERY_AUTH_IDS:
+ case HWRM_NVM_GET_DEV_INFO:
+ case HWRM_NVM_GET_DIR_INFO:
+ case HWRM_SELFTEST_QLIST:
+ return scope >= FWCTL_RPC_DEBUG_READ_ONLY;
+
+ case HWRM_PORT_PHY_I2C_WRITE:
+ case HWRM_PORT_PHY_MDIO_WRITE:
+ return scope >= FWCTL_RPC_DEBUG_WRITE;
+
+ default:
+ return false;
+ }
+}
+
+#define BNXTCTL_HWRM_CMD_TIMEOUT_DFLT 500 /* ms */
+#define BNXTCTL_HWRM_CMD_TIMEOUT_MEDM 2000 /* ms */
+#define BNXTCTL_HWRM_CMD_TIMEOUT_LONG 60000 /* ms */
+
+static unsigned int bnxtctl_get_timeout(struct input *req)
+{
+ switch (le16_to_cpu(req->req_type)) {
+ case HWRM_NVM_DEFRAG:
+ case HWRM_NVM_FACTORY_DEFAULTS:
+ case HWRM_NVM_FLUSH:
+ case HWRM_NVM_VERIFY_UPDATE:
+ case HWRM_NVM_ERASE_DIR_ENTRY:
+ case HWRM_NVM_MOD_DIR_ENTRY:
+ return BNXTCTL_HWRM_CMD_TIMEOUT_LONG;
+ case HWRM_FUNC_RESET:
+ return BNXTCTL_HWRM_CMD_TIMEOUT_MEDM;
+ default:
+ return BNXTCTL_HWRM_CMD_TIMEOUT_DFLT;
+ }
+}
+
+static void *bnxtctl_fw_rpc(struct fwctl_uctx *uctx,
+ enum fwctl_rpc_scope scope,
+ void *in, size_t in_len, size_t *out_len)
+{
+ struct bnxtctl_dev *bnxtctl =
+ container_of(uctx->fwctl, struct bnxtctl_dev, fwctl);
+ struct bnxt_en_dev *edev = bnxtctl->aux_priv->edev;
+ struct bnxt_fw_msg rpc_in = {0};
+ int rc;
+
+ if (in_len < sizeof(struct input) || in_len > HWRM_MAX_REQ_LEN)
+ return ERR_PTR(-EINVAL);
+
+ if (*out_len < sizeof(struct output))
+ return ERR_PTR(-EINVAL);
+
+ rpc_in.msg = in;
+ rpc_in.msg_len = in_len;
+ rpc_in.resp = kzalloc(*out_len, GFP_KERNEL);
+ if (!rpc_in.resp)
+ return ERR_PTR(-ENOMEM);
+
+ rpc_in.resp_max_len = *out_len;
+ rpc_in.timeout = bnxtctl_get_timeout(in);
+
+ guard(mutex)(&edev->en_dev_lock);
+
+ if (!bnxtctl_validate_rpc(edev, &rpc_in, scope)) {
+ kfree(rpc_in.resp);
+ return ERR_PTR(-EPERM);
+ }
+
+ rc = bnxt_send_msg(edev, &rpc_in);
+ if (rc) {
+ struct output *resp = rpc_in.resp;
+
+ /* Copy the response to user always, as it contains
+ * detailed status of the command failure
+ */
+ if (!resp->error_code)
+ /* bnxt_send_msg() returned much before FW
+ * received the command.
+ */
+ resp->error_code = cpu_to_le16(rc);
+ }
+
+ return rpc_in.resp;
+}
+
+static const struct fwctl_ops bnxtctl_ops = {
+ .device_type = FWCTL_DEVICE_TYPE_BNXT,
+ .uctx_size = sizeof(struct bnxtctl_uctx),
+ .open_uctx = bnxtctl_open_uctx,
+ .close_uctx = bnxtctl_close_uctx,
+ .info = bnxtctl_info,
+ .fw_rpc = bnxtctl_fw_rpc,
+};
+
+static int bnxtctl_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct bnxt_aux_priv *aux_priv =
+ container_of(adev, struct bnxt_aux_priv, aux_dev);
+ struct bnxtctl_dev *bnxtctl __free(bnxtctl) =
+ fwctl_alloc_device(&aux_priv->edev->pdev->dev, &bnxtctl_ops,
+ struct bnxtctl_dev, fwctl);
+ int rc;
+
+ if (!bnxtctl)
+ return -ENOMEM;
+
+ bnxtctl->aux_priv = aux_priv;
+
+ rc = fwctl_register(&bnxtctl->fwctl);
+ if (rc)
+ return rc;
+
+ auxiliary_set_drvdata(adev, no_free_ptr(bnxtctl));
+ return 0;
+}
+
+static void bnxtctl_remove(struct auxiliary_device *adev)
+{
+ struct bnxtctl_dev *ctldev = auxiliary_get_drvdata(adev);
+
+ fwctl_unregister(&ctldev->fwctl);
+ fwctl_put(&ctldev->fwctl);
+}
+
+static const struct auxiliary_device_id bnxtctl_id_table[] = {
+ { .name = "bnxt_en.fwctl", },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, bnxtctl_id_table);
+
+static struct auxiliary_driver bnxtctl_driver = {
+ .name = "bnxt_fwctl",
+ .probe = bnxtctl_probe,
+ .remove = bnxtctl_remove,
+ .id_table = bnxtctl_id_table,
+};
+
+module_auxiliary_driver(bnxtctl_driver);
+
+MODULE_IMPORT_NS("FWCTL");
+MODULE_DESCRIPTION("BNXT fwctl driver");
+MODULE_AUTHOR("Pavan Chebbi <pavan.chebbi@broadcom.com>");
+MODULE_AUTHOR("Andy Gospodarek <gospo@broadcom.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c
index bc6378506296..098c3824ad75 100644
--- a/drivers/fwctl/main.c
+++ b/drivers/fwctl/main.c
@@ -415,7 +415,7 @@ static void __exit fwctl_exit(void)
unregister_chrdev_region(fwctl_dev, FWCTL_MAX_DEVICES);
}
-module_init(fwctl_init);
+subsys_initcall(fwctl_init);
module_exit(fwctl_exit);
MODULE_DESCRIPTION("fwctl device firmware access framework");
MODULE_LICENSE("GPL");
diff --git a/drivers/infiniband/hw/bnxt_re/debugfs.c b/drivers/infiniband/hw/bnxt_re/debugfs.c
index a2ad79c3bbd0..5fed2cf66be3 100644
--- a/drivers/infiniband/hw/bnxt_re/debugfs.c
+++ b/drivers/infiniband/hw/bnxt_re/debugfs.c
@@ -10,8 +10,8 @@
#include <linux/pci.h>
#include <linux/seq_file.h>
#include <rdma/ib_addr.h>
+#include <linux/bnxt/ulp.h>
-#include "bnxt_ulp.h"
#include "roce_hsi.h"
#include "qplib_res.h"
#include "qplib_sp.h"
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index b576f05e3b26..47afccddf55e 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -55,8 +55,8 @@
#include <rdma/ib_umem.h>
#include <rdma/ib_addr.h>
#include <linux/hashtable.h>
+#include <linux/bnxt/ulp.h>
-#include "bnxt_ulp.h"
#include "roce_hsi.h"
#include "qplib_res.h"
#include "qplib_sp.h"
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index 2d7932b3c492..b4c7b8f582ba 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -46,6 +46,7 @@
#include <linux/delay.h>
#include <linux/prefetch.h>
#include <linux/if_ether.h>
+#include <linux/bnxt/ulp.h>
#include <rdma/ib_mad.h>
#include "roce_hsi.h"
@@ -55,7 +56,6 @@
#include "qplib_sp.h"
#include "qplib_fp.h"
#include <rdma/ib_addr.h>
-#include "bnxt_ulp.h"
#include "bnxt_re.h"
#include "ib_verbs.h"
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h
index 9a5dcf97b6f4..0a4a03efeb0b 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h
@@ -39,7 +39,7 @@
#ifndef __BNXT_QPLIB_RES_H__
#define __BNXT_QPLIB_RES_H__
-#include "bnxt_ulp.h"
+#include <linux/bnxt/ulp.h>
extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 2715632115a5..58cf02bcb98a 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -59,10 +59,10 @@
#include <net/netdev_rx_queue.h>
#include <linux/pci-tph.h>
#include <linux/bnxt/hsi.h>
+#include <linux/bnxt/ulp.h>
#include "bnxt.h"
#include "bnxt_hwrm.h"
-#include "bnxt_ulp.h"
#include "bnxt_sriov.h"
#include "bnxt_ethtool.h"
#include "bnxt_dcb.h"
@@ -6985,7 +6985,8 @@ vnic_mru:
#endif
if ((bp->flags & BNXT_FLAG_STRIP_VLAN) || def_vlan)
req->flags |= cpu_to_le32(VNIC_CFG_REQ_FLAGS_VLAN_STRIP_MODE);
- if (vnic->vnic_id == BNXT_VNIC_DEFAULT && bnxt_ulp_registered(bp->edev))
+ if (vnic->vnic_id == BNXT_VNIC_DEFAULT &&
+ bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA]))
req->flags |= cpu_to_le32(bnxt_get_roce_vnic_mode(bp));
return hwrm_req_send(bp, req);
@@ -8120,6 +8121,7 @@ static int bnxt_get_avail_msix(struct bnxt *bp, int num);
static int __bnxt_reserve_rings(struct bnxt *bp)
{
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
struct bnxt_hw_rings hwr = {0};
int rx_rings, old_rx_rings, rc;
int cp = bp->cp_nr_rings;
@@ -8130,7 +8132,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
if (!bnxt_need_reserve_rings(bp))
return 0;
- if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(bp->edev)) {
+ if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
if (!ulp_msix)
bnxt_set_ulp_stat_ctxs(bp, 0);
@@ -8183,8 +8185,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
}
rx_rings = min_t(int, rx_rings, hwr.grp);
hwr.cp = min_t(int, hwr.cp, bp->cp_nr_rings);
- if (bnxt_ulp_registered(bp->edev) &&
- hwr.stat > bnxt_get_ulp_stat_ctxs(bp))
+ if (bnxt_ulp_registered(edev) && hwr.stat > bnxt_get_ulp_stat_ctxs(bp))
hwr.stat -= bnxt_get_ulp_stat_ctxs(bp);
hwr.cp = min_t(int, hwr.cp, hwr.stat);
rc = bnxt_trim_rings(bp, &rx_rings, &hwr.tx, hwr.cp, sh);
@@ -8227,7 +8228,7 @@ static int __bnxt_reserve_rings(struct bnxt *bp)
!netif_is_rxfh_configured(bp->dev))
bnxt_set_dflt_rss_indir_tbl(bp, NULL);
- if (!bnxt_ulp_registered(bp->edev) && BNXT_NEW_RM(bp)) {
+ if (!bnxt_ulp_registered(edev) && BNXT_NEW_RM(bp)) {
int resv_msix, resv_ctx, ulp_ctxs;
struct bnxt_hw_resc *hw_resc;
@@ -11584,6 +11585,7 @@ static void bnxt_clear_int_mode(struct bnxt *bp)
int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
{
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
bool irq_cleared = false;
bool irq_change = false;
int tcs = bp->num_tc;
@@ -11593,7 +11595,7 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
if (!bnxt_need_reserve_rings(bp))
return 0;
- if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(bp->edev)) {
+ if (BNXT_NEW_RM(bp) && !bnxt_ulp_registered(edev)) {
int ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want);
if (ulp_msix > bp->ulp_num_msix_want)
@@ -14700,7 +14702,7 @@ static void bnxt_fw_echo_reply(struct bnxt *bp)
static void bnxt_ulp_restart(struct bnxt *bp)
{
bnxt_ulp_stop(bp);
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
}
static void bnxt_sp_task(struct work_struct *work)
@@ -14857,7 +14859,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
hwr.cp_p5 = hwr.tx + rx;
rc = bnxt_hwrm_check_rings(bp, &hwr);
if (!rc && pci_msix_can_alloc_dyn(bp->pdev)) {
- if (!bnxt_ulp_registered(bp->edev)) {
+ if (!bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA])) {
hwr.cp += bnxt_get_ulp_msix_num(bp);
hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp));
}
@@ -15377,7 +15379,7 @@ static void bnxt_fw_reset_task(struct work_struct *work)
bnxt_dl_health_fw_status_update(bp, true);
}
netdev_unlock(bp->dev);
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
bnxt_reenable_sriov(bp);
netdev_lock(bp->dev);
bnxt_vf_reps_alloc(bp);
@@ -15399,7 +15401,8 @@ fw_reset_abort:
bnxt_fw_reset_abort(bp, rc);
netdev_unlock(bp->dev);
ulp_start:
- bnxt_ulp_start(bp, rc);
+ if (!rc)
+ bnxt_ulp_start(bp);
}
static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
@@ -16444,12 +16447,13 @@ static void bnxt_remove_one(struct pci_dev *pdev)
if (BNXT_PF(bp))
__bnxt_sriov_disable(bp);
- bnxt_rdma_aux_device_del(bp);
+ bnxt_aux_devices_del(bp);
unregister_netdev(dev);
bnxt_ptp_clear(bp);
- bnxt_rdma_aux_device_uninit(bp);
+ bnxt_aux_devices_uninit(bp);
+ bnxt_auxdev_id_free(bp, bp->auxdev_id);
bnxt_free_l2_filters(bp, true);
bnxt_free_ntp_fltrs(bp, true);
@@ -17053,7 +17057,9 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bnxt_set_tpa_flags(bp);
bnxt_init_ring_params(bp);
bnxt_set_ring_params(bp);
- bnxt_rdma_aux_device_init(bp);
+ mutex_init(&bp->auxdev_lock);
+ if (!bnxt_auxdev_id_alloc(bp))
+ bnxt_aux_devices_init(bp);
rc = bnxt_set_dflt_rings(bp, true);
if (rc) {
if (BNXT_VF(bp) && rc == -ENODEV) {
@@ -17118,7 +17124,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bnxt_dl_fw_reporters_create(bp);
- bnxt_rdma_aux_device_add(bp);
+ bnxt_aux_devices_add(bp);
bnxt_print_device_info(bp);
@@ -17126,7 +17132,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
init_err_cleanup:
- bnxt_rdma_aux_device_uninit(bp);
+ bnxt_aux_devices_uninit(bp);
+ bnxt_auxdev_id_free(bp, bp->auxdev_id);
bnxt_dl_unregister(bp);
init_err_dl:
bnxt_shutdown_tc(bp);
@@ -17260,9 +17267,10 @@ static int bnxt_resume(struct device *device)
resume_exit:
netdev_unlock(bp->dev);
- bnxt_ulp_start(bp, rc);
- if (!rc)
+ if (!rc) {
+ bnxt_ulp_start(bp);
bnxt_reenable_sriov(bp);
+ }
return rc;
}
@@ -17442,9 +17450,10 @@ static void bnxt_io_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
netdev_unlock(netdev);
- bnxt_ulp_start(bp, err);
- if (!err)
+ if (!err) {
+ bnxt_ulp_start(bp);
bnxt_reenable_sriov(bp);
+ }
}
static const struct pci_error_handlers bnxt_err_handler = {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index fe50576ae525..61c847b36b9f 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -26,12 +26,12 @@
#include <linux/interrupt.h>
#include <linux/rhashtable.h>
#include <linux/crash_dump.h>
-#include <linux/auxiliary_bus.h>
#include <net/devlink.h>
#include <net/dst_metadata.h>
#include <net/xdp.h>
#include <linux/dim.h>
#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/bnxt/ulp.h>
#ifdef CONFIG_TEE_BNXT_FW
#include <linux/firmware/broadcom/tee_bnxt_fw.h>
#endif
@@ -2100,12 +2100,6 @@ struct bnxt_fw_health {
#define BNXT_FW_IF_RETRY 10
#define BNXT_FW_SLOT_RESET_RETRY 4
-struct bnxt_aux_priv {
- struct auxiliary_device aux_dev;
- struct bnxt_en_dev *edev;
- int id;
-};
-
enum board_idx {
BCM57301,
BCM57302,
@@ -2365,8 +2359,8 @@ struct bnxt {
#define BNXT_CHIP_P5_AND_MINUS(bp) \
(BNXT_CHIP_P3(bp) || BNXT_CHIP_P4(bp) || BNXT_CHIP_P5(bp))
- struct bnxt_aux_priv *aux_priv;
- struct bnxt_en_dev *edev;
+ struct bnxt_aux_priv *aux_priv[__BNXT_AUXDEV_MAX];
+ struct bnxt_en_dev *edev[__BNXT_AUXDEV_MAX];
struct bnxt_napi **bnapi;
@@ -2778,6 +2772,13 @@ struct bnxt {
struct bnxt_ctx_pg_info *fw_crash_mem;
u32 fw_crash_len;
struct bnxt_bs_trace_info bs_trace[BNXT_TRACE_MAX];
+ int auxdev_id;
+ /* synchronize validity checks of available aux devices */
+ struct mutex auxdev_lock;
+ u8 auxdev_state[__BNXT_AUXDEV_MAX];
+#define BNXT_ADEV_STATE_NONE 0
+#define BNXT_ADEV_STATE_INIT 1
+#define BNXT_ADEV_STATE_ADD 2
};
#define BNXT_NUM_RX_RING_STATS 8
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
index 15de802bbac4..835f2b413931 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
@@ -13,12 +13,12 @@
#include <net/devlink.h>
#include <net/netdev_lock.h>
#include <linux/bnxt/hsi.h>
+#include <linux/bnxt/ulp.h>
#include "bnxt.h"
#include "bnxt_hwrm.h"
#include "bnxt_vfr.h"
#include "bnxt_devlink.h"
#include "bnxt_ethtool.h"
-#include "bnxt_ulp.h"
#include "bnxt_ptp.h"
#include "bnxt_coredump.h"
#include "bnxt_nvm_defs.h"
@@ -440,13 +440,13 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
"reload is unsupported while VFs are allocated or being configured");
netdev_unlock(bp->dev);
rtnl_unlock();
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
return -EOPNOTSUPP;
}
if (bp->dev->reg_state == NETREG_UNREGISTERED) {
netdev_unlock(bp->dev);
rtnl_unlock();
- bnxt_ulp_start(bp, 0);
+ bnxt_ulp_start(bp);
return -ENODEV;
}
if (netif_running(bp->dev))
@@ -578,8 +578,8 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti
}
netdev_unlock(bp->dev);
rtnl_unlock();
- if (action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
- bnxt_ulp_start(bp, rc);
+ if (!rc && action == DEVLINK_RELOAD_ACTION_DRIVER_REINIT)
+ bnxt_ulp_start(bp);
return rc;
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
index 9ded88196bb4..9b14134d62d2 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
@@ -27,9 +27,9 @@
#include <net/netdev_queues.h>
#include <net/netlink.h>
#include <linux/bnxt/hsi.h>
+#include <linux/bnxt/ulp.h>
#include "bnxt.h"
#include "bnxt_hwrm.h"
-#include "bnxt_ulp.h"
#include "bnxt_xdp.h"
#include "bnxt_ptp.h"
#include "bnxt_ethtool.h"
@@ -5245,7 +5245,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
memset(buf, 0, sizeof(u64) * bp->num_tests);
if (etest->flags & ETH_TEST_FL_OFFLINE &&
- bnxt_ulp_registered(bp->edev)) {
+ bnxt_ulp_registered(bp->edev[BNXT_AUXDEV_RDMA])) {
etest->flags |= ETH_TEST_FL_FAILED;
netdev_warn(dev, "Offline tests cannot be run with RoCE driver loaded\n");
return;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
index 7f9829287c49..edcc002e4ca3 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -17,9 +17,9 @@
#include <linux/etherdevice.h>
#include <net/dcbnl.h>
#include <linux/bnxt/hsi.h>
+#include <linux/bnxt/ulp.h>
#include "bnxt.h"
#include "bnxt_hwrm.h"
-#include "bnxt_ulp.h"
#include "bnxt_sriov.h"
#include "bnxt_vfr.h"
#include "bnxt_ethtool.h"
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
index e1e82a72cf1b..052bf69cfa4c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
@@ -22,16 +22,41 @@
#include <linux/auxiliary_bus.h>
#include <net/netdev_lock.h>
#include <linux/bnxt/hsi.h>
+#include <linux/bnxt/ulp.h>
#include "bnxt.h"
#include "bnxt_hwrm.h"
-#include "bnxt_ulp.h"
static DEFINE_IDA(bnxt_aux_dev_ids);
+struct bnxt_aux_device {
+ const char *name;
+};
+
+static void bnxt_auxdev_set_state(struct bnxt *bp, int idx, int state)
+{
+ bp->auxdev_state[idx] = state;
+}
+
+static bool bnxt_auxdev_is_init(struct bnxt *bp, int idx)
+{
+ return (bp->auxdev_state[idx] == BNXT_ADEV_STATE_INIT);
+}
+
+static bool bnxt_auxdev_is_active(struct bnxt *bp, int idx)
+{
+ return (bp->auxdev_state[idx] == BNXT_ADEV_STATE_ADD);
+}
+
+static struct bnxt_aux_device bnxt_aux_devices[__BNXT_AUXDEV_MAX] = {{
+ .name = "rdma",
+}, {
+ .name = "fwctl",
+}};
+
static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
{
- struct bnxt_en_dev *edev = bp->edev;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
int num_msix, i;
if (!edev->ulp_tbl->msix_requested) {
@@ -51,61 +76,75 @@ static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
int bnxt_get_ulp_msix_num(struct bnxt *bp)
{
- if (bp->edev)
- return bp->edev->ulp_num_msix_vec;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ return edev->ulp_num_msix_vec;
return 0;
}
void bnxt_set_ulp_msix_num(struct bnxt *bp, int num)
{
- if (bp->edev)
- bp->edev->ulp_num_msix_vec = num;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ edev->ulp_num_msix_vec = num;
}
int bnxt_get_ulp_msix_num_in_use(struct bnxt *bp)
{
- if (bnxt_ulp_registered(bp->edev))
- return bp->edev->ulp_num_msix_vec;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (bnxt_ulp_registered(edev))
+ return edev->ulp_num_msix_vec;
return 0;
}
int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
{
- if (bp->edev)
- return bp->edev->ulp_num_ctxs;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ return edev->ulp_num_ctxs;
return 0;
}
void bnxt_set_ulp_stat_ctxs(struct bnxt *bp, int num_ulp_ctx)
{
- if (bp->edev)
- bp->edev->ulp_num_ctxs = num_ulp_ctx;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev)
+ edev->ulp_num_ctxs = num_ulp_ctx;
}
int bnxt_get_ulp_stat_ctxs_in_use(struct bnxt *bp)
{
- if (bnxt_ulp_registered(bp->edev))
- return bp->edev->ulp_num_ctxs;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (bnxt_ulp_registered(edev))
+ return edev->ulp_num_ctxs;
return 0;
}
void bnxt_set_dflt_ulp_stat_ctxs(struct bnxt *bp)
{
- if (bp->edev) {
- bp->edev->ulp_num_ctxs = BNXT_MIN_ROCE_STAT_CTXS;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
+
+ if (edev) {
+ edev->ulp_num_ctxs = BNXT_MIN_ROCE_STAT_CTXS;
/* Reserve one additional stat_ctx for PF0 (except
* on 1-port NICs) as it also creates one stat_ctx
* for PF1 in case of RoCE bonding.
*/
if (BNXT_PF(bp) && !bp->pf.port_id &&
bp->port_count > 1)
- bp->edev->ulp_num_ctxs++;
+ edev->ulp_num_ctxs++;
/* Reserve one additional stat_ctx when the device is capable
* of supporting port mirroring on RDMA device.
*/
if (BNXT_MIRROR_ON_ROCE_CAP(bp))
- bp->edev->ulp_num_ctxs++;
+ edev->ulp_num_ctxs++;
}
}
@@ -141,7 +180,7 @@ int bnxt_register_dev(struct bnxt_en_dev *edev,
edev->ulp_tbl->msix_requested = bnxt_get_ulp_msix_num(bp);
- bnxt_fill_msix_vecs(bp, bp->edev->msix_entries);
+ bnxt_fill_msix_vecs(bp, edev->msix_entries);
exit:
mutex_unlock(&edev->en_dev_lock);
netdev_unlock(dev);
@@ -227,20 +266,32 @@ EXPORT_SYMBOL(bnxt_send_msg);
void bnxt_ulp_stop(struct bnxt *bp)
{
- struct bnxt_aux_priv *aux_priv = bp->aux_priv;
- struct bnxt_en_dev *edev = bp->edev;
+ int i;
- if (!edev)
- return;
-
- mutex_lock(&edev->en_dev_lock);
- if (!bnxt_ulp_registered(edev) ||
- (edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
- goto ulp_stop_exit;
-
- edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
- if (aux_priv) {
+ mutex_lock(&bp->auxdev_lock);
+ for (i = 0; i < __BNXT_AUXDEV_MAX; i++) {
+ struct bnxt_aux_priv *aux_priv;
struct auxiliary_device *adev;
+ struct bnxt_en_dev *edev;
+
+ if (!bnxt_auxdev_is_active(bp, i))
+ continue;
+
+ aux_priv = bp->aux_priv[i];
+ edev = bp->edev[i];
+ mutex_lock(&edev->en_dev_lock);
+ if (i == BNXT_AUXDEV_FWCTL) {
+ edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
+ mutex_unlock(&edev->en_dev_lock);
+ continue;
+ }
+ if (!bnxt_ulp_registered(edev) ||
+ (edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
+ mutex_unlock(&edev->en_dev_lock);
+ continue;
+ }
+
+ edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
adev = &aux_priv->aux_dev;
if (adev->dev.driver) {
@@ -251,29 +302,35 @@ void bnxt_ulp_stop(struct bnxt *bp)
edev->en_state = bp->state;
adrv->suspend(adev, pm);
}
+ mutex_unlock(&edev->en_dev_lock);
}
-ulp_stop_exit:
- mutex_unlock(&edev->en_dev_lock);
+ mutex_unlock(&bp->auxdev_lock);
}
-void bnxt_ulp_start(struct bnxt *bp, int err)
+void bnxt_ulp_start(struct bnxt *bp)
{
- struct bnxt_aux_priv *aux_priv = bp->aux_priv;
- struct bnxt_en_dev *edev = bp->edev;
+ int i;
- if (!edev || err)
- return;
+ mutex_lock(&bp->auxdev_lock);
+ for (i = 0; i < __BNXT_AUXDEV_MAX; i++) {
+ struct bnxt_aux_priv *aux_priv;
+ struct auxiliary_device *adev;
+ struct bnxt_en_dev *edev;
- mutex_lock(&edev->en_dev_lock);
- if (!bnxt_ulp_registered(edev) ||
- !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
- goto ulp_start_exit;
+ if (!bnxt_auxdev_is_active(bp, i))
+ continue;
- if (edev->ulp_tbl->msix_requested)
- bnxt_fill_msix_vecs(bp, edev->msix_entries);
+ aux_priv = bp->aux_priv[i];
+ edev = bp->edev[i];
+ mutex_lock(&edev->en_dev_lock);
+ if (i == BNXT_AUXDEV_FWCTL || !bnxt_ulp_registered(edev) ||
+ !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
+ goto clear_flag_continue;
+ }
+
+ if (edev->ulp_tbl->msix_requested)
+ bnxt_fill_msix_vecs(bp, edev->msix_entries);
- if (aux_priv) {
- struct auxiliary_device *adev;
adev = &aux_priv->aux_dev;
if (adev->dev.driver) {
@@ -283,22 +340,23 @@ void bnxt_ulp_start(struct bnxt *bp, int err)
edev->en_state = bp->state;
adrv->resume(adev);
}
+clear_flag_continue:
+ edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
+ mutex_unlock(&edev->en_dev_lock);
}
-ulp_start_exit:
- edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
- mutex_unlock(&edev->en_dev_lock);
+ mutex_unlock(&bp->auxdev_lock);
}
void bnxt_ulp_irq_stop(struct bnxt *bp)
{
- struct bnxt_en_dev *edev = bp->edev;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
struct bnxt_ulp_ops *ops;
bool reset = false;
if (!edev)
return;
- if (bnxt_ulp_registered(bp->edev)) {
+ if (bnxt_ulp_registered(edev)) {
struct bnxt_ulp *ulp = edev->ulp_tbl;
if (!ulp->msix_requested)
@@ -315,13 +373,13 @@ void bnxt_ulp_irq_stop(struct bnxt *bp)
void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
{
- struct bnxt_en_dev *edev = bp->edev;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
struct bnxt_ulp_ops *ops;
if (!edev)
return;
- if (bnxt_ulp_registered(bp->edev)) {
+ if (bnxt_ulp_registered(edev)) {
struct bnxt_ulp *ulp = edev->ulp_tbl;
struct bnxt_msix_entry *ent = NULL;
@@ -346,7 +404,7 @@ void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl)
{
u16 event_id = le16_to_cpu(cmpl->event_id);
- struct bnxt_en_dev *edev = bp->edev;
+ struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA];
struct bnxt_ulp_ops *ops;
struct bnxt_ulp *ulp;
@@ -387,18 +445,21 @@ void bnxt_register_async_events(struct bnxt_en_dev *edev,
}
EXPORT_SYMBOL(bnxt_register_async_events);
-void bnxt_rdma_aux_device_uninit(struct bnxt *bp)
+void bnxt_aux_devices_uninit(struct bnxt *bp)
{
struct bnxt_aux_priv *aux_priv;
struct auxiliary_device *adev;
-
- /* Skip if no auxiliary device init was done. */
- if (!bp->aux_priv)
- return;
-
- aux_priv = bp->aux_priv;
- adev = &aux_priv->aux_dev;
- auxiliary_device_uninit(adev);
+ int idx;
+
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ if (bnxt_auxdev_is_init(bp, idx)) {
+ aux_priv = bp->aux_priv[idx];
+ adev = &aux_priv->aux_dev;
+ auxiliary_device_uninit(adev);
+ }
+ }
+ mutex_unlock(&bp->auxdev_lock);
}
static void bnxt_aux_dev_release(struct device *dev)
@@ -407,20 +468,25 @@ static void bnxt_aux_dev_release(struct device *dev)
container_of(dev, struct bnxt_aux_priv, aux_dev.dev);
struct bnxt *bp = netdev_priv(aux_priv->edev->net);
- ida_free(&bnxt_aux_dev_ids, aux_priv->id);
kfree(aux_priv->edev->ulp_tbl);
- bp->edev = NULL;
+ bp->edev[aux_priv->id] = NULL;
kfree(aux_priv->edev);
+ bp->aux_priv[aux_priv->id] = NULL;
kfree(aux_priv);
- bp->aux_priv = NULL;
}
-void bnxt_rdma_aux_device_del(struct bnxt *bp)
+void bnxt_aux_devices_del(struct bnxt *bp)
{
- if (!bp->edev)
- return;
+ int idx;
- auxiliary_device_delete(&bp->aux_priv->aux_dev);
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ if (bnxt_auxdev_is_active(bp, idx)) {
+ auxiliary_device_delete(&bp->aux_priv[idx]->aux_dev);
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
+ }
+ }
+ mutex_unlock(&bp->auxdev_lock);
}
static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp)
@@ -450,83 +516,106 @@ static void bnxt_set_edev_info(struct bnxt_en_dev *edev, struct bnxt *bp)
edev->bar0 = bp->bar0;
}
-void bnxt_rdma_aux_device_add(struct bnxt *bp)
+void bnxt_aux_devices_add(struct bnxt *bp)
{
struct auxiliary_device *aux_dev;
- int rc;
-
- if (!bp->edev)
- return;
-
- aux_dev = &bp->aux_priv->aux_dev;
- rc = auxiliary_device_add(aux_dev);
- if (rc) {
- netdev_warn(bp->dev, "Failed to add auxiliary device for ROCE\n");
- auxiliary_device_uninit(aux_dev);
- bp->flags &= ~BNXT_FLAG_ROCE_CAP;
+ int rc, idx;
+
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ if (bnxt_auxdev_is_init(bp, idx)) {
+ aux_dev = &bp->aux_priv[idx]->aux_dev;
+ rc = auxiliary_device_add(aux_dev);
+ if (rc) {
+ netdev_warn(bp->dev, "Failed to add auxiliary device for auxdev type %d\n",
+ idx);
+ auxiliary_device_uninit(aux_dev);
+ if (idx == BNXT_AUXDEV_RDMA)
+ bp->flags &= ~BNXT_FLAG_ROCE_CAP;
+ continue;
+ }
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_ADD);
+ }
}
+ mutex_unlock(&bp->auxdev_lock);
}
-void bnxt_rdma_aux_device_init(struct bnxt *bp)
+void bnxt_aux_devices_init(struct bnxt *bp)
{
struct auxiliary_device *aux_dev;
struct bnxt_aux_priv *aux_priv;
struct bnxt_en_dev *edev;
struct bnxt_ulp *ulp;
- int rc;
+ int rc, idx;
+
+ mutex_lock(&bp->auxdev_lock);
+ for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) {
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_NONE);
+
+ if (idx == BNXT_AUXDEV_RDMA &&
+ !(bp->flags & BNXT_FLAG_ROCE_CAP))
+ continue;
+
+ aux_priv = kzalloc_obj(*aux_priv);
+ if (!aux_priv)
+ goto next_auxdev;
+
+ aux_dev = &aux_priv->aux_dev;
+ aux_dev->id = bp->auxdev_id;
+ aux_dev->name = bnxt_aux_devices[idx].name;
+ aux_dev->dev.parent = &bp->pdev->dev;
+ aux_dev->dev.release = bnxt_aux_dev_release;
+
+ rc = auxiliary_device_init(aux_dev);
+ if (rc) {
+ kfree(aux_priv);
+ goto next_auxdev;
+ }
+ bp->aux_priv[idx] = aux_priv;
- if (!(bp->flags & BNXT_FLAG_ROCE_CAP))
- return;
+ /* From this point, all cleanup will happen via the .release
+ * callback & any error unwinding will need to include a call
+ * to auxiliary_device_uninit.
+ */
+ edev = kzalloc_obj(*edev);
+ if (!edev)
+ goto aux_dev_uninit;
- aux_priv = kzalloc_obj(*bp->aux_priv);
- if (!aux_priv)
- goto exit;
+ aux_priv->edev = edev;
+ bnxt_set_edev_info(edev, bp);
- aux_priv->id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL);
- if (aux_priv->id < 0) {
- netdev_warn(bp->dev,
- "ida alloc failed for ROCE auxiliary device\n");
- kfree(aux_priv);
- goto exit;
- }
+ ulp = kzalloc_obj(*ulp);
+ if (!ulp)
+ goto aux_dev_uninit;
- aux_dev = &aux_priv->aux_dev;
- aux_dev->id = aux_priv->id;
- aux_dev->name = "rdma";
- aux_dev->dev.parent = &bp->pdev->dev;
- aux_dev->dev.release = bnxt_aux_dev_release;
+ edev->ulp_tbl = ulp;
+ bp->edev[idx] = edev;
+ if (idx == BNXT_AUXDEV_RDMA)
+ bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
+ aux_priv->id = idx;
+ bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
- rc = auxiliary_device_init(aux_dev);
- if (rc) {
- ida_free(&bnxt_aux_dev_ids, aux_priv->id);
- kfree(aux_priv);
- goto exit;
+ continue;
+aux_dev_uninit:
+ auxiliary_device_uninit(aux_dev);
+next_auxdev:
+ if (idx == BNXT_AUXDEV_RDMA)
+ bp->flags &= ~BNXT_FLAG_ROCE_CAP;
}
- bp->aux_priv = aux_priv;
-
- /* From this point, all cleanup will happen via the .release callback &
- * any error unwinding will need to include a call to
- * auxiliary_device_uninit.
- */
- edev = kzalloc_obj(*edev);
- if (!edev)
- goto aux_dev_uninit;
-
- aux_priv->edev = edev;
-
- ulp = kzalloc_obj(*ulp);
- if (!ulp)
- goto aux_dev_uninit;
+ mutex_unlock(&bp->auxdev_lock);
+}
- edev->ulp_tbl = ulp;
- bp->edev = edev;
- bnxt_set_edev_info(edev, bp);
- bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
+int bnxt_auxdev_id_alloc(struct bnxt *bp)
+{
+ bp->auxdev_id = ida_alloc(&bnxt_aux_dev_ids, GFP_KERNEL);
+ if (bp->auxdev_id < 0)
+ return bp->auxdev_id;
- return;
+ return 0;
+}
-aux_dev_uninit:
- auxiliary_device_uninit(aux_dev);
-exit:
- bp->flags &= ~BNXT_FLAG_ROCE_CAP;
+void bnxt_auxdev_id_free(struct bnxt *bp, int id)
+{
+ if (bp->auxdev_id >= 0)
+ ida_free(&bnxt_aux_dev_ids, id);
}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/include/linux/bnxt/ulp.h
index 3c5b8a53f715..0851ad3394b0 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h
+++ b/include/linux/bnxt/ulp.h
@@ -10,6 +10,8 @@
#ifndef BNXT_ULP_H
#define BNXT_ULP_H
+#include <linux/auxiliary_bus.h>
+
#define BNXT_MIN_ROCE_CP_RINGS 2
#define BNXT_MIN_ROCE_STAT_CTXS 1
@@ -20,6 +22,18 @@
struct hwrm_async_event_cmpl;
struct bnxt;
+enum bnxt_auxdev_type {
+ BNXT_AUXDEV_RDMA = 0,
+ BNXT_AUXDEV_FWCTL,
+ __BNXT_AUXDEV_MAX
+};
+
+struct bnxt_aux_priv {
+ struct auxiliary_device aux_dev;
+ struct bnxt_en_dev *edev;
+ int id;
+};
+
struct bnxt_msix_entry {
u32 vector;
u32 ring_idx;
@@ -110,19 +124,21 @@ void bnxt_set_ulp_stat_ctxs(struct bnxt *bp, int num_ctxs);
int bnxt_get_ulp_stat_ctxs_in_use(struct bnxt *bp);
void bnxt_set_dflt_ulp_stat_ctxs(struct bnxt *bp);
void bnxt_ulp_stop(struct bnxt *bp);
-void bnxt_ulp_start(struct bnxt *bp, int err);
+void bnxt_ulp_start(struct bnxt *bp);
void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs);
void bnxt_ulp_irq_stop(struct bnxt *bp);
void bnxt_ulp_irq_restart(struct bnxt *bp, int err);
void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl);
-void bnxt_rdma_aux_device_uninit(struct bnxt *bp);
-void bnxt_rdma_aux_device_del(struct bnxt *bp);
-void bnxt_rdma_aux_device_add(struct bnxt *bp);
-void bnxt_rdma_aux_device_init(struct bnxt *bp);
+void bnxt_aux_devices_uninit(struct bnxt *bp);
+void bnxt_aux_devices_del(struct bnxt *bp);
+void bnxt_aux_devices_add(struct bnxt *bp);
+void bnxt_aux_devices_init(struct bnxt *bp);
int bnxt_register_dev(struct bnxt_en_dev *edev, struct bnxt_ulp_ops *ulp_ops,
void *handle);
void bnxt_unregister_dev(struct bnxt_en_dev *edev);
int bnxt_send_msg(struct bnxt_en_dev *edev, struct bnxt_fw_msg *fw_msg);
void bnxt_register_async_events(struct bnxt_en_dev *edev,
unsigned long *events_bmap, u16 max_id);
+int bnxt_auxdev_id_alloc(struct bnxt *bp);
+void bnxt_auxdev_id_free(struct bnxt *bp, int id);
#endif
diff --git a/include/uapi/fwctl/bnxt.h b/include/uapi/fwctl/bnxt.h
new file mode 100644
index 000000000000..32e0bfb9a836
--- /dev/null
+++ b/include/uapi/fwctl/bnxt.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (c) 2026, Broadcom Inc
+ */
+
+#ifndef _UAPI_FWCTL_BNXT_H_
+#define _UAPI_FWCTL_BNXT_H_
+
+#include <linux/types.h>
+
+enum fwctl_bnxt_commands {
+ FWCTL_BNXT_INLINE_COMMANDS = 0,
+ FWCTL_BNXT_QUERY_COMMANDS,
+ FWCTL_BNXT_SEND_COMMANDS,
+};
+
+/**
+ * struct fwctl_info_bnxt - ioctl(FWCTL_INFO) out_device_data
+ * @uctx_caps: The command capabilities driver accepts.
+ *
+ * Return basic information about the FW interface available.
+ */
+struct fwctl_info_bnxt {
+ __u32 uctx_caps;
+};
+#endif
diff --git a/include/uapi/fwctl/fwctl.h b/include/uapi/fwctl/fwctl.h
index 716ac0eee42d..2d6d4049c205 100644
--- a/include/uapi/fwctl/fwctl.h
+++ b/include/uapi/fwctl/fwctl.h
@@ -44,6 +44,7 @@ enum fwctl_device_type {
FWCTL_DEVICE_TYPE_ERROR = 0,
FWCTL_DEVICE_TYPE_MLX5 = 1,
FWCTL_DEVICE_TYPE_CXL = 2,
+ FWCTL_DEVICE_TYPE_BNXT = 3,
FWCTL_DEVICE_TYPE_PDS = 4,
};