brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 669d24b Raw
242 lines · c
1/* Broadcom NetXtreme-C/E network driver.2 *3 * Copyright (c) 2023 Broadcom Limited4 *5 * This program is free software; you can redistribute it and/or modify6 * it under the terms of the GNU General Public License as published by7 * the Free Software Foundation.8 */9 10#include <linux/dev_printk.h>11#include <linux/errno.h>12#include <linux/hwmon.h>13#include <linux/hwmon-sysfs.h>14#include <linux/pci.h>15 16#include "bnxt_hsi.h"17#include "bnxt.h"18#include "bnxt_hwrm.h"19#include "bnxt_hwmon.h"20 21void bnxt_hwmon_notify_event(struct bnxt *bp)22{23	u32 attr;24 25	if (!bp->hwmon_dev)26		return;27 28	switch (bp->thermal_threshold_type) {29	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_WARN:30		attr = hwmon_temp_max_alarm;31		break;32	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_CRITICAL:33		attr = hwmon_temp_crit_alarm;34		break;35	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_FATAL:36	case ASYNC_EVENT_CMPL_ERROR_REPORT_THERMAL_EVENT_DATA1_THRESHOLD_TYPE_SHUTDOWN:37		attr = hwmon_temp_emergency_alarm;38		break;39	default:40		return;41	}42 43	hwmon_notify_event(&bp->pdev->dev, hwmon_temp, attr, 0);44}45 46static int bnxt_hwrm_temp_query(struct bnxt *bp, u8 *temp)47{48	struct hwrm_temp_monitor_query_output *resp;49	struct hwrm_temp_monitor_query_input *req;50	int rc;51 52	rc = hwrm_req_init(bp, req, HWRM_TEMP_MONITOR_QUERY);53	if (rc)54		return rc;55	resp = hwrm_req_hold(bp, req);56	rc = hwrm_req_send_silent(bp, req);57	if (rc)58		goto drop_req;59 60	if (temp) {61		*temp = resp->temp;62	} else if (resp->flags &63		   TEMP_MONITOR_QUERY_RESP_FLAGS_THRESHOLD_VALUES_AVAILABLE) {64		bp->fw_cap |= BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED;65		bp->warn_thresh_temp = resp->warn_threshold;66		bp->crit_thresh_temp = resp->critical_threshold;67		bp->fatal_thresh_temp = resp->fatal_threshold;68		bp->shutdown_thresh_temp = resp->shutdown_threshold;69	}70drop_req:71	hwrm_req_drop(bp, req);72	return rc;73}74 75static umode_t bnxt_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type,76				     u32 attr, int channel)77{78	const struct bnxt *bp = _data;79 80	if (type != hwmon_temp)81		return 0;82 83	switch (attr) {84	case hwmon_temp_input:85		return 0444;86	case hwmon_temp_max:87	case hwmon_temp_crit:88	case hwmon_temp_emergency:89	case hwmon_temp_max_alarm:90	case hwmon_temp_crit_alarm:91	case hwmon_temp_emergency_alarm:92		if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED))93			return 0;94		return 0444;95	default:96		return 0;97	}98}99 100static int bnxt_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,101			   int channel, long *val)102{103	struct bnxt *bp = dev_get_drvdata(dev);104	u8 temp = 0;105	int rc;106 107	switch (attr) {108	case hwmon_temp_input:109		rc = bnxt_hwrm_temp_query(bp, &temp);110		if (!rc)111			*val = temp * 1000;112		return rc;113	case hwmon_temp_max:114		*val = bp->warn_thresh_temp * 1000;115		return 0;116	case hwmon_temp_crit:117		*val = bp->crit_thresh_temp * 1000;118		return 0;119	case hwmon_temp_emergency:120		*val = bp->fatal_thresh_temp * 1000;121		return 0;122	case hwmon_temp_max_alarm:123		rc = bnxt_hwrm_temp_query(bp, &temp);124		if (!rc)125			*val = temp >= bp->warn_thresh_temp;126		return rc;127	case hwmon_temp_crit_alarm:128		rc = bnxt_hwrm_temp_query(bp, &temp);129		if (!rc)130			*val = temp >= bp->crit_thresh_temp;131		return rc;132	case hwmon_temp_emergency_alarm:133		rc = bnxt_hwrm_temp_query(bp, &temp);134		if (!rc)135			*val = temp >= bp->fatal_thresh_temp;136		return rc;137	default:138		return -EOPNOTSUPP;139	}140}141 142static const struct hwmon_channel_info *bnxt_hwmon_info[] = {143	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |144			   HWMON_T_EMERGENCY | HWMON_T_MAX_ALARM |145			   HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM),146	NULL147};148 149static const struct hwmon_ops bnxt_hwmon_ops = {150	.is_visible     = bnxt_hwmon_is_visible,151	.read           = bnxt_hwmon_read,152};153 154static const struct hwmon_chip_info bnxt_hwmon_chip_info = {155	.ops    = &bnxt_hwmon_ops,156	.info   = bnxt_hwmon_info,157};158 159static ssize_t temp1_shutdown_show(struct device *dev,160				   struct device_attribute *attr, char *buf)161{162	struct bnxt *bp = dev_get_drvdata(dev);163 164	return sysfs_emit(buf, "%u\n", bp->shutdown_thresh_temp * 1000);165}166 167static ssize_t temp1_shutdown_alarm_show(struct device *dev,168					 struct device_attribute *attr, char *buf)169{170	struct bnxt *bp = dev_get_drvdata(dev);171	u8 temp;172	int rc;173 174	rc = bnxt_hwrm_temp_query(bp, &temp);175	if (rc)176		return -EIO;177 178	return sysfs_emit(buf, "%u\n", temp >= bp->shutdown_thresh_temp);179}180 181static DEVICE_ATTR_RO(temp1_shutdown);182static DEVICE_ATTR_RO(temp1_shutdown_alarm);183 184static struct attribute *bnxt_temp_extra_attrs[] = {185	&dev_attr_temp1_shutdown.attr,186	&dev_attr_temp1_shutdown_alarm.attr,187	NULL,188};189 190static umode_t bnxt_temp_extra_attrs_visible(struct kobject *kobj,191					     struct attribute *attr, int index)192{193	struct device *dev = kobj_to_dev(kobj);194	struct bnxt *bp = dev_get_drvdata(dev);195 196	/* Shutdown temperature setting in NVM is optional */197	if (!(bp->fw_cap & BNXT_FW_CAP_THRESHOLD_TEMP_SUPPORTED) ||198	    !bp->shutdown_thresh_temp)199		return 0;200 201	return attr->mode;202}203 204static const struct attribute_group bnxt_temp_extra_group = {205	.attrs		= bnxt_temp_extra_attrs,206	.is_visible	= bnxt_temp_extra_attrs_visible,207};208__ATTRIBUTE_GROUPS(bnxt_temp_extra);209 210void bnxt_hwmon_uninit(struct bnxt *bp)211{212	if (bp->hwmon_dev) {213		hwmon_device_unregister(bp->hwmon_dev);214		bp->hwmon_dev = NULL;215	}216}217 218void bnxt_hwmon_init(struct bnxt *bp)219{220	struct pci_dev *pdev = bp->pdev;221	int rc;222 223	/* temp1_xxx is only sensor, ensure not registered if it will fail */224	rc = bnxt_hwrm_temp_query(bp, NULL);225	if (rc == -EACCES || rc == -EOPNOTSUPP) {226		bnxt_hwmon_uninit(bp);227		return;228	}229 230	if (bp->hwmon_dev)231		return;232 233	bp->hwmon_dev = hwmon_device_register_with_info(&pdev->dev,234							DRV_MODULE_NAME, bp,235							&bnxt_hwmon_chip_info,236							bnxt_temp_extra_groups);237	if (IS_ERR(bp->hwmon_dev)) {238		bp->hwmon_dev = NULL;239		dev_warn(&pdev->dev, "Cannot register hwmon device\n");240	}241}242