Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.32-rc2 328 lines 9.6 kB view raw
1/**************************************************************************** 2 * Driver for Solarflare Solarstorm network controllers and boards 3 * Copyright 2007-2008 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 "net_driver.h" 11#include "phy.h" 12#include "boards.h" 13#include "efx.h" 14#include "workarounds.h" 15 16/* Macros for unpacking the board revision */ 17/* The revision info is in host byte order. */ 18#define BOARD_TYPE(_rev) (_rev >> 8) 19#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf) 20#define BOARD_MINOR(_rev) (_rev & 0xf) 21 22/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */ 23#define BLINK_INTERVAL (HZ/2) 24 25static void blink_led_timer(unsigned long context) 26{ 27 struct efx_nic *efx = (struct efx_nic *)context; 28 struct efx_blinker *bl = &efx->board_info.blinker; 29 efx->board_info.set_id_led(efx, bl->state); 30 bl->state = !bl->state; 31 if (bl->resubmit) 32 mod_timer(&bl->timer, jiffies + BLINK_INTERVAL); 33} 34 35static void board_blink(struct efx_nic *efx, bool blink) 36{ 37 struct efx_blinker *blinker = &efx->board_info.blinker; 38 39 /* The rtnl mutex serialises all ethtool ioctls, so 40 * nothing special needs doing here. */ 41 if (blink) { 42 blinker->resubmit = true; 43 blinker->state = false; 44 setup_timer(&blinker->timer, blink_led_timer, 45 (unsigned long)efx); 46 mod_timer(&blinker->timer, jiffies + BLINK_INTERVAL); 47 } else { 48 blinker->resubmit = false; 49 if (blinker->timer.function) 50 del_timer_sync(&blinker->timer); 51 efx->board_info.init_leds(efx); 52 } 53} 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/***************************************************************************** 153 * Support for the SFE4002 154 * 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}; 176 177/****************************************************************************/ 178/* LED allocations. Note that on rev A0 boards the schematic and the reality 179 * differ: red and green are swapped. Below is the fixed (A1) layout (there 180 * are only 3 A0 boards in existence, so no real reason to make this 181 * conditional). 182 */ 183#define SFE4002_FAULT_LED (2) /* Red */ 184#define SFE4002_RX_LED (0) /* Green */ 185#define SFE4002_TX_LED (1) /* Amber */ 186 187static void sfe4002_init_leds(struct efx_nic *efx) 188{ 189 /* Set the TX and RX LEDs to reflect status and activity, and the 190 * fault LED off */ 191 xfp_set_led(efx, SFE4002_TX_LED, 192 QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT); 193 xfp_set_led(efx, SFE4002_RX_LED, 194 QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT); 195 xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF); 196} 197 198static void sfe4002_set_id_led(struct efx_nic *efx, bool state) 199{ 200 xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON : 201 QUAKE_LED_OFF); 202} 203 204static int sfe4002_check_hw(struct efx_nic *efx) 205{ 206 /* A0 board rev. 4002s report a temperature fault the whole time 207 * (bad sensor) so we mask it out. */ 208 unsigned alarm_mask = 209 (efx->board_info.major == 0 && efx->board_info.minor == 0) ? 210 ~LM87_ALARM_TEMP_EXT1 : ~0; 211 212 return efx_check_lm87(efx, alarm_mask); 213} 214 215static int sfe4002_init(struct efx_nic *efx) 216{ 217 int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); 218 if (rc) 219 return rc; 220 efx->board_info.monitor = sfe4002_check_hw; 221 efx->board_info.init_leds = sfe4002_init_leds; 222 efx->board_info.set_id_led = sfe4002_set_id_led; 223 efx->board_info.blink = board_blink; 224 efx->board_info.fini = efx_fini_lm87; 225 return 0; 226} 227 228/***************************************************************************** 229 * Support for the SFN4112F 230 * 231 */ 232static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */ 233 234static const u8 sfn4112f_lm87_regs[] = { 235 LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ 236 LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ 237 LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ 238 LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ 239 LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ 240 LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ 241 LM87_TEMP_INT_LIMITS(10, 60), /* board */ 242 LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ 243 0 244}; 245 246static struct i2c_board_info sfn4112f_hwmon_info = { 247 I2C_BOARD_INFO("lm87", 0x2e), 248 .platform_data = &sfn4112f_lm87_channel, 249}; 250 251#define SFN4112F_ACT_LED 0 252#define SFN4112F_LINK_LED 1 253 254static void sfn4112f_init_leds(struct efx_nic *efx) 255{ 256 xfp_set_led(efx, SFN4112F_ACT_LED, 257 QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT); 258 xfp_set_led(efx, SFN4112F_LINK_LED, 259 QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT); 260} 261 262static void sfn4112f_set_id_led(struct efx_nic *efx, bool state) 263{ 264 xfp_set_led(efx, SFN4112F_LINK_LED, 265 state ? QUAKE_LED_ON : QUAKE_LED_OFF); 266} 267 268static int sfn4112f_check_hw(struct efx_nic *efx) 269{ 270 /* Mask out unused sensors */ 271 return efx_check_lm87(efx, ~0x48); 272} 273 274static int sfn4112f_init(struct efx_nic *efx) 275{ 276 int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); 277 if (rc) 278 return rc; 279 efx->board_info.monitor = sfn4112f_check_hw; 280 efx->board_info.init_leds = sfn4112f_init_leds; 281 efx->board_info.set_id_led = sfn4112f_set_id_led; 282 efx->board_info.blink = board_blink; 283 efx->board_info.fini = efx_fini_lm87; 284 return 0; 285} 286 287/* This will get expanded as board-specific details get moved out of the 288 * PHY drivers. */ 289struct efx_board_data { 290 enum efx_board_type type; 291 const char *ref_model; 292 const char *gen_type; 293 int (*init) (struct efx_nic *nic); 294}; 295 296 297static struct efx_board_data board_data[] = { 298 { EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init }, 299 { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init }, 300 { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter", 301 sfn4111t_init }, 302 { EFX_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter", 303 sfn4112f_init }, 304}; 305 306void efx_set_board_info(struct efx_nic *efx, u16 revision_info) 307{ 308 struct efx_board_data *data = NULL; 309 int i; 310 311 efx->board_info.type = BOARD_TYPE(revision_info); 312 efx->board_info.major = BOARD_MAJOR(revision_info); 313 efx->board_info.minor = BOARD_MINOR(revision_info); 314 315 for (i = 0; i < ARRAY_SIZE(board_data); i++) 316 if (board_data[i].type == efx->board_info.type) 317 data = &board_data[i]; 318 319 if (data) { 320 EFX_INFO(efx, "board is %s rev %c%d\n", 321 (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) 322 ? data->ref_model : data->gen_type, 323 'A' + efx->board_info.major, efx->board_info.minor); 324 efx->board_info.init = data->init; 325 } else { 326 EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type); 327 } 328}