aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2012-01-06 15:25:39 -0500
committerBen Hutchings <bhutchings@solarflare.com>2012-01-26 19:10:53 -0500
commit55c5e0f85dc550f03dc8a0b0097da6af3b4865c5 (patch)
treeb6f2087958e641be791136e79912f69656391225 /drivers
parent1646a6f352a6f70fcca828589ed04797aa09d494 (diff)
sfc: Add hwmon driver for boards using SFC9000-family controllers
The SFC9000-family controllers have firmware to manage all board peripherals including temperature, heat sink continuity and voltage sensors. The firmware reports sensor alarms, which we log, and will shut down the board if necessary. Some users may want to monitor their boards more closely, so add an hwmon driver that exposes all sensors reported by the firmware. Move efx_mcdi_sensor_event() into the new file so it can share the array of sensor labels with the hwmon driver. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/sfc/Kconfig7
-rw-r--r--drivers/net/ethernet/sfc/Makefile2
-rw-r--r--drivers/net/ethernet/sfc/mcdi.c43
-rw-r--r--drivers/net/ethernet/sfc/mcdi.h28
-rw-r--r--drivers/net/ethernet/sfc/mcdi_mon.c415
-rw-r--r--drivers/net/ethernet/sfc/nic.h14
-rw-r--r--drivers/net/ethernet/sfc/siena.c6
7 files changed, 471 insertions, 44 deletions
diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig
index 5d18841f0f3..ae40b666739 100644
--- a/drivers/net/ethernet/sfc/Kconfig
+++ b/drivers/net/ethernet/sfc/Kconfig
@@ -19,3 +19,10 @@ config SFC_MTD
19 This exposes the on-board flash memory as MTD devices (e.g. 19 This exposes the on-board flash memory as MTD devices (e.g.
20 /dev/mtd1). This makes it possible to upload new firmware 20 /dev/mtd1). This makes it possible to upload new firmware
21 to the NIC. 21 to the NIC.
22config SFC_MCDI_MON
23 bool "Solarflare SFC9000-family hwmon support"
24 depends on SFC && HWMON && !(SFC=y && HWMON=m)
25 default y
26 ----help---
27 This exposes the on-board firmware-managed sensors as a
28 hardware monitor device.
diff --git a/drivers/net/ethernet/sfc/Makefile b/drivers/net/ethernet/sfc/Makefile
index ab31c7124db..3fa2e25ccc4 100644
--- a/drivers/net/ethernet/sfc/Makefile
+++ b/drivers/net/ethernet/sfc/Makefile
@@ -2,7 +2,7 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \
2 falcon_xmac.o mcdi_mac.o \ 2 falcon_xmac.o mcdi_mac.o \
3 selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ 3 selftest.o ethtool.o qt202x_phy.o mdio_10g.o \
4 tenxpress.o txc43128_phy.o falcon_boards.o \ 4 tenxpress.o txc43128_phy.o falcon_boards.o \
5 mcdi.o mcdi_phy.o 5 mcdi.o mcdi_phy.o mcdi_mon.o
6sfc-$(CONFIG_SFC_MTD) += mtd.o 6sfc-$(CONFIG_SFC_MTD) += mtd.o
7 7
8obj-$(CONFIG_SFC) += sfc.o 8obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c
index f1cad22b30f..619f63a66ce 100644
--- a/drivers/net/ethernet/sfc/mcdi.c
+++ b/drivers/net/ethernet/sfc/mcdi.c
@@ -517,49 +517,6 @@ static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev)
517 efx_link_status_changed(efx); 517 efx_link_status_changed(efx);
518} 518}
519 519
520static const char *const sensor_names[] = {
521 [MC_CMD_SENSOR_CONTROLLER_TEMP] = "Controller temp. sensor",
522 [MC_CMD_SENSOR_PHY_COMMON_TEMP] = "PHY shared temp. sensor",
523 [MC_CMD_SENSOR_CONTROLLER_COOLING] = "Controller cooling",
524 [MC_CMD_SENSOR_PHY0_TEMP] = "PHY 0 temp. sensor",
525 [MC_CMD_SENSOR_PHY0_COOLING] = "PHY 0 cooling",
526 [MC_CMD_SENSOR_PHY1_TEMP] = "PHY 1 temp. sensor",
527 [MC_CMD_SENSOR_PHY1_COOLING] = "PHY 1 cooling",
528 [MC_CMD_SENSOR_IN_1V0] = "1.0V supply sensor",
529 [MC_CMD_SENSOR_IN_1V2] = "1.2V supply sensor",
530 [MC_CMD_SENSOR_IN_1V8] = "1.8V supply sensor",
531 [MC_CMD_SENSOR_IN_2V5] = "2.5V supply sensor",
532 [MC_CMD_SENSOR_IN_3V3] = "3.3V supply sensor",
533 [MC_CMD_SENSOR_IN_12V0] = "12V supply sensor"
534};
535
536static const char *const sensor_status_names[] = {
537 [MC_CMD_SENSOR_STATE_OK] = "OK",
538 [MC_CMD_SENSOR_STATE_WARNING] = "Warning",
539 [MC_CMD_SENSOR_STATE_FATAL] = "Fatal",
540 [MC_CMD_SENSOR_STATE_BROKEN] = "Device failure",
541};
542
543static void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
544{
545 unsigned int monitor, state, value;
546 const char *name, *state_txt;
547 monitor = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);
548 state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);
549 value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE);
550 /* Deal gracefully with the board having more drivers than we
551 * know about, but do not expect new sensor states. */
552 name = (monitor >= ARRAY_SIZE(sensor_names))
553 ? "No sensor name available" :
554 sensor_names[monitor];
555 EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
556 state_txt = sensor_status_names[state];
557
558 netif_err(efx, hw, efx->net_dev,
559 "Sensor %d (%s) reports condition '%s' for raw value %d\n",
560 monitor, name, state_txt, value);
561}
562
563/* Called from falcon_process_eventq for MCDI events */ 520/* Called from falcon_process_eventq for MCDI events */
564void efx_mcdi_process_event(struct efx_channel *channel, 521void efx_mcdi_process_event(struct efx_channel *channel,
565 efx_qword_t *event) 522 efx_qword_t *event)
diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h
index 4dd39fcca67..fbaa6efcd74 100644
--- a/drivers/net/ethernet/sfc/mcdi.h
+++ b/drivers/net/ethernet/sfc/mcdi.h
@@ -56,6 +56,15 @@ struct efx_mcdi_iface {
56 size_t resplen; 56 size_t resplen;
57}; 57};
58 58
59struct efx_mcdi_mon {
60 struct efx_buffer dma_buf;
61 struct mutex update_lock;
62 unsigned long last_update;
63 struct device *device;
64 struct efx_mcdi_mon_attribute *attrs;
65 unsigned int n_attrs;
66};
67
59extern void efx_mcdi_init(struct efx_nic *efx); 68extern void efx_mcdi_init(struct efx_nic *efx);
60 69
61extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, 70extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const u8 *inbuf,
@@ -68,6 +77,7 @@ extern void efx_mcdi_mode_event(struct efx_nic *efx);
68 77
69extern void efx_mcdi_process_event(struct efx_channel *channel, 78extern void efx_mcdi_process_event(struct efx_channel *channel,
70 efx_qword_t *event); 79 efx_qword_t *event);
80extern void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
71 81
72#define MCDI_PTR2(_buf, _ofst) \ 82#define MCDI_PTR2(_buf, _ofst) \
73 (((u8 *)_buf) + _ofst) 83 (((u8 *)_buf) + _ofst)
@@ -83,6 +93,10 @@ extern void efx_mcdi_process_event(struct efx_channel *channel,
83 93
84#define MCDI_PTR(_buf, _ofst) \ 94#define MCDI_PTR(_buf, _ofst) \
85 MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST) 95 MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST)
96#define MCDI_ARRAY_PTR(_buf, _field, _type, _index) \
97 MCDI_PTR2(_buf, \
98 MC_CMD_ ## _field ## _OFST + \
99 (_index) * MC_CMD_ ## _type ## _TYPEDEF_LEN)
86#define MCDI_SET_DWORD(_buf, _ofst, _value) \ 100#define MCDI_SET_DWORD(_buf, _ofst, _value) \
87 MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value) 101 MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value)
88#define MCDI_DWORD(_buf, _ofst) \ 102#define MCDI_DWORD(_buf, _ofst) \
@@ -92,6 +106,12 @@ extern void efx_mcdi_process_event(struct efx_channel *channel,
92 106
93#define MCDI_EVENT_FIELD(_ev, _field) \ 107#define MCDI_EVENT_FIELD(_ev, _field) \
94 EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field) 108 EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field)
109#define MCDI_ARRAY_FIELD(_buf, _field1, _type, _index, _field2) \
110 EFX_DWORD_FIELD( \
111 *((efx_dword_t *) \
112 (MCDI_ARRAY_PTR(_buf, _field1, _type, _index) + \
113 (MC_CMD_ ## _type ## _TYPEDEF_ ## _field2 ## _OFST & ~3))), \
114 MC_CMD_ ## _type ## _TYPEDEF_ ## _field2)
95 115
96extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len); 116extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len);
97extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, 117extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
@@ -131,4 +151,12 @@ extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
131extern int efx_mcdi_mac_reconfigure(struct efx_nic *efx); 151extern int efx_mcdi_mac_reconfigure(struct efx_nic *efx);
132extern bool efx_mcdi_mac_check_fault(struct efx_nic *efx); 152extern bool efx_mcdi_mac_check_fault(struct efx_nic *efx);
133 153
154#ifdef CONFIG_SFC_MCDI_MON
155extern int efx_mcdi_mon_probe(struct efx_nic *efx);
156extern void efx_mcdi_mon_remove(struct efx_nic *efx);
157#else
158static inline int efx_mcdi_mon_probe(struct efx_nic *efx) { return 0; }
159static inline void efx_mcdi_mon_remove(struct efx_nic *efx) {}
160#endif
161
134#endif /* EFX_MCDI_H */ 162#endif /* EFX_MCDI_H */
diff --git a/drivers/net/ethernet/sfc/mcdi_mon.c b/drivers/net/ethernet/sfc/mcdi_mon.c
new file mode 100644
index 00000000000..8a72c10b9a6
--- /dev/null
+++ b/drivers/net/ethernet/sfc/mcdi_mon.c
@@ -0,0 +1,415 @@
1/****************************************************************************
2 * Driver for Solarflare Solarstorm network controllers and boards
3 * Copyright 2011 Solarflare Communications Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published
7 * by the Free Software Foundation, incorporated herein by reference.
8 */
9
10#include <linux/bitops.h>
11#include <linux/slab.h>
12#include <linux/hwmon.h>
13#include <linux/stat.h>
14
15#include "net_driver.h"
16#include "mcdi.h"
17#include "mcdi_pcol.h"
18#include "nic.h"
19
20enum efx_hwmon_type {
21 EFX_HWMON_UNKNOWN,
22 EFX_HWMON_TEMP, /* temperature */
23 EFX_HWMON_COOL, /* cooling device, probably a heatsink */
24 EFX_HWMON_IN /* input voltage */
25};
26
27static const struct {
28 const char *label;
29 enum efx_hwmon_type hwmon_type;
30 int port;
31} efx_mcdi_sensor_type[MC_CMD_SENSOR_ENTRY_MAXNUM] = {
32#define SENSOR(name, label, hwmon_type, port) \
33 [MC_CMD_SENSOR_##name] = { label, hwmon_type, port }
34 SENSOR(CONTROLLER_TEMP, "Controller temp.", EFX_HWMON_TEMP, -1),
35 SENSOR(PHY_COMMON_TEMP, "PHY temp.", EFX_HWMON_TEMP, -1),
36 SENSOR(CONTROLLER_COOLING, "Controller cooling", EFX_HWMON_COOL, -1),
37 SENSOR(PHY0_TEMP, "PHY temp.", EFX_HWMON_TEMP, 0),
38 SENSOR(PHY0_COOLING, "PHY cooling", EFX_HWMON_COOL, 0),
39 SENSOR(PHY1_TEMP, "PHY temp.", EFX_HWMON_TEMP, 1),
40 SENSOR(PHY1_COOLING, "PHY cooling", EFX_HWMON_COOL, 1),
41 SENSOR(IN_1V0, "1.0V supply", EFX_HWMON_IN, -1),
42 SENSOR(IN_1V2, "1.2V supply", EFX_HWMON_IN, -1),
43 SENSOR(IN_1V8, "1.8V supply", EFX_HWMON_IN, -1),
44 SENSOR(IN_2V5, "2.5V supply", EFX_HWMON_IN, -1),
45 SENSOR(IN_3V3, "3.3V supply", EFX_HWMON_IN, -1),
46 SENSOR(IN_12V0, "12.0V supply", EFX_HWMON_IN, -1),
47 SENSOR(IN_1V2A, "1.2V analogue supply", EFX_HWMON_IN, -1),
48 SENSOR(IN_VREF, "ref. voltage", EFX_HWMON_IN, -1),
49#undef SENSOR
50};
51
52static const char *const sensor_status_names[] = {
53 [MC_CMD_SENSOR_STATE_OK] = "OK",
54 [MC_CMD_SENSOR_STATE_WARNING] = "Warning",
55 [MC_CMD_SENSOR_STATE_FATAL] = "Fatal",
56 [MC_CMD_SENSOR_STATE_BROKEN] = "Device failure",
57};
58
59void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
60{
61 unsigned int type, state, value;
62 const char *name = NULL, *state_txt;
63
64 type = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);
65 state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);
66 value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE);
67
68 /* Deal gracefully with the board having more drivers than we
69 * know about, but do not expect new sensor states. */
70 if (type < ARRAY_SIZE(efx_mcdi_sensor_type))
71 name = efx_mcdi_sensor_type[type].label;
72 if (!name)
73 name = "No sensor name available";
74 EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
75 state_txt = sensor_status_names[state];
76
77 netif_err(efx, hw, efx->net_dev,
78 "Sensor %d (%s) reports condition '%s' for raw value %d\n",
79 type, name, state_txt, value);
80}
81
82#ifdef CONFIG_SFC_MCDI_MON
83
84struct efx_mcdi_mon_attribute {
85 struct device_attribute dev_attr;
86 unsigned int index;
87 unsigned int type;
88 unsigned int limit_value;
89 char name[12];
90};
91
92static int efx_mcdi_mon_update(struct efx_nic *efx)
93{
94 struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
95 u8 inbuf[MC_CMD_READ_SENSORS_IN_LEN];
96 int rc;
97
98 MCDI_SET_DWORD(inbuf, READ_SENSORS_IN_DMA_ADDR_LO,
99 hwmon->dma_buf.dma_addr & 0xffffffff);
100 MCDI_SET_DWORD(inbuf, READ_SENSORS_IN_DMA_ADDR_HI,
101 (u64)hwmon->dma_buf.dma_addr >> 32);
102
103 rc = efx_mcdi_rpc(efx, MC_CMD_READ_SENSORS,
104 inbuf, sizeof(inbuf), NULL, 0, NULL);
105 if (rc == 0)
106 hwmon->last_update = jiffies;
107 return rc;
108}
109
110static ssize_t efx_mcdi_mon_show_name(struct device *dev,
111 struct device_attribute *attr,
112 char *buf)
113{
114 return sprintf(buf, "%s\n", KBUILD_MODNAME);
115}
116
117static int efx_mcdi_mon_get_entry(struct device *dev, unsigned int index,
118 efx_dword_t *entry)
119{
120 struct efx_nic *efx = dev_get_drvdata(dev);
121 struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
122 int rc;
123
124 BUILD_BUG_ON(MC_CMD_READ_SENSORS_OUT_LEN != 0);
125
126 mutex_lock(&hwmon->update_lock);
127
128 /* Use cached value if last update was < 1 s ago */
129 if (time_before(jiffies, hwmon->last_update + HZ))
130 rc = 0;
131 else
132 rc = efx_mcdi_mon_update(efx);
133
134 /* Copy out the requested entry */
135 *entry = ((efx_dword_t *)hwmon->dma_buf.addr)[index];
136
137 mutex_unlock(&hwmon->update_lock);
138
139 return rc;
140}
141
142static ssize_t efx_mcdi_mon_show_value(struct device *dev,
143 struct device_attribute *attr,
144 char *buf)
145{
146 struct efx_mcdi_mon_attribute *mon_attr =
147 container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
148 efx_dword_t entry;
149 unsigned int value;
150 int rc;
151
152 rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);
153 if (rc)
154 return rc;
155
156 value = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_VALUE);
157
158 /* Convert temperature from degrees to milli-degrees Celsius */
159 if (efx_mcdi_sensor_type[mon_attr->type].hwmon_type == EFX_HWMON_TEMP)
160 value *= 1000;
161
162 return sprintf(buf, "%u\n", value);
163}
164
165static ssize_t efx_mcdi_mon_show_limit(struct device *dev,
166 struct device_attribute *attr,
167 char *buf)
168{
169 struct efx_mcdi_mon_attribute *mon_attr =
170 container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
171 unsigned int value;
172
173 value = mon_attr->limit_value;
174
175 /* Convert temperature from degrees to milli-degrees Celsius */
176 if (efx_mcdi_sensor_type[mon_attr->type].hwmon_type == EFX_HWMON_TEMP)
177 value *= 1000;
178
179 return sprintf(buf, "%u\n", value);
180}
181
182static ssize_t efx_mcdi_mon_show_alarm(struct device *dev,
183 struct device_attribute *attr,
184 char *buf)
185{
186 struct efx_mcdi_mon_attribute *mon_attr =
187 container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
188 efx_dword_t entry;
189 int state;
190 int rc;
191
192 rc = efx_mcdi_mon_get_entry(dev, mon_attr->index, &entry);
193 if (rc)
194 return rc;
195
196 state = EFX_DWORD_FIELD(entry, MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE);
197 return sprintf(buf, "%d\n", state != MC_CMD_SENSOR_STATE_OK);
198}
199
200static ssize_t efx_mcdi_mon_show_label(struct device *dev,
201 struct device_attribute *attr,
202 char *buf)
203{
204 struct efx_mcdi_mon_attribute *mon_attr =
205 container_of(attr, struct efx_mcdi_mon_attribute, dev_attr);
206 return sprintf(buf, "%s\n",
207 efx_mcdi_sensor_type[mon_attr->type].label);
208}
209
210static int
211efx_mcdi_mon_add_attr(struct efx_nic *efx, const char *name,
212 ssize_t (*reader)(struct device *,
213 struct device_attribute *, char *),
214 unsigned int index, unsigned int type,
215 unsigned int limit_value)
216{
217 struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
218 struct efx_mcdi_mon_attribute *attr = &hwmon->attrs[hwmon->n_attrs];
219 int rc;
220
221 strlcpy(attr->name, name, sizeof(attr->name));
222 attr->index = index;
223 attr->type = type;
224 attr->limit_value = limit_value;
225 attr->dev_attr.attr.name = attr->name;
226 attr->dev_attr.attr.mode = S_IRUGO;
227 attr->dev_attr.show = reader;
228 rc = device_create_file(&efx->pci_dev->dev, &attr->dev_attr);
229 if (rc == 0)
230 ++hwmon->n_attrs;
231 return rc;
232}
233
234int efx_mcdi_mon_probe(struct efx_nic *efx)
235{
236 struct efx_mcdi_mon *hwmon = efx_mcdi_mon(efx);
237 unsigned int n_attrs, n_temp = 0, n_cool = 0, n_in = 0;
238 u8 outbuf[MC_CMD_SENSOR_INFO_OUT_LENMAX];
239 size_t outlen;
240 char name[12];
241 u32 mask;
242 int rc, i, type;
243
244 BUILD_BUG_ON(MC_CMD_SENSOR_INFO_IN_LEN != 0);
245
246 rc = efx_mcdi_rpc(efx, MC_CMD_SENSOR_INFO, NULL, 0,
247 outbuf, sizeof(outbuf), &outlen);
248 if (rc)
249 return rc;
250 if (outlen < MC_CMD_SENSOR_INFO_OUT_LENMIN)
251 return -EIO;
252
253 /* Find out which sensors are present. Don't create a device
254 * if there are none.
255 */
256 mask = MCDI_DWORD(outbuf, SENSOR_INFO_OUT_MASK);
257 if (mask == 0)
258 return 0;
259
260 /* Check again for short response */
261 if (outlen < MC_CMD_SENSOR_INFO_OUT_LEN(hweight32(mask)))
262 return -EIO;
263
264 rc = efx_nic_alloc_buffer(efx, &hwmon->dma_buf,
265 4 * MC_CMD_SENSOR_ENTRY_MAXNUM);
266 if (rc)
267 return rc;
268
269 mutex_init(&hwmon->update_lock);
270 efx_mcdi_mon_update(efx);
271
272 /* Allocate space for the maximum possible number of
273 * attributes for this set of sensors: name of the driver plus
274 * value, min, max, crit, alarm and label for each sensor.
275 */
276 n_attrs = 1 + 6 * hweight32(mask);
277 hwmon->attrs = kcalloc(n_attrs, sizeof(*hwmon->attrs), GFP_KERNEL);
278 if (!hwmon->attrs) {
279 rc = -ENOMEM;
280 goto fail;
281 }
282
283 hwmon->device = hwmon_device_register(&efx->pci_dev->dev);
284 if (IS_ERR(hwmon->device)) {
285 rc = PTR_ERR(hwmon->device);
286 goto fail;
287 }
288
289 rc = efx_mcdi_mon_add_attr(efx, "name", efx_mcdi_mon_show_name, 0, 0, 0);
290 if (rc)
291 goto fail;
292
293 for (i = 0, type = -1; ; i++) {
294 const char *hwmon_prefix;
295 unsigned hwmon_index;
296 u16 min1, max1, min2, max2;
297
298 /* Find next sensor type or exit if there is none */
299 type++;
300 while (!(mask & (1 << type))) {
301 type++;
302 if (type == 32)
303 return 0;
304 }
305
306 /* Skip sensors specific to a different port */
307 if (efx_mcdi_sensor_type[type].hwmon_type != EFX_HWMON_UNKNOWN &&
308 efx_mcdi_sensor_type[type].port >= 0 &&
309 efx_mcdi_sensor_type[type].port != efx_port_num(efx))
310 continue;
311
312 switch (efx_mcdi_sensor_type[type].hwmon_type) {
313 case EFX_HWMON_TEMP:
314 hwmon_prefix = "temp";
315 hwmon_index = ++n_temp; /* 1-based */
316 break;
317 case EFX_HWMON_COOL:
318 /* This is likely to be a heatsink, but there
319 * is no convention for representing cooling
320 * devices other than fans.
321 */
322 hwmon_prefix = "fan";
323 hwmon_index = ++n_cool; /* 1-based */
324 break;
325 default:
326 hwmon_prefix = "in";
327 hwmon_index = n_in++; /* 0-based */
328 break;
329 }
330
331 min1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
332 SENSOR_INFO_ENTRY, i, MIN1);
333 max1 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
334 SENSOR_INFO_ENTRY, i, MAX1);
335 min2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
336 SENSOR_INFO_ENTRY, i, MIN2);
337 max2 = MCDI_ARRAY_FIELD(outbuf, SENSOR_ENTRY,
338 SENSOR_INFO_ENTRY, i, MAX2);
339
340 if (min1 != max1) {
341 snprintf(name, sizeof(name), "%s%u_input",
342 hwmon_prefix, hwmon_index);
343 rc = efx_mcdi_mon_add_attr(
344 efx, name, efx_mcdi_mon_show_value, i, type, 0);
345 if (rc)
346 goto fail;
347
348 snprintf(name, sizeof(name), "%s%u_min",
349 hwmon_prefix, hwmon_index);
350 rc = efx_mcdi_mon_add_attr(
351 efx, name, efx_mcdi_mon_show_limit,
352 i, type, min1);
353 if (rc)
354 goto fail;
355
356 snprintf(name, sizeof(name), "%s%u_max",
357 hwmon_prefix, hwmon_index);
358 rc = efx_mcdi_mon_add_attr(
359 efx, name, efx_mcdi_mon_show_limit,
360 i, type, max1);
361 if (rc)
362 goto fail;
363
364 if (min2 != max2) {
365 /* Assume max2 is critical value.
366 * But we have no good way to expose min2.
367 */
368 snprintf(name, sizeof(name), "%s%u_crit",
369 hwmon_prefix, hwmon_index);
370 rc = efx_mcdi_mon_add_attr(
371 efx, name, efx_mcdi_mon_show_limit,
372 i, type, max2);
373 if (rc)
374 goto fail;
375 }
376 }
377
378 snprintf(name, sizeof(name), "%s%u_alarm",
379 hwmon_prefix, hwmon_index);
380 rc = efx_mcdi_mon_add_attr(
381 efx, name, efx_mcdi_mon_show_alarm, i, type, 0);
382 if (rc)
383 goto fail;
384
385 if (efx_mcdi_sensor_type[type].label) {
386 snprintf(name, sizeof(name), "%s%u_label",
387 hwmon_prefix, hwmon_index);
388 rc = efx_mcdi_mon_add_attr(
389 efx, name, efx_mcdi_mon_show_label, i, type, 0);
390 if (rc)
391 goto fail;
392 }
393 }
394
395fail:
396 efx_mcdi_mon_remove(efx);
397 return rc;
398}
399
400void efx_mcdi_mon_remove(struct efx_nic *efx)
401{
402 struct siena_nic_data *nic_data = efx->nic_data;
403 struct efx_mcdi_mon *hwmon = &nic_data->hwmon;
404 unsigned int i;
405
406 for (i = 0; i < hwmon->n_attrs; i++)
407 device_remove_file(&efx->pci_dev->dev,
408 &hwmon->attrs[i].dev_attr);
409 kfree(hwmon->attrs);
410 if (hwmon->device)
411 hwmon_device_unregister(hwmon->device);
412 efx_nic_free_buffer(efx, &hwmon->dma_buf);
413}
414
415#endif /* CONFIG_SFC_MCDI_MON */
diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h
index a3ccd0b9d78..905a1877d60 100644
--- a/drivers/net/ethernet/sfc/nic.h
+++ b/drivers/net/ethernet/sfc/nic.h
@@ -144,12 +144,26 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
144 * struct siena_nic_data - Siena NIC state 144 * struct siena_nic_data - Siena NIC state
145 * @mcdi: Management-Controller-to-Driver Interface 145 * @mcdi: Management-Controller-to-Driver Interface
146 * @wol_filter_id: Wake-on-LAN packet filter id 146 * @wol_filter_id: Wake-on-LAN packet filter id
147 * @hwmon: Hardware monitor state
147 */ 148 */
148struct siena_nic_data { 149struct siena_nic_data {
149 struct efx_mcdi_iface mcdi; 150 struct efx_mcdi_iface mcdi;
150 int wol_filter_id; 151 int wol_filter_id;
152#ifdef CONFIG_SFC_MCDI_MON
153 struct efx_mcdi_mon hwmon;
154#endif
151}; 155};
152 156
157#ifdef CONFIG_SFC_MCDI_MON
158static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx)
159{
160 struct siena_nic_data *nic_data;
161 EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0);
162 nic_data = efx->nic_data;
163 return &nic_data->hwmon;
164}
165#endif
166
153extern const struct efx_nic_type falcon_a1_nic_type; 167extern const struct efx_nic_type falcon_a1_nic_type;
154extern const struct efx_nic_type falcon_b0_nic_type; 168extern const struct efx_nic_type falcon_b0_nic_type;
155extern const struct efx_nic_type siena_a0_nic_type; 169extern const struct efx_nic_type siena_a0_nic_type;
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index f05425842b3..d3c4169e2a0 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -300,6 +300,10 @@ static int siena_probe_nic(struct efx_nic *efx)
300 goto fail5; 300 goto fail5;
301 } 301 }
302 302
303 rc = efx_mcdi_mon_probe(efx);
304 if (rc)
305 goto fail5;
306
303 return 0; 307 return 0;
304 308
305fail5: 309fail5:
@@ -387,6 +391,8 @@ static int siena_init_nic(struct efx_nic *efx)
387 391
388static void siena_remove_nic(struct efx_nic *efx) 392static void siena_remove_nic(struct efx_nic *efx)
389{ 393{
394 efx_mcdi_mon_remove(efx);
395
390 efx_nic_free_buffer(efx, &efx->irq_status); 396 efx_nic_free_buffer(efx, &efx->irq_status);
391 397
392 siena_reset_hw(efx, RESET_TYPE_ALL); 398 siena_reset_hw(efx, RESET_TYPE_ALL);