Commit 55c5e0f8 authored by Ben Hutchings's avatar Ben Hutchings

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: default avatarBen Hutchings <bhutchings@solarflare.com>
parent 1646a6f3
...@@ -19,3 +19,10 @@ config SFC_MTD ...@@ -19,3 +19,10 @@ config SFC_MTD
This exposes the on-board flash memory as MTD devices (e.g. This exposes the on-board flash memory as MTD devices (e.g.
/dev/mtd1). This makes it possible to upload new firmware /dev/mtd1). This makes it possible to upload new firmware
to the NIC. to the NIC.
config SFC_MCDI_MON
bool "Solarflare SFC9000-family hwmon support"
depends on SFC && HWMON && !(SFC=y && HWMON=m)
default y
----help---
This exposes the on-board firmware-managed sensors as a
hardware monitor device.
...@@ -2,7 +2,7 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \ ...@@ -2,7 +2,7 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \
falcon_xmac.o mcdi_mac.o \ falcon_xmac.o mcdi_mac.o \
selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ selftest.o ethtool.o qt202x_phy.o mdio_10g.o \
tenxpress.o txc43128_phy.o falcon_boards.o \ tenxpress.o txc43128_phy.o falcon_boards.o \
mcdi.o mcdi_phy.o mcdi.o mcdi_phy.o mcdi_mon.o
sfc-$(CONFIG_SFC_MTD) += mtd.o sfc-$(CONFIG_SFC_MTD) += mtd.o
obj-$(CONFIG_SFC) += sfc.o obj-$(CONFIG_SFC) += sfc.o
...@@ -517,49 +517,6 @@ static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev) ...@@ -517,49 +517,6 @@ static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev)
efx_link_status_changed(efx); efx_link_status_changed(efx);
} }
static const char *const sensor_names[] = {
[MC_CMD_SENSOR_CONTROLLER_TEMP] = "Controller temp. sensor",
[MC_CMD_SENSOR_PHY_COMMON_TEMP] = "PHY shared temp. sensor",
[MC_CMD_SENSOR_CONTROLLER_COOLING] = "Controller cooling",
[MC_CMD_SENSOR_PHY0_TEMP] = "PHY 0 temp. sensor",
[MC_CMD_SENSOR_PHY0_COOLING] = "PHY 0 cooling",
[MC_CMD_SENSOR_PHY1_TEMP] = "PHY 1 temp. sensor",
[MC_CMD_SENSOR_PHY1_COOLING] = "PHY 1 cooling",
[MC_CMD_SENSOR_IN_1V0] = "1.0V supply sensor",
[MC_CMD_SENSOR_IN_1V2] = "1.2V supply sensor",
[MC_CMD_SENSOR_IN_1V8] = "1.8V supply sensor",
[MC_CMD_SENSOR_IN_2V5] = "2.5V supply sensor",
[MC_CMD_SENSOR_IN_3V3] = "3.3V supply sensor",
[MC_CMD_SENSOR_IN_12V0] = "12V supply sensor"
};
static const char *const sensor_status_names[] = {
[MC_CMD_SENSOR_STATE_OK] = "OK",
[MC_CMD_SENSOR_STATE_WARNING] = "Warning",
[MC_CMD_SENSOR_STATE_FATAL] = "Fatal",
[MC_CMD_SENSOR_STATE_BROKEN] = "Device failure",
};
static void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
{
unsigned int monitor, state, value;
const char *name, *state_txt;
monitor = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);
state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);
value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE);
/* Deal gracefully with the board having more drivers than we
* know about, but do not expect new sensor states. */
name = (monitor >= ARRAY_SIZE(sensor_names))
? "No sensor name available" :
sensor_names[monitor];
EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
state_txt = sensor_status_names[state];
netif_err(efx, hw, efx->net_dev,
"Sensor %d (%s) reports condition '%s' for raw value %d\n",
monitor, name, state_txt, value);
}
/* Called from falcon_process_eventq for MCDI events */ /* Called from falcon_process_eventq for MCDI events */
void efx_mcdi_process_event(struct efx_channel *channel, void efx_mcdi_process_event(struct efx_channel *channel,
efx_qword_t *event) efx_qword_t *event)
......
...@@ -56,6 +56,15 @@ struct efx_mcdi_iface { ...@@ -56,6 +56,15 @@ struct efx_mcdi_iface {
size_t resplen; size_t resplen;
}; };
struct efx_mcdi_mon {
struct efx_buffer dma_buf;
struct mutex update_lock;
unsigned long last_update;
struct device *device;
struct efx_mcdi_mon_attribute *attrs;
unsigned int n_attrs;
};
extern void efx_mcdi_init(struct efx_nic *efx); extern void efx_mcdi_init(struct efx_nic *efx);
extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, extern 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,6 +77,7 @@ extern void efx_mcdi_mode_event(struct efx_nic *efx);
extern void efx_mcdi_process_event(struct efx_channel *channel, extern void efx_mcdi_process_event(struct efx_channel *channel,
efx_qword_t *event); efx_qword_t *event);
extern void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
#define MCDI_PTR2(_buf, _ofst) \ #define MCDI_PTR2(_buf, _ofst) \
(((u8 *)_buf) + _ofst) (((u8 *)_buf) + _ofst)
...@@ -83,6 +93,10 @@ extern void efx_mcdi_process_event(struct efx_channel *channel, ...@@ -83,6 +93,10 @@ extern void efx_mcdi_process_event(struct efx_channel *channel,
#define MCDI_PTR(_buf, _ofst) \ #define MCDI_PTR(_buf, _ofst) \
MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST) MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST)
#define MCDI_ARRAY_PTR(_buf, _field, _type, _index) \
MCDI_PTR2(_buf, \
MC_CMD_ ## _field ## _OFST + \
(_index) * MC_CMD_ ## _type ## _TYPEDEF_LEN)
#define MCDI_SET_DWORD(_buf, _ofst, _value) \ #define MCDI_SET_DWORD(_buf, _ofst, _value) \
MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value) MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value)
#define MCDI_DWORD(_buf, _ofst) \ #define MCDI_DWORD(_buf, _ofst) \
...@@ -92,6 +106,12 @@ extern void efx_mcdi_process_event(struct efx_channel *channel, ...@@ -92,6 +106,12 @@ extern void efx_mcdi_process_event(struct efx_channel *channel,
#define MCDI_EVENT_FIELD(_ev, _field) \ #define MCDI_EVENT_FIELD(_ev, _field) \
EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field) EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field)
#define MCDI_ARRAY_FIELD(_buf, _field1, _type, _index, _field2) \
EFX_DWORD_FIELD( \
*((efx_dword_t *) \
(MCDI_ARRAY_PTR(_buf, _field1, _type, _index) + \
(MC_CMD_ ## _type ## _TYPEDEF_ ## _field2 ## _OFST & ~3))), \
MC_CMD_ ## _type ## _TYPEDEF_ ## _field2)
extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len); extern void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len);
extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, extern 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, ...@@ -131,4 +151,12 @@ extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
extern int efx_mcdi_mac_reconfigure(struct efx_nic *efx); extern int efx_mcdi_mac_reconfigure(struct efx_nic *efx);
extern bool efx_mcdi_mac_check_fault(struct efx_nic *efx); extern bool efx_mcdi_mac_check_fault(struct efx_nic *efx);
#ifdef CONFIG_SFC_MCDI_MON
extern int efx_mcdi_mon_probe(struct efx_nic *efx);
extern void efx_mcdi_mon_remove(struct efx_nic *efx);
#else
static inline int efx_mcdi_mon_probe(struct efx_nic *efx) { return 0; }
static inline void efx_mcdi_mon_remove(struct efx_nic *efx) {}
#endif
#endif /* EFX_MCDI_H */ #endif /* EFX_MCDI_H */
This diff is collapsed.
...@@ -144,12 +144,26 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) ...@@ -144,12 +144,26 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
* struct siena_nic_data - Siena NIC state * struct siena_nic_data - Siena NIC state
* @mcdi: Management-Controller-to-Driver Interface * @mcdi: Management-Controller-to-Driver Interface
* @wol_filter_id: Wake-on-LAN packet filter id * @wol_filter_id: Wake-on-LAN packet filter id
* @hwmon: Hardware monitor state
*/ */
struct siena_nic_data { struct siena_nic_data {
struct efx_mcdi_iface mcdi; struct efx_mcdi_iface mcdi;
int wol_filter_id; int wol_filter_id;
#ifdef CONFIG_SFC_MCDI_MON
struct efx_mcdi_mon hwmon;
#endif
}; };
#ifdef CONFIG_SFC_MCDI_MON
static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx)
{
struct siena_nic_data *nic_data;
EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0);
nic_data = efx->nic_data;
return &nic_data->hwmon;
}
#endif
extern const struct efx_nic_type falcon_a1_nic_type; extern const struct efx_nic_type falcon_a1_nic_type;
extern const struct efx_nic_type falcon_b0_nic_type; extern const struct efx_nic_type falcon_b0_nic_type;
extern const struct efx_nic_type siena_a0_nic_type; extern const struct efx_nic_type siena_a0_nic_type;
......
...@@ -300,6 +300,10 @@ static int siena_probe_nic(struct efx_nic *efx) ...@@ -300,6 +300,10 @@ static int siena_probe_nic(struct efx_nic *efx)
goto fail5; goto fail5;
} }
rc = efx_mcdi_mon_probe(efx);
if (rc)
goto fail5;
return 0; return 0;
fail5: fail5:
...@@ -387,6 +391,8 @@ static int siena_init_nic(struct efx_nic *efx) ...@@ -387,6 +391,8 @@ static int siena_init_nic(struct efx_nic *efx)
static void siena_remove_nic(struct efx_nic *efx) static void siena_remove_nic(struct efx_nic *efx)
{ {
efx_mcdi_mon_remove(efx);
efx_nic_free_buffer(efx, &efx->irq_status); efx_nic_free_buffer(efx, &efx->irq_status);
siena_reset_hw(efx, RESET_TYPE_ALL); siena_reset_hw(efx, RESET_TYPE_ALL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment