Commit 20767b23 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bnxt_en-hwmon-SRIOV'

Michael Chan says:

====================
bnxt_en: hwmon and SRIOV updates

The first 7 patches are v2 of the hwmon patches posted about 6 weeks ago
on Aug 14.  The last 2 patches are SRIOV related updates.

Link to v1 hwmon patches:
https://lore.kernel.org/netdev/20230815045658.80494-11-michael.chan@broadcom.com/


====================

Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 20f7cce7 cbdbf0aa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4,3 +4,4 @@ obj-$(CONFIG_BNXT) += bnxt_en.o
bnxt_en-y := bnxt.o bnxt_hwrm.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o bnxt_coredump.o
bnxt_en-$(CONFIG_BNXT_FLOWER_OFFLOAD) += bnxt_tc.o
bnxt_en-$(CONFIG_DEBUG_FS) += bnxt_debugfs.o
bnxt_en-$(CONFIG_BNXT_HWMON) += bnxt_hwmon.o
+75 −77
Original line number Diff line number Diff line
@@ -52,8 +52,6 @@
#include <linux/cpu_rmap.h>
#include <linux/cpumask.h>
#include <net/pkt_cls.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <net/page_pool/helpers.h>
#include <linux/align.h>
#include <net/netdev_queues.h>
@@ -71,6 +69,7 @@
#include "bnxt_tc.h"
#include "bnxt_devlink.h"
#include "bnxt_debugfs.h"
#include "bnxt_hwmon.h"

#define BNXT_TX_TIMEOUT		(5 * HZ)
#define BNXT_DEF_MSG_ENABLE	(NETIF_MSG_DRV | NETIF_MSG_HW | \
@@ -2130,6 +2129,24 @@ static u16 bnxt_agg_ring_id_to_grp_idx(struct bnxt *bp, u16 ring_id)
	return INVALID_HW_RING_ID;
}

#define BNXT_EVENT_THERMAL_CURRENT_TEMP(data2)				\
	((data2) &							\
	  ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA2_CURRENT_TEMP_MASK)

#define BNXT_EVENT_THERMAL_THRESHOLD_TEMP(data2)			\
	(((data2) &							\
	  ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA2_THRESHOLD_TEMP_MASK) >>\
	 ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA2_THRESHOLD_TEMP_SFT)

#define EVENT_DATA1_THERMAL_THRESHOLD_TYPE(data1)			\
	((data1) &							\
	 ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_MASK)

#define EVENT_DATA1_THERMAL_THRESHOLD_DIR_INCREASING(data1)		\
	(((data1) &							\
	  ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_TRANSITION_DIR) ==\
	 ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_TRANSITION_DIR_INCREASING)

static void bnxt_event_error_report(struct bnxt *bp, u32 data1, u32 data2)
{
	u32 err_type = BNXT_EVENT_ERROR_REPORT_TYPE(data1);
@@ -2145,6 +2162,40 @@ static void bnxt_event_error_report(struct bnxt *bp, u32 data1, u32 data2)
	case ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_DOORBELL_DROP_THRESHOLD:
		netdev_warn(bp->dev, "One or more MMIO doorbells dropped by the device!\n");
		break;
	case ASYNC_EVENT_CMPL_ERROR_REPORT_BASE_EVENT_DATA1_ERROR_TYPE_THERMAL_THRESHOLD: {
		u32 type = EVENT_DATA1_THERMAL_THRESHOLD_TYPE(data1);
		char *threshold_type;
		char *dir_str;

		switch (type) {
		case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_WARN:
			threshold_type = "warning";
			break;
		case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_CRITICAL:
			threshold_type = "critical";
			break;
		case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_FATAL:
			threshold_type = "fatal";
			break;
		case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_SHUTDOWN:
			threshold_type = "shutdown";
			break;
		default:
			netdev_err(bp->dev, "Unknown Thermal threshold type event\n");
			return;
		}
		if (EVENT_DATA1_THERMAL_THRESHOLD_DIR_INCREASING(data1))
			dir_str = "above";
		else
			dir_str = "below";
		netdev_warn(bp->dev, "Chip temperature has gone %s the %s thermal threshold!\n",
			    dir_str, threshold_type);
		netdev_warn(bp->dev, "Temperature (In Celsius), Current: %lu, threshold: %lu\n",
			    BNXT_EVENT_THERMAL_CURRENT_TEMP(data2),
			    BNXT_EVENT_THERMAL_THRESHOLD_TEMP(data2));
		bnxt_hwmon_notify_event(bp, type);
		break;
	}
	default:
		netdev_err(bp->dev, "FW reported unknown error type %u\n",
			   err_type);
@@ -7699,6 +7750,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
		bp->fw_cap |= BNXT_FW_CAP_HOT_RESET_IF;
	if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_FW_LIVEPATCH_SUPPORTED))
		bp->fw_cap |= BNXT_FW_CAP_LIVEPATCH;
	if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_DFLT_VLAN_TPID_PCP_SUPPORTED))
		bp->fw_cap |= BNXT_FW_CAP_DFLT_VLAN_TPID_PCP;

	flags_ext2 = le32_to_cpu(resp->flags_ext2);
	if (flags_ext2 & FUNC_QCAPS_RESP_FLAGS_EXT2_RX_ALL_PKTS_TIMESTAMPS_SUPPORTED)
@@ -10250,79 +10303,6 @@ static void bnxt_get_wol_settings(struct bnxt *bp)
	} while (handle && handle != 0xffff);
}

#ifdef CONFIG_BNXT_HWMON
static ssize_t bnxt_show_temp(struct device *dev,
			      struct device_attribute *devattr, char *buf)
{
	struct hwrm_temp_monitor_query_output *resp;
	struct hwrm_temp_monitor_query_input *req;
	struct bnxt *bp = dev_get_drvdata(dev);
	u32 len = 0;
	int rc;

	rc = hwrm_req_init(bp, req, HWRM_TEMP_MONITOR_QUERY);
	if (rc)
		return rc;
	resp = hwrm_req_hold(bp, req);
	rc = hwrm_req_send(bp, req);
	if (!rc)
		len = sprintf(buf, "%u\n", resp->temp * 1000); /* display millidegree */
	hwrm_req_drop(bp, req);
	if (rc)
		return rc;
	return len;
}
static SENSOR_DEVICE_ATTR(temp1_input, 0444, bnxt_show_temp, NULL, 0);

static struct attribute *bnxt_attrs[] = {
	&sensor_dev_attr_temp1_input.dev_attr.attr,
	NULL
};
ATTRIBUTE_GROUPS(bnxt);

static void bnxt_hwmon_close(struct bnxt *bp)
{
	if (bp->hwmon_dev) {
		hwmon_device_unregister(bp->hwmon_dev);
		bp->hwmon_dev = NULL;
	}
}

static void bnxt_hwmon_open(struct bnxt *bp)
{
	struct hwrm_temp_monitor_query_input *req;
	struct pci_dev *pdev = bp->pdev;
	int rc;

	rc = hwrm_req_init(bp, req, HWRM_TEMP_MONITOR_QUERY);
	if (!rc)
		rc = hwrm_req_send_silent(bp, req);
	if (rc == -EACCES || rc == -EOPNOTSUPP) {
		bnxt_hwmon_close(bp);
		return;
	}

	if (bp->hwmon_dev)
		return;

	bp->hwmon_dev = hwmon_device_register_with_groups(&pdev->dev,
							  DRV_MODULE_NAME, bp,
							  bnxt_groups);
	if (IS_ERR(bp->hwmon_dev)) {
		bp->hwmon_dev = NULL;
		dev_warn(&pdev->dev, "Cannot register hwmon device\n");
	}
}
#else
static void bnxt_hwmon_close(struct bnxt *bp)
{
}

static void bnxt_hwmon_open(struct bnxt *bp)
{
}
#endif

static bool bnxt_eee_config_ok(struct bnxt *bp)
{
	struct ethtool_eee *eee = &bp->eee;
@@ -10651,7 +10631,6 @@ static int bnxt_open(struct net_device *dev)
				bnxt_reenable_sriov(bp);
			}
		}
		bnxt_hwmon_open(bp);
	}

	return rc;
@@ -10736,7 +10715,6 @@ static int bnxt_close(struct net_device *dev)
{
	struct bnxt *bp = netdev_priv(dev);

	bnxt_hwmon_close(bp);
	bnxt_close_nic(bp, true, true);
	bnxt_hwrm_shutdown_link(bp);
	bnxt_hwrm_if_change(bp, false);
@@ -12237,6 +12215,20 @@ static void bnxt_init_dflt_coal(struct bnxt *bp)
	bp->stats_coal_ticks = BNXT_DEF_STATS_COAL_TICKS;
}

/* FW that pre-reserves 1 VNIC per function */
static bool bnxt_fw_pre_resv_vnics(struct bnxt *bp)
{
	u16 fw_maj = BNXT_FW_MAJ(bp), fw_bld = BNXT_FW_BLD(bp);

	if (!(bp->flags & BNXT_FLAG_CHIP_P5) &&
	    (fw_maj > 218 || (fw_maj == 218 && fw_bld >= 18)))
		return true;
	if ((bp->flags & BNXT_FLAG_CHIP_P5) &&
	    (fw_maj > 216 || (fw_maj == 216 && fw_bld >= 172)))
		return true;
	return false;
}

static int bnxt_fw_init_one_p1(struct bnxt *bp)
{
	int rc;
@@ -12293,6 +12285,9 @@ static int bnxt_fw_init_one_p2(struct bnxt *bp)
	if (rc)
		return -ENODEV;

	if (bnxt_fw_pre_resv_vnics(bp))
		bp->fw_cap |= BNXT_FW_CAP_PRE_RESV_VNICS;

	bnxt_hwrm_func_qcfg(bp);
	bnxt_hwrm_vnic_qcaps(bp);
	bnxt_hwrm_port_led_qcaps(bp);
@@ -12300,6 +12295,7 @@ static int bnxt_fw_init_one_p2(struct bnxt *bp)
	if (bp->fw_cap & BNXT_FW_CAP_PTP)
		__bnxt_hwrm_ptp_qcfg(bp);
	bnxt_dcb_init(bp);
	bnxt_hwmon_init(bp);
	return 0;
}

@@ -13205,6 +13201,7 @@ static void bnxt_remove_one(struct pci_dev *pdev)
	bnxt_clear_int_mode(bp);
	bnxt_hwrm_func_drv_unrgtr(bp);
	bnxt_free_hwrm_resources(bp);
	bnxt_hwmon_uninit(bp);
	bnxt_ethtool_free(bp);
	bnxt_dcb_free(bp);
	kfree(bp->ptp_cfg);
@@ -13801,6 +13798,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
init_err_pci_clean:
	bnxt_hwrm_func_drv_unrgtr(bp);
	bnxt_free_hwrm_resources(bp);
	bnxt_hwmon_uninit(bp);
	bnxt_ethtool_free(bp);
	bnxt_ptp_clear(bp);
	kfree(bp->ptp_cfg);
+10 −1
Original line number Diff line number Diff line
@@ -1135,7 +1135,6 @@ struct bnxt_vf_info {
	u16	vlan;
	u16	func_qcfg_flags;
	u32	flags;
#define BNXT_VF_QOS		0x1
#define BNXT_VF_SPOOFCHK	0x2
#define BNXT_VF_LINK_FORCED	0x4
#define BNXT_VF_LINK_UP		0x8
@@ -2013,6 +2012,9 @@ struct bnxt {
	#define BNXT_FW_CAP_RING_MONITOR		BIT_ULL(30)
	#define BNXT_FW_CAP_DBG_QCAPS			BIT_ULL(31)
	#define BNXT_FW_CAP_PTP				BIT_ULL(32)
	#define BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED	BIT_ULL(33)
	#define BNXT_FW_CAP_DFLT_VLAN_TPID_PCP		BIT_ULL(34)
	#define BNXT_FW_CAP_PRE_RESV_VNICS		BIT_ULL(35)

	u32			fw_dbg_cap;

@@ -2053,6 +2055,7 @@ struct bnxt {
#define BNXT_FW_VER_CODE(maj, min, bld, rsv)			\
	((u64)(maj) << 48 | (u64)(min) << 32 | (u64)(bld) << 16 | (rsv))
#define BNXT_FW_MAJ(bp)		((bp)->fw_ver_code >> 48)
#define BNXT_FW_BLD(bp)		(((bp)->fw_ver_code >> 16) & 0xffff)

	u16			vxlan_fw_dst_port_id;
	u16			nge_fw_dst_port_id;
@@ -2185,7 +2188,13 @@ struct bnxt {
	struct bnxt_tc_info	*tc_info;
	struct list_head	tc_indr_block_list;
	struct dentry		*debugfs_pdev;
#ifdef CONFIG_BNXT_HWMON
	struct device		*hwmon_dev;
	u8			warn_thresh_temp;
	u8			crit_thresh_temp;
	u8			fatal_thresh_temp;
	u8			shutdown_thresh_temp;
#endif
	enum board_idx		board_idx;
};

+367 −178

File changed.

Preview size limit exceeded, changes collapsed.

+241 −0
Original line number Diff line number Diff line
/* Broadcom NetXtreme-C/E network driver.
 *
 * Copyright (c) 2023 Broadcom Limited
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 */

#include <linux/dev_printk.h>
#include <linux/errno.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/pci.h>

#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_hwrm.h"
#include "bnxt_hwmon.h"

void bnxt_hwmon_notify_event(struct bnxt *bp, u32 type)
{
	u32 attr;

	if (!bp->hwmon_dev)
		return;

	switch (type) {
	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_WARN:
		attr = hwmon_temp_max_alarm;
		break;
	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_CRITICAL:
		attr = hwmon_temp_crit_alarm;
		break;
	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_FATAL:
	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_SHUTDOWN:
		attr = hwmon_temp_emergency_alarm;
		break;
	default:
		return;
	}

	hwmon_notify_event(&bp->pdev->dev, hwmon_temp, attr, 0);
}

static int bnxt_hwrm_temp_query(struct bnxt *bp, u8 *temp)
{
	struct hwrm_temp_monitor_query_output *resp;
	struct hwrm_temp_monitor_query_input *req;
	int rc;

	rc = hwrm_req_init(bp, req, HWRM_TEMP_MONITOR_QUERY);
	if (rc)
		return rc;
	resp = hwrm_req_hold(bp, req);
	rc = hwrm_req_send_silent(bp, req);
	if (rc)
		goto drop_req;

	if (temp) {
		*temp = resp->temp;
	} else if (resp->flags &
		   TEMP_MONITOR_QUERY_RESP_FLAGS_THRESHOLD_VALUES_AVAILABLE) {
		bp->fw_cap |= BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED;
		bp->warn_thresh_temp = resp->warn_threshold;
		bp->crit_thresh_temp = resp->critical_threshold;
		bp->fatal_thresh_temp = resp->fatal_threshold;
		bp->shutdown_thresh_temp = resp->shutdown_threshold;
	}
drop_req:
	hwrm_req_drop(bp, req);
	return rc;
}

static umode_t bnxt_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type,
				     u32 attr, int channel)
{
	const struct bnxt *bp = _data;

	if (type != hwmon_temp)
		return 0;

	switch (attr) {
	case hwmon_temp_input:
		return 0444;
	case hwmon_temp_max:
	case hwmon_temp_crit:
	case hwmon_temp_emergency:
	case hwmon_temp_max_alarm:
	case hwmon_temp_crit_alarm:
	case hwmon_temp_emergency_alarm:
		if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED))
			return 0;
		return 0444;
	default:
		return 0;
	}
}

static int bnxt_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
			   int channel, long *val)
{
	struct bnxt *bp = dev_get_drvdata(dev);
	u8 temp = 0;
	int rc;

	switch (attr) {
	case hwmon_temp_input:
		rc = bnxt_hwrm_temp_query(bp, &temp);
		if (!rc)
			*val = temp * 1000;
		return rc;
	case hwmon_temp_max:
		*val = bp->warn_thresh_temp * 1000;
		return 0;
	case hwmon_temp_crit:
		*val = bp->crit_thresh_temp * 1000;
		return 0;
	case hwmon_temp_emergency:
		*val = bp->fatal_thresh_temp * 1000;
		return 0;
	case hwmon_temp_max_alarm:
		rc = bnxt_hwrm_temp_query(bp, &temp);
		if (!rc)
			*val = temp >= bp->warn_thresh_temp;
		return rc;
	case hwmon_temp_crit_alarm:
		rc = bnxt_hwrm_temp_query(bp, &temp);
		if (!rc)
			*val = temp >= bp->crit_thresh_temp;
		return rc;
	case hwmon_temp_emergency_alarm:
		rc = bnxt_hwrm_temp_query(bp, &temp);
		if (!rc)
			*val = temp >= bp->fatal_thresh_temp;
		return rc;
	default:
		return -EOPNOTSUPP;
	}
}

static const struct hwmon_channel_info *bnxt_hwmon_info[] = {
	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
			   HWMON_T_EMERGENCY | HWMON_T_MAX_ALARM |
			   HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM),
	NULL
};

static const struct hwmon_ops bnxt_hwmon_ops = {
	.is_visible     = bnxt_hwmon_is_visible,
	.read           = bnxt_hwmon_read,
};

static const struct hwmon_chip_info bnxt_hwmon_chip_info = {
	.ops    = &bnxt_hwmon_ops,
	.info   = bnxt_hwmon_info,
};

static ssize_t temp1_shutdown_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct bnxt *bp = dev_get_drvdata(dev);

	return sysfs_emit(buf, "%u\n", bp->shutdown_thresh_temp * 1000);
}

static ssize_t temp1_shutdown_alarm_show(struct device *dev,
					 struct device_attribute *attr, char *buf)
{
	struct bnxt *bp = dev_get_drvdata(dev);
	u8 temp;
	int rc;

	rc = bnxt_hwrm_temp_query(bp, &temp);
	if (rc)
		return -EIO;

	return sysfs_emit(buf, "%u\n", temp >= bp->shutdown_thresh_temp);
}

static DEVICE_ATTR_RO(temp1_shutdown);
static DEVICE_ATTR_RO(temp1_shutdown_alarm);

static struct attribute *bnxt_temp_extra_attrs[] = {
	&dev_attr_temp1_shutdown.attr,
	&dev_attr_temp1_shutdown_alarm.attr,
	NULL,
};

static umode_t bnxt_temp_extra_attrs_visible(struct kobject *kobj,
					     struct attribute *attr, int index)
{
	struct device *dev = kobj_to_dev(kobj);
	struct bnxt *bp = dev_get_drvdata(dev);

	/* Shutdown temperature setting in NVM is optional */
	if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED) ||
	    !bp->shutdown_thresh_temp)
		return 0;

	return attr->mode;
}

static const struct attribute_group bnxt_temp_extra_group = {
	.attrs		= bnxt_temp_extra_attrs,
	.is_visible	= bnxt_temp_extra_attrs_visible,
};
__ATTRIBUTE_GROUPS(bnxt_temp_extra);

void bnxt_hwmon_uninit(struct bnxt *bp)
{
	if (bp->hwmon_dev) {
		hwmon_device_unregister(bp->hwmon_dev);
		bp->hwmon_dev = NULL;
	}
}

void bnxt_hwmon_init(struct bnxt *bp)
{
	struct pci_dev *pdev = bp->pdev;
	int rc;

	/* temp1_xxx is only sensor, ensure not registered if it will fail */
	rc = bnxt_hwrm_temp_query(bp, NULL);
	if (rc == -EACCES || rc == -EOPNOTSUPP) {
		bnxt_hwmon_uninit(bp);
		return;
	}

	if (bp->hwmon_dev)
		return;

	bp->hwmon_dev = hwmon_device_register_with_info(&pdev->dev,
							DRV_MODULE_NAME, bp,
							&bnxt_hwmon_chip_info,
							bnxt_temp_extra_groups);
	if (IS_ERR(bp->hwmon_dev)) {
		bp->hwmon_dev = NULL;
		dev_warn(&pdev->dev, "Cannot register hwmon device\n");
	}
}
Loading