brintos

brintos / linux-shallow public Read only

0
0
Text · 15.2 KiB · f5128db Raw
532 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/****************************************************************************3 * Driver for Solarflare network controllers and boards4 * Copyright 2011-2013 Solarflare Communications Inc.5 */6 7#include <linux/bitops.h>8#include <linux/slab.h>9#include <linux/hwmon.h>10#include <linux/stat.h>11 12#include "net_driver.h"13#include "mcdi.h"14#include "mcdi_pcol.h"15#include "nic.h"16 17enum efx_hwmon_type {18	EFX_HWMON_UNKNOWN,19	EFX_HWMON_TEMP,         /* temperature */20	EFX_HWMON_COOL,         /* cooling device, probably a heatsink */21	EFX_HWMON_IN,		/* voltage */22	EFX_HWMON_CURR,		/* current */23	EFX_HWMON_POWER,	/* power */24	EFX_HWMON_TYPES_COUNT25};26 27static const char *const efx_hwmon_unit[EFX_HWMON_TYPES_COUNT] = {28	[EFX_HWMON_TEMP]  = " degC",29	[EFX_HWMON_COOL]  = " rpm", /* though nonsense for a heatsink */30	[EFX_HWMON_IN]    = " mV",31	[EFX_HWMON_CURR]  = " mA",32	[EFX_HWMON_POWER] = " W",33};34 35static const struct {36	const char *label;37	enum efx_hwmon_type hwmon_type;38	int port;39} efx_mcdi_sensor_type[] = {40#define SENSOR(name, label, hwmon_type, port)				\41	[MC_CMD_SENSOR_##name] = { label, EFX_HWMON_ ## hwmon_type, port }42	SENSOR(CONTROLLER_TEMP,		"Controller board temp.",   TEMP,  -1),43	SENSOR(PHY_COMMON_TEMP,		"PHY temp.",		    TEMP,  -1),44	SENSOR(CONTROLLER_COOLING,	"Controller heat sink",	    COOL,  -1),45	SENSOR(PHY0_TEMP,		"PHY temp.",		    TEMP,  0),46	SENSOR(PHY0_COOLING,		"PHY heat sink",	    COOL,  0),47	SENSOR(PHY1_TEMP,		"PHY temp.",		    TEMP,  1),48	SENSOR(PHY1_COOLING,		"PHY heat sink",	    COOL,  1),49	SENSOR(IN_1V0,			"1.0V supply",		    IN,    -1),50	SENSOR(IN_1V2,			"1.2V supply",		    IN,    -1),51	SENSOR(IN_1V8,			"1.8V supply",		    IN,    -1),52	SENSOR(IN_2V5,			"2.5V supply",		    IN,    -1),53	SENSOR(IN_3V3,			"3.3V supply",		    IN,    -1),54	SENSOR(IN_12V0,			"12.0V supply",		    IN,    -1),55	SENSOR(IN_1V2A,			"1.2V analogue supply",	    IN,    -1),56	SENSOR(IN_VREF,			"Ref. voltage",		    IN,    -1),57	SENSOR(OUT_VAOE,		"AOE FPGA supply",	    IN,    -1),58	SENSOR(AOE_TEMP,		"AOE FPGA temp.",	    TEMP,  -1),59	SENSOR(PSU_AOE_TEMP,		"AOE regulator temp.",	    TEMP,  -1),60	SENSOR(PSU_TEMP,		"Controller regulator temp.",61								    TEMP,  -1),62	SENSOR(FAN_0,			"Fan 0",		    COOL,  -1),63	SENSOR(FAN_1,			"Fan 1",		    COOL,  -1),64	SENSOR(FAN_2,			"Fan 2",		    COOL,  -1),65	SENSOR(FAN_3,			"Fan 3",		    COOL,  -1),66	SENSOR(FAN_4,			"Fan 4",		    COOL,  -1),67	SENSOR(IN_VAOE,			"AOE input supply",	    IN,    -1),68	SENSOR(OUT_IAOE,		"AOE output current",	    CURR,  -1),69	SENSOR(IN_IAOE,			"AOE input current",	    CURR,  -1),70	SENSOR(NIC_POWER,		"Board power use",	    POWER, -1),71	SENSOR(IN_0V9,			"0.9V supply",		    IN,    -1),72	SENSOR(IN_I0V9,			"0.9V supply current",	    CURR,  -1),73	SENSOR(IN_I1V2,			"1.2V supply current",	    CURR,  -1),74	SENSOR(IN_0V9_ADC,		"0.9V supply (ext. ADC)",   IN,    -1),75	SENSOR(CONTROLLER_2_TEMP,	"Controller board temp. 2", TEMP,  -1),76	SENSOR(VREG_INTERNAL_TEMP,	"Regulator die temp.",	    TEMP,  -1),77	SENSOR(VREG_0V9_TEMP,		"0.9V regulator temp.",     TEMP,  -1),78	SENSOR(VREG_1V2_TEMP,		"1.2V regulator temp.",     TEMP,  -1),79	SENSOR(CONTROLLER_VPTAT,80			      "Controller PTAT voltage (int. ADC)", IN,    -1),81	SENSOR(CONTROLLER_INTERNAL_TEMP,82				 "Controller die temp. (int. ADC)", TEMP,  -1),83	SENSOR(CONTROLLER_VPTAT_EXTADC,84			      "Controller PTAT voltage (ext. ADC)", IN,    -1),85	SENSOR(CONTROLLER_INTERNAL_TEMP_EXTADC,86				 "Controller die temp. (ext. ADC)", TEMP,  -1),87	SENSOR(AMBIENT_TEMP,		"Ambient temp.",	    TEMP,  -1),88	SENSOR(AIRFLOW,			"Air flow raw",		    IN,    -1),89	SENSOR(VDD08D_VSS08D_CSR,	"0.9V die (int. ADC)",	    IN,    -1),90	SENSOR(VDD08D_VSS08D_CSR_EXTADC, "0.9V die (ext. ADC)",	    IN,    -1),91	SENSOR(HOTPOINT_TEMP,  "Controller board temp. (hotpoint)", TEMP,  -1),92#undef SENSOR93};94 95static const char *const sensor_status_names[] = {96	[MC_CMD_SENSOR_STATE_OK] = "OK",97	[MC_CMD_SENSOR_STATE_WARNING] = "Warning",98	[MC_CMD_SENSOR_STATE_FATAL] = "Fatal",99	[MC_CMD_SENSOR_STATE_BROKEN] = "Device failure",100	[MC_CMD_SENSOR_STATE_NO_READING] = "No reading",101};102 103void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)104{105	unsigned int type, state, value;106	enum efx_hwmon_type hwmon_type = EFX_HWMON_UNKNOWN;107	const char *name = NULL, *state_txt, *unit;108 109	type = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);110	state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);111	value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE);112 113	/* Deal gracefully with the board having more drivers than we114	 * know about, but do not expect new sensor states. */115	if (type < ARRAY_SIZE(efx_mcdi_sensor_type)) {116		name = efx_mcdi_sensor_type[type].label;117		hwmon_type = efx_mcdi_sensor_type[type].hwmon_type;118	}119	if (!name)120		name = "No sensor name available";121	EFX_WARN_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));122	state_txt = sensor_status_names[state];123	EFX_WARN_ON_PARANOID(hwmon_type >= EFX_HWMON_TYPES_COUNT);124	unit = efx_hwmon_unit[hwmon_type];125	if (!unit)126		unit = "";127 128	netif_err(efx, hw, efx->net_dev,129		  "Sensor %d (%s) reports condition '%s' for value %d%s\n",130		  type, name, state_txt, value, unit);131}132 133#ifdef CONFIG_SFC_MCDI_MON134 135struct efx_mcdi_mon_attribute {136	struct device_attribute dev_attr;137	unsigned int index;138	unsigned int type;139	enum efx_hwmon_type hwmon_type;140	unsigned int limit_value;141	char name[12];142};143 144static int efx_mcdi_mon_update(struct efx_nic *efx)145{146	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);147	MCDI_DECLARE_BUF(inbuf, MC_CMD_READ_SENSORS_EXT_IN_LEN);148	int rc;149 150	MCDI_SET_QWORD(inbuf, READ_SENSORS_EXT_IN_DMA_ADDR,151		       hwmon->dma_buf.dma_addr);152	MCDI_SET_DWORD(inbuf, READ_SENSORS_EXT_IN_LENGTH, hwmon->dma_buf.len);153 154	rc = efx_mcdi_rpc(efx, MC_CMD_READ_SENSORS,155			  inbuf, sizeof(inbuf), NULL, 0, NULL);156	if (rc == 0)157		hwmon->last_update = jiffies;158	return rc;159}160 161static int efx_mcdi_mon_get_entry(struct device *dev, unsigned int index,162				  efx_dword_t *entry)163{164	struct efx_nic *efx = dev_get_drvdata(dev->parent);165	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);166	int rc;167 168	BUILD_BUG_ON(MC_CMD_READ_SENSORS_OUT_LEN != 0);169 170	mutex_lock(&hwmon->update_lock);171 172	/* Use cached value if last update was < 1 s ago */173	if (time_before(jiffies, hwmon->last_update + HZ))174		rc = 0;175	else176		rc = efx_mcdi_mon_update(efx);177 178	/* Copy out the requested entry */179	*entry = ((efx_dword_t *)hwmon->dma_buf.addr)[index];180 181	mutex_unlock(&hwmon->update_lock);182 183	return rc;184}185 186static ssize_t efx_mcdi_mon_show_value(struct device *dev,187				       struct device_attribute *attr,188				       char *buf)189{190	struct efx_mcdi_mon_attribute *mon_attr =191		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);192	efx_dword_t entry;193	unsigned int value, state;194	int rc;195 196	rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);197	if (rc)198		return rc;199 200	state = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);201	if (state == MC_CMD_SENSOR_STATE_NO_READING)202		return -EBUSY;203 204	value = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);205 206	switch (mon_attr->hwmon_type) {207	case EFX_HWMON_TEMP:208		/* Convert temperature from degrees to milli-degrees Celsius */209		value *= 1000;210		break;211	case EFX_HWMON_POWER:212		/* Convert power from watts to microwatts */213		value *= 1000000;214		break;215	default:216		/* No conversion needed */217		break;218	}219 220	return sprintf(buf, "%u\n", value);221}222 223static ssize_t efx_mcdi_mon_show_limit(struct device *dev,224				       struct device_attribute *attr,225				       char *buf)226{227	struct efx_mcdi_mon_attribute *mon_attr =228		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);229	unsigned int value;230 231	value = mon_attr->limit_value;232 233	switch (mon_attr->hwmon_type) {234	case EFX_HWMON_TEMP:235		/* Convert temperature from degrees to milli-degrees Celsius */236		value *= 1000;237		break;238	case EFX_HWMON_POWER:239		/* Convert power from watts to microwatts */240		value *= 1000000;241		break;242	default:243		/* No conversion needed */244		break;245	}246 247	return sprintf(buf, "%u\n", value);248}249 250static ssize_t efx_mcdi_mon_show_alarm(struct device *dev,251				       struct device_attribute *attr,252				       char *buf)253{254	struct efx_mcdi_mon_attribute *mon_attr =255		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);256	efx_dword_t entry;257	int state;258	int rc;259 260	rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);261	if (rc)262		return rc;263 264	state = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);265	return sprintf(buf, "%d\n", state != MC_CMD_SENSOR_STATE_OK);266}267 268static ssize_t efx_mcdi_mon_show_label(struct device *dev,269				       struct device_attribute *attr,270				       char *buf)271{272	struct efx_mcdi_mon_attribute *mon_attr =273		container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);274	return sprintf(buf, "%s\n",275		       efx_mcdi_sensor_type[mon_attr->type].label);276}277 278static void279efx_mcdi_mon_add_attr(struct efx_nic *efx, const char *name,280		      ssize_t (*reader)(struct device *,281					struct device_attribute *, char *),282		      unsigned int index, unsigned int type,283		      unsigned int limit_value)284{285	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);286	struct efx_mcdi_mon_attribute *attr = &hwmon->attrs[hwmon->n_attrs];287 288	strscpy(attr->name, name, sizeof(attr->name));289	attr->index = index;290	attr->type = type;291	if (type < ARRAY_SIZE(efx_mcdi_sensor_type))292		attr->hwmon_type = efx_mcdi_sensor_type[type].hwmon_type;293	else294		attr->hwmon_type = EFX_HWMON_UNKNOWN;295	attr->limit_value = limit_value;296	sysfs_attr_init(&attr->dev_attr.attr);297	attr->dev_attr.attr.name = attr->name;298	attr->dev_attr.attr.mode = 0444;299	attr->dev_attr.show = reader;300	hwmon->group.attrs[hwmon->n_attrs++] = &attr->dev_attr.attr;301}302 303int efx_mcdi_mon_probe(struct efx_nic *efx)304{305	unsigned int n_temp = 0, n_cool = 0, n_in = 0, n_curr = 0, n_power = 0;306	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);307	MCDI_DECLARE_BUF(inbuf, MC_CMD_SENSOR_INFO_EXT_IN_LEN);308	MCDI_DECLARE_BUF(outbuf, MC_CMD_SENSOR_INFO_OUT_LENMAX);309	unsigned int n_pages, n_sensors, n_attrs, page;310	size_t outlen;311	char name[12];312	u32 mask;313	int rc, i, j, type;314 315	/* Find out how many sensors are present */316	n_sensors = 0;317	page = 0;318	do {319		MCDI_SET_DWORD(inbuf, SENSOR_INFO_EXT_IN_PAGE, page);320 321		rc = efx_mcdi_rpc(efx, MC_CMD_SENSOR_INFO, inbuf, sizeof(inbuf),322				  outbuf, sizeof(outbuf), &outlen);323		if (rc)324			return rc;325		if (outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN)326			return -EIO;327 328		mask = MCDI_DWORD(outbuf, SENSOR_INFO_OUT_MASK);329		n_sensors += hweight32(mask & ~(1 << MC_CMD_SENSOR_PAGE0_NEXT));330		++page;331	} while (mask & (1 << MC_CMD_SENSOR_PAGE0_NEXT));332	n_pages = page;333 334	/* Don't create a device if there are none */335	if (n_sensors == 0)336		return 0;337 338	rc = efx_nic_alloc_buffer(339		efx, &hwmon->dma_buf,340		n_sensors * MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_LEN,341		GFP_KERNEL);342	if (rc)343		return rc;344 345	mutex_init(&hwmon->update_lock);346	efx_mcdi_mon_update(efx);347 348	/* Allocate space for the maximum possible number of349	 * attributes for this set of sensors:350	 * value, min, max, crit, alarm and label for each sensor.351	 */352	n_attrs = 6 * n_sensors;353	hwmon->attrs = kcalloc(n_attrs, sizeof(*hwmon->attrs), GFP_KERNEL);354	if (!hwmon->attrs) {355		rc = -ENOMEM;356		goto fail;357	}358	hwmon->group.attrs = kcalloc(n_attrs + 1, sizeof(struct attribute *),359				     GFP_KERNEL);360	if (!hwmon->group.attrs) {361		rc = -ENOMEM;362		goto fail;363	}364 365	for (i = 0, j = -1, type = -1; ; i++) {366		enum efx_hwmon_type hwmon_type;367		const char *hwmon_prefix;368		unsigned hwmon_index;369		u16 min1, max1, min2, max2;370 371		/* Find next sensor type or exit if there is none */372		do {373			type++;374 375			if ((type % 32) == 0) {376				page = type / 32;377				j = -1;378				if (page == n_pages)379					goto hwmon_register;380 381				MCDI_SET_DWORD(inbuf, SENSOR_INFO_EXT_IN_PAGE,382					       page);383				rc = efx_mcdi_rpc(efx, MC_CMD_SENSOR_INFO,384						  inbuf, sizeof(inbuf),385						  outbuf, sizeof(outbuf),386						  &outlen);387				if (rc)388					goto fail;389				if (outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN) {390					rc = -EIO;391					goto fail;392				}393 394				mask = (MCDI_DWORD(outbuf,395						   SENSOR_INFO_OUT_MASK) &396					~(1 << MC_CMD_SENSOR_PAGE0_NEXT));397 398				/* Check again for short response */399				if (outlen <400				    MC_CMD_SENSOR_INFO_OUT_LEN(hweight32(mask))) {401					rc = -EIO;402					goto fail;403				}404			}405		} while (!(mask & (1 << type % 32)));406		j++;407 408		if (type < ARRAY_SIZE(efx_mcdi_sensor_type)) {409			hwmon_type = efx_mcdi_sensor_type[type].hwmon_type;410 411			/* Skip sensors specific to a different port */412			if (hwmon_type != EFX_HWMON_UNKNOWN &&413			    efx_mcdi_sensor_type[type].port >= 0 &&414			    efx_mcdi_sensor_type[type].port !=415			    efx_port_num(efx))416				continue;417		} else {418			hwmon_type = EFX_HWMON_UNKNOWN;419		}420 421		switch (hwmon_type) {422		case EFX_HWMON_TEMP:423			hwmon_prefix = "temp";424			hwmon_index = ++n_temp; /* 1-based */425			break;426		case EFX_HWMON_COOL:427			/* This is likely to be a heatsink, but there428			 * is no convention for representing cooling429			 * devices other than fans.430			 */431			hwmon_prefix = "fan";432			hwmon_index = ++n_cool; /* 1-based */433			break;434		default:435			hwmon_prefix = "in";436			hwmon_index = n_in++; /* 0-based */437			break;438		case EFX_HWMON_CURR:439			hwmon_prefix = "curr";440			hwmon_index = ++n_curr; /* 1-based */441			break;442		case EFX_HWMON_POWER:443			hwmon_prefix = "power";444			hwmon_index = ++n_power; /* 1-based */445			break;446		}447 448		min1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,449					SENSOR_INFO_ENTRY, j, MIN1);450		max1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,451					SENSOR_INFO_ENTRY, j, MAX1);452		min2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,453					SENSOR_INFO_ENTRY, j, MIN2);454		max2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,455					SENSOR_INFO_ENTRY, j, MAX2);456 457		if (min1 != max1) {458			snprintf(name, sizeof(name), "%s%u_input",459				 hwmon_prefix, hwmon_index);460			efx_mcdi_mon_add_attr(461				efx, name, efx_mcdi_mon_show_value, i, type, 0);462 463			if (hwmon_type != EFX_HWMON_POWER) {464				snprintf(name, sizeof(name), "%s%u_min",465					 hwmon_prefix, hwmon_index);466				efx_mcdi_mon_add_attr(467					efx, name, efx_mcdi_mon_show_limit,468					i, type, min1);469			}470 471			snprintf(name, sizeof(name), "%s%u_max",472				 hwmon_prefix, hwmon_index);473			efx_mcdi_mon_add_attr(474				efx, name, efx_mcdi_mon_show_limit,475				i, type, max1);476 477			if (min2 != max2) {478				/* Assume max2 is critical value.479				 * But we have no good way to expose min2.480				 */481				snprintf(name, sizeof(name), "%s%u_crit",482					 hwmon_prefix, hwmon_index);483				efx_mcdi_mon_add_attr(484					efx, name, efx_mcdi_mon_show_limit,485					i, type, max2);486			}487		}488 489		snprintf(name, sizeof(name), "%s%u_alarm",490			 hwmon_prefix, hwmon_index);491		efx_mcdi_mon_add_attr(492			efx, name, efx_mcdi_mon_show_alarm, i, type, 0);493 494		if (type < ARRAY_SIZE(efx_mcdi_sensor_type) &&495		    efx_mcdi_sensor_type[type].label) {496			snprintf(name, sizeof(name), "%s%u_label",497				 hwmon_prefix, hwmon_index);498			efx_mcdi_mon_add_attr(499				efx, name, efx_mcdi_mon_show_label, i, type, 0);500		}501	}502 503hwmon_register:504	hwmon->groups[0] = &hwmon->group;505	hwmon->device = hwmon_device_register_with_groups(&efx->pci_dev->dev,506							  KBUILD_MODNAME, NULL,507							  hwmon->groups);508	if (IS_ERR(hwmon->device)) {509		rc = PTR_ERR(hwmon->device);510		goto fail;511	}512 513	return 0;514 515fail:516	efx_mcdi_mon_remove(efx);517	return rc;518}519 520void efx_mcdi_mon_remove(struct efx_nic *efx)521{522	struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);523 524	if (hwmon->device)525		hwmon_device_unregister(hwmon->device);526	kfree(hwmon->attrs);527	kfree(hwmon->group.attrs);528	efx_nic_free_buffer(efx, &hwmon->dma_buf);529}530 531#endif /* CONFIG_SFC_MCDI_MON */532