diff options
Diffstat (limited to 'drivers/net/sfc/boards.c')
-rw-r--r-- | drivers/net/sfc/boards.c | 206 |
1 files changed, 156 insertions, 50 deletions
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index 99e602373269..64903496aa9a 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /**************************************************************************** | 1 | /**************************************************************************** |
2 | * Driver for Solarflare Solarstorm network controllers and boards | 2 | * Driver for Solarflare Solarstorm network controllers and boards |
3 | * Copyright 2007 Solarflare Communications Inc. | 3 | * Copyright 2007-2008 Solarflare Communications Inc. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify it | 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 | 6 | * under the terms of the GNU General Public License version 2 as published |
@@ -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,81 +204,67 @@ 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 | ||
95 | /* This will get expanded as board-specific details get moved out of the | 231 | /* This will get expanded as board-specific details get moved out of the |
96 | * PHY drivers. */ | 232 | * PHY drivers. */ |
97 | struct efx_board_data { | 233 | struct efx_board_data { |
234 | enum efx_board_type type; | ||
98 | const char *ref_model; | 235 | const char *ref_model; |
99 | const char *gen_type; | 236 | const char *gen_type; |
100 | int (*init) (struct efx_nic *nic); | 237 | int (*init) (struct efx_nic *nic); |
101 | }; | 238 | }; |
102 | 239 | ||
103 | static int dummy_init(struct efx_nic *nic) | ||
104 | { | ||
105 | return 0; | ||
106 | } | ||
107 | 240 | ||
108 | static struct efx_board_data board_data[] = { | 241 | static struct efx_board_data board_data[] = { |
109 | [EFX_BOARD_INVALID] = | 242 | { EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init }, |
110 | {NULL, NULL, dummy_init}, | 243 | { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init }, |
111 | [EFX_BOARD_SFE4001] = | 244 | { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter", |
112 | {"SFE4001", "10GBASE-T adapter", sfe4001_init}, | 245 | sfn4111t_init }, |
113 | [EFX_BOARD_SFE4002] = | ||
114 | {"SFE4002", "XFP adapter", sfe4002_init}, | ||
115 | }; | 246 | }; |
116 | 247 | ||
117 | int efx_set_board_info(struct efx_nic *efx, u16 revision_info) | 248 | void efx_set_board_info(struct efx_nic *efx, u16 revision_info) |
118 | { | 249 | { |
119 | int rc = 0; | 250 | struct efx_board_data *data = NULL; |
120 | struct efx_board_data *data; | 251 | int i; |
121 | |||
122 | if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) { | ||
123 | EFX_ERR(efx, "squashing unknown board type %d\n", | ||
124 | BOARD_TYPE(revision_info)); | ||
125 | revision_info = 0; | ||
126 | } | ||
127 | 252 | ||
128 | if (BOARD_TYPE(revision_info) == 0) { | 253 | efx->board_info.type = BOARD_TYPE(revision_info); |
129 | efx->board_info.major = 0; | 254 | efx->board_info.major = BOARD_MAJOR(revision_info); |
130 | efx->board_info.minor = 0; | 255 | efx->board_info.minor = BOARD_MINOR(revision_info); |
131 | /* For early boards that don't have revision info. there is | ||
132 | * only 1 board for each PHY type, so we can work it out, with | ||
133 | * the exception of the PHY-less boards. */ | ||
134 | switch (efx->phy_type) { | ||
135 | case PHY_TYPE_10XPRESS: | ||
136 | efx->board_info.type = EFX_BOARD_SFE4001; | ||
137 | break; | ||
138 | case PHY_TYPE_XFP: | ||
139 | efx->board_info.type = EFX_BOARD_SFE4002; | ||
140 | break; | ||
141 | default: | ||
142 | efx->board_info.type = 0; | ||
143 | break; | ||
144 | } | ||
145 | } else { | ||
146 | efx->board_info.type = BOARD_TYPE(revision_info); | ||
147 | efx->board_info.major = BOARD_MAJOR(revision_info); | ||
148 | efx->board_info.minor = BOARD_MINOR(revision_info); | ||
149 | } | ||
150 | 256 | ||
151 | data = &board_data[efx->board_info.type]; | 257 | for (i = 0; i < ARRAY_SIZE(board_data); i++) |
258 | if (board_data[i].type == efx->board_info.type) | ||
259 | data = &board_data[i]; | ||
152 | 260 | ||
153 | /* Report the board model number or generic type for recognisable | 261 | if (data) { |
154 | * boards. */ | ||
155 | if (efx->board_info.type != 0) | ||
156 | EFX_INFO(efx, "board is %s rev %c%d\n", | 262 | EFX_INFO(efx, "board is %s rev %c%d\n", |
157 | (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) | 263 | (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) |
158 | ? data->ref_model : data->gen_type, | 264 | ? data->ref_model : data->gen_type, |
159 | 'A' + efx->board_info.major, efx->board_info.minor); | 265 | 'A' + efx->board_info.major, efx->board_info.minor); |
160 | 266 | efx->board_info.init = data->init; | |
161 | efx->board_info.init = data->init; | 267 | } else { |
162 | 268 | EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type); | |
163 | return rc; | 269 | } |
164 | } | 270 | } |