aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2008-11-04 15:34:56 -0500
committerJeff Garzik <jgarzik@redhat.com>2008-11-06 00:50:09 -0500
commit3e133c44d24a094118caee182200462d46c55b56 (patch)
treecabc1821bef090abedd1891c3d16137dea8f2ef3 /drivers/net/sfc
parentf41507245ef8b079685aba8da5b5b2b5e87e70bc (diff)
sfc: Use lm87 and lm90 drivers for board temperature/power monitoring
Add board monitoring to periodic work whenever link is down. For SFE4001, report when a fault has caused the PHY to turn off. For SFE4002, switch XFP PHY into low-power state in case of a fault. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/sfc')
-rw-r--r--drivers/net/sfc/boards.c136
-rw-r--r--drivers/net/sfc/mdio_10g.c35
-rw-r--r--drivers/net/sfc/mdio_10g.h7
-rw-r--r--drivers/net/sfc/net_driver.h6
-rw-r--r--drivers/net/sfc/sfe4001.c116
-rw-r--r--drivers/net/sfc/tenxpress.c18
-rw-r--r--drivers/net/sfc/workarounds.h2
-rw-r--r--drivers/net/sfc/xfp_phy.c9
8 files changed, 265 insertions, 64 deletions
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
index 99e602373269..edf026280bec 100644
--- a/drivers/net/sfc/boards.c
+++ b/drivers/net/sfc/boards.c
@@ -11,6 +11,7 @@
11#include "phy.h" 11#include "phy.h"
12#include "boards.h" 12#include "boards.h"
13#include "efx.h" 13#include "efx.h"
14#include "workarounds.h"
14 15
15/* Macros for unpacking the board revision */ 16/* Macros for unpacking the board revision */
16/* The revision info is in host byte order. */ 17/* The revision info is in host byte order. */
@@ -52,9 +53,128 @@ static void board_blink(struct efx_nic *efx, bool blink)
52} 53}
53 54
54/***************************************************************************** 55/*****************************************************************************
56 * Support for LM87 sensor chip used on several boards
57 */
58#define LM87_REG_ALARMS1 0x41
59#define LM87_REG_ALARMS2 0x42
60#define LM87_IN_LIMITS(nr, _min, _max) \
61 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
62#define LM87_AIN_LIMITS(nr, _min, _max) \
63 0x3B + (nr), _max, 0x1A + (nr), _min
64#define LM87_TEMP_INT_LIMITS(_min, _max) \
65 0x39, _max, 0x3A, _min
66#define LM87_TEMP_EXT1_LIMITS(_min, _max) \
67 0x37, _max, 0x38, _min
68
69#define LM87_ALARM_TEMP_INT 0x10
70#define LM87_ALARM_TEMP_EXT1 0x20
71
72#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
73
74static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
75 const u8 *reg_values)
76{
77 struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info);
78 int rc;
79
80 if (!client)
81 return -EIO;
82
83 while (*reg_values) {
84 u8 reg = *reg_values++;
85 u8 value = *reg_values++;
86 rc = i2c_smbus_write_byte_data(client, reg, value);
87 if (rc)
88 goto err;
89 }
90
91 efx->board_info.hwmon_client = client;
92 return 0;
93
94err:
95 i2c_unregister_device(client);
96 return rc;
97}
98
99static void efx_fini_lm87(struct efx_nic *efx)
100{
101 i2c_unregister_device(efx->board_info.hwmon_client);
102}
103
104static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
105{
106 struct i2c_client *client = efx->board_info.hwmon_client;
107 s32 alarms1, alarms2;
108
109 /* If link is up then do not monitor temperature */
110 if (EFX_WORKAROUND_7884(efx) && efx->link_up)
111 return 0;
112
113 alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
114 alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
115 if (alarms1 < 0)
116 return alarms1;
117 if (alarms2 < 0)
118 return alarms2;
119 alarms1 &= mask;
120 alarms2 &= mask >> 8;
121 if (alarms1 || alarms2) {
122 EFX_ERR(efx,
123 "LM87 detected a hardware failure (status %02x:%02x)"
124 "%s%s\n",
125 alarms1, alarms2,
126 (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
127 (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
128 return -ERANGE;
129 }
130
131 return 0;
132}
133
134#else /* !CONFIG_SENSORS_LM87 */
135
136static inline int
137efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
138 const u8 *reg_values)
139{
140 return 0;
141}
142static inline void efx_fini_lm87(struct efx_nic *efx)
143{
144}
145static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
146{
147 return 0;
148}
149
150#endif /* CONFIG_SENSORS_LM87 */
151
152/*****************************************************************************
55 * Support for the SFE4002 153 * Support for the SFE4002
56 * 154 *
57 */ 155 */
156static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
157
158static const u8 sfe4002_lm87_regs[] = {
159 LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */
160 LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */
161 LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */
162 LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */
163 LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */
164 LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */
165 LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */
166 LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */
167 LM87_TEMP_INT_LIMITS(10, 60), /* board */
168 LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */
169 0
170};
171
172static struct i2c_board_info sfe4002_hwmon_info = {
173 I2C_BOARD_INFO("lm87", 0x2e),
174 .platform_data = &sfe4002_lm87_channel,
175 .irq = -1,
176};
177
58/****************************************************************************/ 178/****************************************************************************/
59/* LED allocations. Note that on rev A0 boards the schematic and the reality 179/* LED allocations. Note that on rev A0 boards the schematic and the reality
60 * differ: red and green are swapped. Below is the fixed (A1) layout (there 180 * differ: red and green are swapped. Below is the fixed (A1) layout (there
@@ -84,11 +204,27 @@ static void sfe4002_fault_led(struct efx_nic *efx, bool state)
84 QUAKE_LED_OFF); 204 QUAKE_LED_OFF);
85} 205}
86 206
207static int sfe4002_check_hw(struct efx_nic *efx)
208{
209 /* A0 board rev. 4002s report a temperature fault the whole time
210 * (bad sensor) so we mask it out. */
211 unsigned alarm_mask =
212 (efx->board_info.major == 0 && efx->board_info.minor == 0) ?
213 ~LM87_ALARM_TEMP_EXT1 : ~0;
214
215 return efx_check_lm87(efx, alarm_mask);
216}
217
87static int sfe4002_init(struct efx_nic *efx) 218static int sfe4002_init(struct efx_nic *efx)
88{ 219{
220 int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
221 if (rc)
222 return rc;
223 efx->board_info.monitor = sfe4002_check_hw;
89 efx->board_info.init_leds = sfe4002_init_leds; 224 efx->board_info.init_leds = sfe4002_init_leds;
90 efx->board_info.set_fault_led = sfe4002_fault_led; 225 efx->board_info.set_fault_led = sfe4002_fault_led;
91 efx->board_info.blink = board_blink; 226 efx->board_info.blink = board_blink;
227 efx->board_info.fini = efx_fini_lm87;
92 return 0; 228 return 0;
93} 229}
94 230
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 003e48dcb2f3..19e25210b687 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -260,6 +260,41 @@ void mdio_clause45_phy_reconfigure(struct efx_nic *efx)
260 MDIO_MMDREG_CTRL1, ctrl2); 260 MDIO_MMDREG_CTRL1, ctrl2);
261} 261}
262 262
263static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx,
264 int lpower, int mmd)
265{
266 int phy = efx->mii.phy_id;
267 int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1);
268 int ctrl1, ctrl2;
269
270 EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n",
271 mmd, lpower);
272
273 if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) {
274 ctrl1 = ctrl2 = mdio_clause45_read(efx, phy,
275 mmd, MDIO_MMDREG_CTRL1);
276 if (lpower)
277 ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
278 else
279 ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
280 if (ctrl1 != ctrl2)
281 mdio_clause45_write(efx, phy, mmd,
282 MDIO_MMDREG_CTRL1, ctrl2);
283 }
284}
285
286void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
287 int low_power, unsigned int mmd_mask)
288{
289 int mmd = 0;
290 while (mmd_mask) {
291 if (mmd_mask & 1)
292 mdio_clause45_set_mmd_lpower(efx, low_power, mmd);
293 mmd_mask = (mmd_mask >> 1);
294 mmd++;
295 }
296}
297
263/** 298/**
264 * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO. 299 * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
265 * @efx: Efx NIC 300 * @efx: Efx NIC
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index 19c42eaf7fb4..db9f358349c6 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -54,6 +54,9 @@
54/* Loopback bit for WIS, PCS, PHYSX and DTEXS */ 54/* Loopback bit for WIS, PCS, PHYSX and DTEXS */
55#define MDIO_MMDREG_CTRL1_LBACK_LBN (14) 55#define MDIO_MMDREG_CTRL1_LBACK_LBN (14)
56#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1) 56#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1)
57/* Low power */
58#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11)
59#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1)
57 60
58/* Bits in MMDREG_STAT1 */ 61/* Bits in MMDREG_STAT1 */
59#define MDIO_MMDREG_STAT1_FAULT_LBN (7) 62#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
@@ -240,6 +243,10 @@ extern void mdio_clause45_transmit_disable(struct efx_nic *efx);
240/* Generic part of reconfigure: set/clear loopback bits */ 243/* Generic part of reconfigure: set/clear loopback bits */
241extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); 244extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx);
242 245
246/* Set the power state of the specified MMDs */
247extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
248 int low_power, unsigned int mmd_mask);
249
243/* Read (some of) the PHY settings over MDIO */ 250/* Read (some of) the PHY settings over MDIO */
244extern void mdio_clause45_get_settings(struct efx_nic *efx, 251extern void mdio_clause45_get_settings(struct efx_nic *efx,
245 struct ethtool_cmd *ecmd); 252 struct ethtool_cmd *ecmd);
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index c953eb19df42..e596c9a6a4c4 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -414,6 +414,7 @@ struct efx_blinker {
414 * @init_leds: Sets up board LEDs 414 * @init_leds: Sets up board LEDs
415 * @set_fault_led: Turns the fault LED on or off 415 * @set_fault_led: Turns the fault LED on or off
416 * @blink: Starts/stops blinking 416 * @blink: Starts/stops blinking
417 * @monitor: Board-specific health check function
417 * @fini: Cleanup function 418 * @fini: Cleanup function
418 * @blinker: used to blink LEDs in software 419 * @blinker: used to blink LEDs in software
419 * @hwmon_client: I2C client for hardware monitor 420 * @hwmon_client: I2C client for hardware monitor
@@ -428,6 +429,7 @@ struct efx_board {
428 * have a separate init callback that happens later than 429 * have a separate init callback that happens later than
429 * board init. */ 430 * board init. */
430 int (*init_leds)(struct efx_nic *efx); 431 int (*init_leds)(struct efx_nic *efx);
432 int (*monitor) (struct efx_nic *nic);
431 void (*set_fault_led) (struct efx_nic *efx, bool state); 433 void (*set_fault_led) (struct efx_nic *efx, bool state);
432 void (*blink) (struct efx_nic *efx, bool start); 434 void (*blink) (struct efx_nic *efx, bool start);
433 void (*fini) (struct efx_nic *nic); 435 void (*fini) (struct efx_nic *nic);
@@ -525,11 +527,15 @@ struct efx_phy_operations {
525 * @enum efx_phy_mode - PHY operating mode flags 527 * @enum efx_phy_mode - PHY operating mode flags
526 * @PHY_MODE_NORMAL: on and should pass traffic 528 * @PHY_MODE_NORMAL: on and should pass traffic
527 * @PHY_MODE_TX_DISABLED: on with TX disabled 529 * @PHY_MODE_TX_DISABLED: on with TX disabled
530 * @PHY_MODE_LOW_POWER: set to low power through MDIO
531 * @PHY_MODE_OFF: switched off through external control
528 * @PHY_MODE_SPECIAL: on but will not pass traffic 532 * @PHY_MODE_SPECIAL: on but will not pass traffic
529 */ 533 */
530enum efx_phy_mode { 534enum efx_phy_mode {
531 PHY_MODE_NORMAL = 0, 535 PHY_MODE_NORMAL = 0,
532 PHY_MODE_TX_DISABLED = 1, 536 PHY_MODE_TX_DISABLED = 1,
537 PHY_MODE_LOW_POWER = 2,
538 PHY_MODE_OFF = 4,
533 PHY_MODE_SPECIAL = 8, 539 PHY_MODE_SPECIAL = 8,
534}; 540};
535 541
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
index fe4e3fd22330..aa576c559ec8 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/sfe4001.c
@@ -21,6 +21,7 @@
21#include "falcon_hwdefs.h" 21#include "falcon_hwdefs.h"
22#include "falcon_io.h" 22#include "falcon_io.h"
23#include "mac.h" 23#include "mac.h"
24#include "workarounds.h"
24 25
25/************************************************************************** 26/**************************************************************************
26 * 27 *
@@ -65,48 +66,9 @@
65#define P1_SPARE_LBN 4 66#define P1_SPARE_LBN 4
66#define P1_SPARE_WIDTH 4 67#define P1_SPARE_WIDTH 4
67 68
68 69/* Temperature Sensor */
69/************************************************************************** 70#define MAX664X_REG_RSL 0x02
70 * 71#define MAX664X_REG_WLHO 0x0B
71 * Temperature Sensor
72 *
73 **************************************************************************/
74#define MAX6647 0x4e
75
76#define RLTS 0x00
77#define RLTE 0x01
78#define RSL 0x02
79#define RCL 0x03
80#define RCRA 0x04
81#define RLHN 0x05
82#define RLLI 0x06
83#define RRHI 0x07
84#define RRLS 0x08
85#define WCRW 0x0a
86#define WLHO 0x0b
87#define WRHA 0x0c
88#define WRLN 0x0e
89#define OSHT 0x0f
90#define REET 0x10
91#define RIET 0x11
92#define RWOE 0x19
93#define RWOI 0x20
94#define HYS 0x21
95#define QUEUE 0x22
96#define MFID 0xfe
97#define REVID 0xff
98
99/* Status bits */
100#define MAX6647_BUSY (1 << 7) /* ADC is converting */
101#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */
102#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */
103#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */
104#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */
105#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */
106#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */
107#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */
108
109static const u8 xgphy_max_temperature = 90;
110 72
111static void sfe4001_poweroff(struct efx_nic *efx) 73static void sfe4001_poweroff(struct efx_nic *efx)
112{ 74{
@@ -119,7 +81,7 @@ static void sfe4001_poweroff(struct efx_nic *efx)
119 i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); 81 i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff);
120 82
121 /* Clear any over-temperature alert */ 83 /* Clear any over-temperature alert */
122 i2c_smbus_read_byte_data(hwmon_client, RSL); 84 i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
123} 85}
124 86
125static int sfe4001_poweron(struct efx_nic *efx) 87static int sfe4001_poweron(struct efx_nic *efx)
@@ -131,7 +93,7 @@ static int sfe4001_poweron(struct efx_nic *efx)
131 u8 out; 93 u8 out;
132 94
133 /* Clear any previous over-temperature alert */ 95 /* Clear any previous over-temperature alert */
134 rc = i2c_smbus_read_byte_data(hwmon_client, RSL); 96 rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL);
135 if (rc < 0) 97 if (rc < 0)
136 return rc; 98 return rc;
137 99
@@ -209,6 +171,34 @@ fail_on:
209 return rc; 171 return rc;
210} 172}
211 173
174static int sfe4001_check_hw(struct efx_nic *efx)
175{
176 s32 status;
177
178 /* If XAUI link is up then do not monitor */
179 if (EFX_WORKAROUND_7884(efx) && falcon_xaui_link_ok(efx))
180 return 0;
181
182 /* Check the powered status of the PHY. Lack of power implies that
183 * the MAX6647 has shut down power to it, probably due to a temp.
184 * alarm. Reading the power status rather than the MAX6647 status
185 * directly because the later is read-to-clear and would thus
186 * start to power up the PHY again when polled, causing us to blip
187 * the power undesirably.
188 * We know we can read from the IO expander because we did
189 * it during power-on. Assume failure now is bad news. */
190 status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN);
191 if (status >= 0 &&
192 (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0)
193 return 0;
194
195 /* Use board power control, not PHY power control */
196 sfe4001_poweroff(efx);
197 efx->phy_mode = PHY_MODE_OFF;
198
199 return (status < 0) ? -EIO : -ERANGE;
200}
201
212/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin 202/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin
213 * using the 3V3X output of the IO-expander. Allow the user to set 203 * using the 3V3X output of the IO-expander. Allow the user to set
214 * this when the device is stopped, and keep it stopped then. 204 * this when the device is stopped, and keep it stopped then.
@@ -261,35 +251,34 @@ static void sfe4001_fini(struct efx_nic *efx)
261 i2c_unregister_device(efx->board_info.hwmon_client); 251 i2c_unregister_device(efx->board_info.hwmon_client);
262} 252}
263 253
254static struct i2c_board_info sfe4001_hwmon_info = {
255 I2C_BOARD_INFO("max6647", 0x4e),
256 .irq = -1,
257};
258
264/* This board uses an I2C expander to provider power to the PHY, which needs to 259/* This board uses an I2C expander to provider power to the PHY, which needs to
265 * be turned on before the PHY can be used. 260 * be turned on before the PHY can be used.
266 * Context: Process context, rtnl lock held 261 * Context: Process context, rtnl lock held
267 */ 262 */
268int sfe4001_init(struct efx_nic *efx) 263int sfe4001_init(struct efx_nic *efx)
269{ 264{
270 struct i2c_client *hwmon_client;
271 int rc; 265 int rc;
272 266
273 hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); 267#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE)
274 if (!hwmon_client) 268 efx->board_info.hwmon_client =
269 i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);
270#else
271 efx->board_info.hwmon_client =
272 i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr);
273#endif
274 if (!efx->board_info.hwmon_client)
275 return -EIO; 275 return -EIO;
276 efx->board_info.hwmon_client = hwmon_client;
277 276
278 /* Set DSP over-temperature alert threshold */ 277 /* Raise board/PHY high limit from 85 to 90 degrees Celsius */
279 EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); 278 rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client,
280 rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, 279 MAX664X_REG_WLHO, 90);
281 xgphy_max_temperature);
282 if (rc) 280 if (rc)
283 goto fail_ioexp; 281 goto fail_hwmon;
284
285 /* Read it back and verify */
286 rc = i2c_smbus_read_byte_data(hwmon_client, RLHN);
287 if (rc < 0)
288 goto fail_ioexp;
289 if (rc != xgphy_max_temperature) {
290 rc = -EFAULT;
291 goto fail_ioexp;
292 }
293 282
294 efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); 283 efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539);
295 if (!efx->board_info.ioexp_client) { 284 if (!efx->board_info.ioexp_client) {
@@ -301,6 +290,7 @@ int sfe4001_init(struct efx_nic *efx)
301 * blink code. */ 290 * blink code. */
302 efx->board_info.blink = tenxpress_phy_blink; 291 efx->board_info.blink = tenxpress_phy_blink;
303 292
293 efx->board_info.monitor = sfe4001_check_hw;
304 efx->board_info.fini = sfe4001_fini; 294 efx->board_info.fini = sfe4001_fini;
305 295
306 rc = sfe4001_poweron(efx); 296 rc = sfe4001_poweron(efx);
@@ -319,6 +309,6 @@ fail_on:
319fail_ioexp: 309fail_ioexp:
320 i2c_unregister_device(efx->board_info.ioexp_client); 310 i2c_unregister_device(efx->board_info.ioexp_client);
321fail_hwmon: 311fail_hwmon:
322 i2c_unregister_device(hwmon_client); 312 i2c_unregister_device(efx->board_info.hwmon_client);
323 return rc; 313 return rc;
324} 314}
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index d507c93d666e..8d41c29b9d7b 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -376,6 +376,7 @@ static int tenxpress_phy_check_hw(struct efx_nic *efx)
376{ 376{
377 struct tenxpress_phy_data *phy_data = efx->phy_data; 377 struct tenxpress_phy_data *phy_data = efx->phy_data;
378 bool link_ok; 378 bool link_ok;
379 int rc = 0;
379 380
380 link_ok = tenxpress_link_ok(efx, true); 381 link_ok = tenxpress_link_ok(efx, true);
381 382
@@ -391,7 +392,22 @@ static int tenxpress_phy_check_hw(struct efx_nic *efx)
391 atomic_set(&phy_data->bad_crc_count, 0); 392 atomic_set(&phy_data->bad_crc_count, 0);
392 } 393 }
393 394
394 return 0; 395 rc = efx->board_info.monitor(efx);
396 if (rc) {
397 EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
398 (rc == -ERANGE) ? "reported fault" : "failed");
399 if (efx->phy_mode & PHY_MODE_OFF) {
400 /* Assume that board has shut PHY off */
401 phy_data->phy_mode = PHY_MODE_OFF;
402 } else {
403 efx->phy_mode |= PHY_MODE_LOW_POWER;
404 mdio_clause45_set_mmds_lpower(efx, true,
405 efx->phy_op->mmds);
406 phy_data->phy_mode |= PHY_MODE_LOW_POWER;
407 }
408 }
409
410 return rc;
395} 411}
396 412
397static void tenxpress_phy_fini(struct efx_nic *efx) 413static void tenxpress_phy_fini(struct efx_nic *efx)
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index fa7b49d69288..ec50b90f4285 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -22,6 +22,8 @@
22#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS 22#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
23/* RX PCIe double split performance issue */ 23/* RX PCIe double split performance issue */
24#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS 24#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
25/* Bit-bashed I2C reads cause performance drop */
26#define EFX_WORKAROUND_7884 EFX_WORKAROUND_ALWAYS
25/* TX pkt parser problem with <= 16 byte TXes */ 27/* TX pkt parser problem with <= 16 byte TXes */
26#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS 28#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
27/* Low rate CRC errors require XAUI reset */ 29/* Low rate CRC errors require XAUI reset */
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
index 276151df3a70..91f024662101 100644
--- a/drivers/net/sfc/xfp_phy.c
+++ b/drivers/net/sfc/xfp_phy.c
@@ -128,6 +128,15 @@ static int xfp_phy_check_hw(struct efx_nic *efx)
128 if (link_up != efx->link_up) 128 if (link_up != efx->link_up)
129 falcon_xmac_sim_phy_event(efx); 129 falcon_xmac_sim_phy_event(efx);
130 130
131 rc = efx->board_info.monitor(efx);
132 if (rc) {
133 struct xfp_phy_data *phy_data = efx->phy_data;
134 EFX_ERR(efx, "XFP sensor alert; putting PHY into low power\n");
135 efx->phy_mode |= PHY_MODE_LOW_POWER;
136 mdio_clause45_set_mmds_lpower(efx, 1, XFP_REQUIRED_DEVS);
137 phy_data->phy_mode |= PHY_MODE_LOW_POWER;
138 }
139
131 return rc; 140 return rc;
132} 141}
133 142