Commit fb7d8b61 authored by Vikas Gupta's avatar Vikas Gupta Committed by Jakub Kicinski
Browse files

bng_en: Add initial interaction with firmware



Query firmware with the help of basic firmware commands and
cache the capabilities. With the help of basic commands
start the initialization process of the driver with the
firmware.
Since basic information is available from the firmware,
register with devlink.

Signed-off-by: default avatarVikas Gupta <vikas.gupta@broadcom.com>
Reviewed-by: default avatarBhargava Chenna Marreddy <bhargava.marreddy@broadcom.com>
Reviewed-by: default avatarRajashekar Hudumula <rajashekar.hudumula@broadcom.com>
Link: https://patch.msgid.link/20250701143511.280702-5-vikas.gupta@broadcom.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 7037d1d8
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -4,4 +4,5 @@ obj-$(CONFIG_BNGE) += bng_en.o

bng_en-y := bnge_core.o \
	    bnge_devlink.o \
	    bnge_hwrm.o
	    bnge_hwrm.o \
	    bnge_hwrm_lib.o
+54 −0
Original line number Diff line number Diff line
@@ -7,6 +7,13 @@
#define DRV_NAME	"bng_en"
#define DRV_SUMMARY	"Broadcom 800G Ethernet Linux Driver"

#include <linux/etherdevice.h>
#include "../bnxt/bnxt_hsi.h"

#define DRV_VER_MAJ	1
#define DRV_VER_MIN	15
#define DRV_VER_UPD	1

extern char bnge_driver_name[];

enum board_idx {
@@ -15,6 +22,36 @@ enum board_idx {

#define INVALID_HW_RING_ID      ((u16)-1)

enum {
	BNGE_FW_CAP_SHORT_CMD				= BIT_ULL(0),
	BNGE_FW_CAP_LLDP_AGENT				= BIT_ULL(1),
	BNGE_FW_CAP_DCBX_AGENT				= BIT_ULL(2),
	BNGE_FW_CAP_IF_CHANGE				= BIT_ULL(3),
	BNGE_FW_CAP_KONG_MB_CHNL			= BIT_ULL(4),
	BNGE_FW_CAP_ERROR_RECOVERY			= BIT_ULL(5),
	BNGE_FW_CAP_PKG_VER				= BIT_ULL(6),
	BNGE_FW_CAP_CFA_ADV_FLOW			= BIT_ULL(7),
	BNGE_FW_CAP_CFA_RFS_RING_TBL_IDX_V2		= BIT_ULL(8),
	BNGE_FW_CAP_PCIE_STATS_SUPPORTED		= BIT_ULL(9),
	BNGE_FW_CAP_EXT_STATS_SUPPORTED			= BIT_ULL(10),
	BNGE_FW_CAP_ERR_RECOVER_RELOAD			= BIT_ULL(11),
	BNGE_FW_CAP_HOT_RESET				= BIT_ULL(12),
	BNGE_FW_CAP_RX_ALL_PKT_TS			= BIT_ULL(13),
	BNGE_FW_CAP_VLAN_RX_STRIP			= BIT_ULL(14),
	BNGE_FW_CAP_VLAN_TX_INSERT			= BIT_ULL(15),
	BNGE_FW_CAP_EXT_HW_STATS_SUPPORTED		= BIT_ULL(16),
	BNGE_FW_CAP_LIVEPATCH				= BIT_ULL(17),
	BNGE_FW_CAP_HOT_RESET_IF			= BIT_ULL(18),
	BNGE_FW_CAP_RING_MONITOR			= BIT_ULL(19),
	BNGE_FW_CAP_DBG_QCAPS				= BIT_ULL(20),
	BNGE_FW_CAP_THRESHOLD_TEMP_SUPPORTED		= BIT_ULL(21),
	BNGE_FW_CAP_DFLT_VLAN_TPID_PCP			= BIT_ULL(22),
	BNGE_FW_CAP_VNIC_TUNNEL_TPA			= BIT_ULL(23),
	BNGE_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO		= BIT_ULL(24),
	BNGE_FW_CAP_CFA_RFS_RING_TBL_IDX_V3		= BIT_ULL(25),
	BNGE_FW_CAP_VNIC_RE_FLUSH			= BIT_ULL(26),
};

struct bnge_dev {
	struct device	*dev;
	struct pci_dev	*pdev;
@@ -25,6 +62,9 @@ struct bnge_dev {

	void __iomem	*bar0;

	u16		chip_num;
	u8		chip_rev;

	/* HWRM members */
	u16			hwrm_cmd_seq;
	u16			hwrm_cmd_kong_seq;
@@ -35,6 +75,20 @@ struct bnge_dev {
	unsigned int		hwrm_cmd_timeout;
	unsigned int		hwrm_cmd_max_timeout;
	struct mutex		hwrm_cmd_lock;	/* serialize hwrm messages */

	struct hwrm_ver_get_output	ver_resp;
#define FW_VER_STR_LEN		32
	char			fw_ver_str[FW_VER_STR_LEN];
	char			hwrm_ver_supp[FW_VER_STR_LEN];
	char			nvm_cfg_ver[FW_VER_STR_LEN];
	u64			fw_ver_code;
#define BNGE_FW_VER_CODE(maj, min, bld, rsv)			\
	((u64)(maj) << 48 | (u64)(min) << 32 | (u64)(bld) << 16 | (rsv))

	unsigned long           state;
#define BNGE_STATE_DRV_REGISTERED      0

	u64			fw_cap;
};

#endif /* _BNGE_H_ */
+71 −0
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@

#include "bnge.h"
#include "bnge_devlink.h"
#include "bnge_hwrm.h"
#include "bnge_hwrm_lib.h"

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRV_SUMMARY);
@@ -37,6 +39,51 @@ static void bnge_print_device_info(struct pci_dev *pdev, enum board_idx idx)
	pcie_print_link_status(pdev);
}

static void bnge_nvm_cfg_ver_get(struct bnge_dev *bd)
{
	struct hwrm_nvm_get_dev_info_output nvm_info;

	if (!bnge_hwrm_nvm_dev_info(bd, &nvm_info))
		snprintf(bd->nvm_cfg_ver, FW_VER_STR_LEN, "%d.%d.%d",
			 nvm_info.nvm_cfg_ver_maj, nvm_info.nvm_cfg_ver_min,
			 nvm_info.nvm_cfg_ver_upd);
}

static void bnge_fw_unregister_dev(struct bnge_dev *bd)
{
	bnge_hwrm_func_drv_unrgtr(bd);
}

static int bnge_fw_register_dev(struct bnge_dev *bd)
{
	int rc;

	bd->fw_cap = 0;
	rc = bnge_hwrm_ver_get(bd);
	if (rc) {
		dev_err(bd->dev, "Get Version command failed rc: %d\n", rc);
		return rc;
	}

	bnge_nvm_cfg_ver_get(bd);

	rc = bnge_hwrm_func_reset(bd);
	if (rc) {
		dev_err(bd->dev, "Failed to reset function rc: %d\n", rc);
		return rc;
	}

	bnge_hwrm_fw_set_time(bd);

	rc =  bnge_hwrm_func_drv_rgtr(bd);
	if (rc) {
		dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc);
		return rc;
	}

	return 0;
}

static void bnge_pci_disable(struct pci_dev *pdev)
{
	pci_release_regions(pdev);
@@ -126,10 +173,28 @@ static int bnge_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
		goto err_devl_free;
	}

	rc = bnge_init_hwrm_resources(bd);
	if (rc)
		goto err_bar_unmap;

	rc = bnge_fw_register_dev(bd);
	if (rc) {
		dev_err(&pdev->dev, "Failed to register with firmware rc = %d\n", rc);
		goto err_hwrm_cleanup;
	}

	bnge_devlink_register(bd);

	pci_save_state(pdev);

	return 0;

err_hwrm_cleanup:
	bnge_cleanup_hwrm_resources(bd);

err_bar_unmap:
	bnge_unmap_bars(pdev);

err_devl_free:
	bnge_devlink_free(bd);

@@ -142,6 +207,12 @@ static void bnge_remove_one(struct pci_dev *pdev)
{
	struct bnge_dev *bd = pci_get_drvdata(pdev);

	bnge_devlink_unregister(bd);

	bnge_fw_unregister_dev(bd);

	bnge_cleanup_hwrm_resources(bd);

	bnge_unmap_bars(pdev);

	bnge_devlink_free(bd);
+164 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include "bnge.h"
#include "bnge_devlink.h"
#include "bnge_hwrm_lib.h"

static int bnge_dl_info_put(struct bnge_dev *bd, struct devlink_info_req *req,
			    enum bnge_dl_version_type type, const char *key,
@@ -16,6 +17,10 @@ static int bnge_dl_info_put(struct bnge_dev *bd, struct devlink_info_req *req,
	if (!strlen(buf))
		return 0;

	if (!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) ||
	    !strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE))
		return 0;

	switch (type) {
	case BNGE_VERSION_FIXED:
		return devlink_info_version_fixed_put(req, key, buf);
@@ -63,11 +68,20 @@ static void bnge_vpd_read_info(struct bnge_dev *bd)
	kfree(vpd_data);
}

#define HWRM_FW_VER_STR_LEN	16

static int bnge_devlink_info_get(struct devlink *devlink,
				 struct devlink_info_req *req,
				 struct netlink_ext_ack *extack)
{
	struct hwrm_nvm_get_dev_info_output nvm_dev_info;
	struct bnge_dev *bd = devlink_priv(devlink);
	struct hwrm_ver_get_output *ver_resp;
	char mgmt_ver[FW_VER_STR_LEN];
	char roce_ver[FW_VER_STR_LEN];
	char ncsi_ver[FW_VER_STR_LEN];
	char buf[32];

	int rc;

	if (bd->dsn) {
@@ -104,6 +118,144 @@ static int bnge_devlink_info_get(struct devlink *devlink,
		return rc;
	}

	/* More information from HWRM ver get command */
	sprintf(buf, "%X", bd->chip_num);
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_FIXED,
			      DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack, "Failed to set asic id");
		return rc;
	}

	ver_resp = &bd->ver_resp;
	sprintf(buf, "%c%d", 'A' + ver_resp->chip_rev, ver_resp->chip_metal);
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_FIXED,
			      DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack, "Failed to set asic info");
		return rc;
	}

	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING,
			      DEVLINK_INFO_VERSION_GENERIC_FW_PSID,
			      bd->nvm_cfg_ver);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack, "Failed to set firmware version");
		return rc;
	}

	buf[0] = 0;
	strncat(buf, ver_resp->active_pkg_name, HWRM_FW_VER_STR_LEN);
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING,
			      DEVLINK_INFO_VERSION_GENERIC_FW, buf);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set firmware generic version");
		return rc;
	}

	if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) {
		snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
			 ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor,
			 ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch);

		snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
			 ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor,
			 ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch);

		snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
			 ver_resp->roce_fw_major, ver_resp->roce_fw_minor,
			 ver_resp->roce_fw_build, ver_resp->roce_fw_patch);
	} else {
		snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
			 ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b,
			 ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b);

		snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
			 ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b,
			 ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b);

		snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
			 ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b,
			 ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b);
	}
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING,
			      DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set firmware mgmt version");
		return rc;
	}

	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING,
			      DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API,
			      bd->hwrm_ver_supp);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set firmware mgmt api version");
		return rc;
	}

	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING,
			      DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set ncsi firmware version");
		return rc;
	}

	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING,
			      DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack, "Failed to set roce firmware version");
		return rc;
	}

	rc = bnge_hwrm_nvm_dev_info(bd, &nvm_dev_info);
	if (!(nvm_dev_info.flags & NVM_GET_DEV_INFO_RESP_FLAGS_FW_VER_VALID))
		return 0;

	buf[0] = 0;
	strncat(buf, nvm_dev_info.pkg_name, HWRM_FW_VER_STR_LEN);
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED,
			      DEVLINK_INFO_VERSION_GENERIC_FW, buf);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set roce firmware version");
		return rc;
	}

	snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
		 nvm_dev_info.hwrm_fw_major, nvm_dev_info.hwrm_fw_minor,
		 nvm_dev_info.hwrm_fw_build, nvm_dev_info.hwrm_fw_patch);
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED,
			      DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set stored firmware version");
		return rc;
	}

	snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
		 nvm_dev_info.mgmt_fw_major, nvm_dev_info.mgmt_fw_minor,
		 nvm_dev_info.mgmt_fw_build, nvm_dev_info.mgmt_fw_patch);
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED,
			      DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver);
	if (rc) {
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set stored ncsi firmware version");
		return rc;
	}

	snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
		 nvm_dev_info.roce_fw_major, nvm_dev_info.roce_fw_minor,
		 nvm_dev_info.roce_fw_build, nvm_dev_info.roce_fw_patch);
	rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED,
			      DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
	if (rc)
		NL_SET_ERR_MSG_MOD(extack,
				   "Failed to set stored roce firmware version");

	return rc;
}

@@ -140,3 +292,15 @@ struct bnge_dev *bnge_devlink_alloc(struct pci_dev *pdev)

	return bd;
}

void bnge_devlink_register(struct bnge_dev *bd)
{
	struct devlink *devlink = priv_to_devlink(bd);
	devlink_register(devlink);
}

void bnge_devlink_unregister(struct bnge_dev *bd)
{
	struct devlink *devlink = priv_to_devlink(bd);
	devlink_unregister(devlink);
}
+2 −0
Original line number Diff line number Diff line
@@ -12,5 +12,7 @@ enum bnge_dl_version_type {

void bnge_devlink_free(struct bnge_dev *bd);
struct bnge_dev *bnge_devlink_alloc(struct pci_dev *pdev);
void bnge_devlink_register(struct bnge_dev *bd);
void bnge_devlink_unregister(struct bnge_dev *bd);

#endif /* _BNGE_DEVLINK_H_ */
Loading