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 +L: linux-kernel@vger.kernel.org +S: Maintained +F: drivers/fwctl/bnxt/ + FWCTL MLX5 DRIVER M: Saeed Mahameed R: Itay Avraham 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 +#include +#include +#include +#include +#include +#include +#include + +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 "); +MODULE_AUTHOR("Andy Gospodarek "); +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 #include #include +#include -#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 #include #include +#include -#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 #include #include +#include #include #include "roce_hsi.h" @@ -55,7 +56,6 @@ #include "qplib_sp.h" #include "qplib_fp.h" #include -#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 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 #include #include +#include #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 #include #include -#include #include #include #include #include #include +#include #ifdef CONFIG_TEE_BNXT_FW #include #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 #include #include +#include #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 #include #include +#include #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 #include #include +#include #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 #include #include +#include #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(&edev->en_dev_lock); - if (!bnxt_ulp_registered(edev) || - !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) - goto ulp_start_exit; - - if (edev->ulp_tbl->msix_requested) - bnxt_fill_msix_vecs(bp, edev->msix_entries); - - 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 || !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); + 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; + int idx; - /* 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); + 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; + int rc, idx; - 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; + 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; - if (!(bp->flags & BNXT_FLAG_ROCE_CAP)) - return; + mutex_lock(&bp->auxdev_lock); + for (idx = 0; idx < __BNXT_AUXDEV_MAX; idx++) { + bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_NONE); - aux_priv = kzalloc_obj(*bp->aux_priv); - if (!aux_priv) - goto exit; + if (idx == BNXT_AUXDEV_RDMA && + !(bp->flags & BNXT_FLAG_ROCE_CAP)) + continue; - 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; - } + aux_priv = kzalloc_obj(*aux_priv); + if (!aux_priv) + goto next_auxdev; - 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; + 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) { - ida_free(&bnxt_aux_dev_ids, aux_priv->id); - kfree(aux_priv); - goto exit; - } - bp->aux_priv = aux_priv; + rc = auxiliary_device_init(aux_dev); + if (rc) { + kfree(aux_priv); + goto next_auxdev; + } + bp->aux_priv[idx] = 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; + /* 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; + aux_priv->edev = edev; + bnxt_set_edev_info(edev, bp); - ulp = kzalloc_obj(*ulp); - if (!ulp) - goto aux_dev_uninit; + ulp = kzalloc_obj(*ulp); + if (!ulp) + goto aux_dev_uninit; - edev->ulp_tbl = ulp; - bp->edev = edev; - bnxt_set_edev_info(edev, bp); - bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp); - - return; + 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); + continue; aux_dev_uninit: - auxiliary_device_uninit(aux_dev); -exit: - bp->flags &= ~BNXT_FLAG_ROCE_CAP; + auxiliary_device_uninit(aux_dev); +next_auxdev: + if (idx == BNXT_AUXDEV_RDMA) + bp->flags &= ~BNXT_FLAG_ROCE_CAP; + } + mutex_unlock(&bp->auxdev_lock); +} + +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 0; +} + +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 similarity index 86% rename from drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h rename to 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 + #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 + +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, };