diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-11-04 15:34:56 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-11-06 00:50:09 -0500 |
commit | 3e133c44d24a094118caee182200462d46c55b56 (patch) | |
tree | cabc1821bef090abedd1891c3d16137dea8f2ef3 /drivers | |
parent | f41507245ef8b079685aba8da5b5b2b5e87e70bc (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')
-rw-r--r-- | drivers/net/sfc/boards.c | 136 | ||||
-rw-r--r-- | drivers/net/sfc/mdio_10g.c | 35 | ||||
-rw-r--r-- | drivers/net/sfc/mdio_10g.h | 7 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 6 | ||||
-rw-r--r-- | drivers/net/sfc/sfe4001.c | 116 | ||||
-rw-r--r-- | drivers/net/sfc/tenxpress.c | 18 | ||||
-rw-r--r-- | drivers/net/sfc/workarounds.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/xfp_phy.c | 9 |
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 | |||
74 | static 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 | |||
94 | err: | ||
95 | i2c_unregister_device(client); | ||
96 | return rc; | ||
97 | } | ||
98 | |||
99 | static void efx_fini_lm87(struct efx_nic *efx) | ||
100 | { | ||
101 | i2c_unregister_device(efx->board_info.hwmon_client); | ||
102 | } | ||
103 | |||
104 | static 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 | |||
136 | static inline int | ||
137 | efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, | ||
138 | const u8 *reg_values) | ||
139 | { | ||
140 | return 0; | ||
141 | } | ||
142 | static inline void efx_fini_lm87(struct efx_nic *efx) | ||
143 | { | ||
144 | } | ||
145 | static 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 | */ |
156 | static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ | ||
157 | |||
158 | static 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 | |||
172 | static 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 | ||
207 | static 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 | |||
87 | static int sfe4002_init(struct efx_nic *efx) | 218 | static 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 | ||
263 | static 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 | |||
286 | void 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 */ |
241 | extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); | 244 | extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); |
242 | 245 | ||
246 | /* Set the power state of the specified MMDs */ | ||
247 | extern 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 */ |
244 | extern void mdio_clause45_get_settings(struct efx_nic *efx, | 251 | extern 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 | */ |
530 | enum efx_phy_mode { | 534 | enum 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 | |||
109 | static const u8 xgphy_max_temperature = 90; | ||
110 | 72 | ||
111 | static void sfe4001_poweroff(struct efx_nic *efx) | 73 | static 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 | ||
125 | static int sfe4001_poweron(struct efx_nic *efx) | 87 | static 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 | ||
174 | static 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 | ||
254 | static 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 | */ |
268 | int sfe4001_init(struct efx_nic *efx) | 263 | int 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: | |||
319 | fail_ioexp: | 309 | fail_ioexp: |
320 | i2c_unregister_device(efx->board_info.ioexp_client); | 310 | i2c_unregister_device(efx->board_info.ioexp_client); |
321 | fail_hwmon: | 311 | fail_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 | ||
397 | static void tenxpress_phy_fini(struct efx_nic *efx) | 413 | static 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 | ||