mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge tag 'for-linus-fwctl' of git://git.kernel.org/pub/scm/linux/kernel/git/fwctl/fwctl
Pull fwctl updates from Jason Gunthorpe: - New fwctl driver for Broadcom RDMA NICs - Bug fix for non-modular builds * tag 'for-linus-fwctl' of git://git.kernel.org/pub/scm/linux/kernel/git/fwctl/fwctl: fwctl: Fix class init ordering to avoid NULL pointer dereference on device removal fwctl/bnxt_fwctl: Add documentation entries fwctl/bnxt_fwctl: Add bnxt fwctl device fwctl/bnxt_en: Create an aux device for fwctl fwctl/bnxt_en: Refactor aux bus functions to be more generic fwctl/bnxt_en: Move common definitions to include/linux/bnxt/
This commit is contained in:
74
Documentation/userspace-api/fwctl/bnxt_fwctl.rst
Normal file
74
Documentation/userspace-api/fwctl/bnxt_fwctl.rst
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -10,5 +10,6 @@ to securely construct and execute RPCs inside device firmware.
|
||||
:maxdepth: 1
|
||||
|
||||
fwctl
|
||||
bnxt_fwctl
|
||||
fwctl-cxl
|
||||
pds_fwctl
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
4
drivers/fwctl/bnxt/Makefile
Normal file
4
drivers/fwctl/bnxt/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_FWCTL_BNXT) += bnxt_fwctl.o
|
||||
|
||||
bnxt_fwctl-y += main.o
|
||||
281
drivers/fwctl/bnxt/main.c
Normal file
281
drivers/fwctl/bnxt/main.c
Normal file
@@ -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");
|
||||
@@ -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");
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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(&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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
26
include/uapi/fwctl/bnxt.h
Normal file
26
include/uapi/fwctl/bnxt.h
Normal file
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user