diff options
| -rw-r--r-- | drivers/net/ethernet/intel/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/Makefile | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.c | 137 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_82575.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_hw.h | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb.h | 29 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_hwmon.c | 242 | ||||
| -rw-r--r-- | drivers/net/ethernet/intel/igb/igb_main.c | 49 |
8 files changed, 469 insertions, 7 deletions
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index e8912f1b8442..21353f0fef63 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig | |||
| @@ -114,6 +114,17 @@ config IGB | |||
| 114 | To compile this driver as a module, choose M here. The module | 114 | To compile this driver as a module, choose M here. The module |
| 115 | will be called igb. | 115 | will be called igb. |
| 116 | 116 | ||
| 117 | config IGB_HWMON | ||
| 118 | bool "Intel(R) PCI-Express Gigabit adapters HWMON support" | ||
| 119 | default y | ||
| 120 | depends on IGB && HWMON && !(IGB=y && HWMON=m) | ||
| 121 | ---help--- | ||
| 122 | Say Y if you want to expose thermal sensor data on Intel devices. | ||
| 123 | |||
| 124 | Some of our devices contain thermal sensors, both external and internal. | ||
| 125 | This data is available via the hwmon sysfs interface and exposes | ||
| 126 | the onboard sensors. | ||
| 127 | |||
| 117 | config IGB_DCA | 128 | config IGB_DCA |
| 118 | bool "Direct Cache Access (DCA) Support" | 129 | bool "Direct Cache Access (DCA) Support" |
| 119 | default y | 130 | default y |
diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile index 624476cfa727..f9d37c809885 100644 --- a/drivers/net/ethernet/intel/igb/Makefile +++ b/drivers/net/ethernet/intel/igb/Makefile | |||
| @@ -34,4 +34,4 @@ obj-$(CONFIG_IGB) += igb.o | |||
| 34 | 34 | ||
| 35 | igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \ | 35 | igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \ |
| 36 | e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \ | 36 | e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \ |
| 37 | e1000_i210.o igb_ptp.o | 37 | e1000_i210.o igb_ptp.o igb_hwmon.o |
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 51e3f4f9b530..b6ec782156bb 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c | |||
| @@ -2303,12 +2303,149 @@ out: | |||
| 2303 | return ret_val; | 2303 | return ret_val; |
| 2304 | } | 2304 | } |
| 2305 | 2305 | ||
| 2306 | static const u8 e1000_emc_temp_data[4] = { | ||
| 2307 | E1000_EMC_INTERNAL_DATA, | ||
| 2308 | E1000_EMC_DIODE1_DATA, | ||
| 2309 | E1000_EMC_DIODE2_DATA, | ||
| 2310 | E1000_EMC_DIODE3_DATA | ||
| 2311 | }; | ||
| 2312 | static const u8 e1000_emc_therm_limit[4] = { | ||
| 2313 | E1000_EMC_INTERNAL_THERM_LIMIT, | ||
| 2314 | E1000_EMC_DIODE1_THERM_LIMIT, | ||
| 2315 | E1000_EMC_DIODE2_THERM_LIMIT, | ||
| 2316 | E1000_EMC_DIODE3_THERM_LIMIT | ||
| 2317 | }; | ||
| 2318 | |||
| 2319 | /* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data | ||
| 2320 | * @hw: pointer to hardware structure | ||
| 2321 | * | ||
| 2322 | * Updates the temperatures in mac.thermal_sensor_data | ||
| 2323 | */ | ||
| 2324 | s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw) | ||
| 2325 | { | ||
| 2326 | s32 status = E1000_SUCCESS; | ||
| 2327 | u16 ets_offset; | ||
| 2328 | u16 ets_cfg; | ||
| 2329 | u16 ets_sensor; | ||
| 2330 | u8 num_sensors; | ||
| 2331 | u8 sensor_index; | ||
| 2332 | u8 sensor_location; | ||
| 2333 | u8 i; | ||
| 2334 | struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; | ||
| 2335 | |||
| 2336 | if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0)) | ||
| 2337 | return E1000_NOT_IMPLEMENTED; | ||
| 2338 | |||
| 2339 | data->sensor[0].temp = (rd32(E1000_THMJT) & 0xFF); | ||
| 2340 | |||
| 2341 | /* Return the internal sensor only if ETS is unsupported */ | ||
| 2342 | hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset); | ||
| 2343 | if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF)) | ||
| 2344 | return status; | ||
| 2345 | |||
| 2346 | hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg); | ||
| 2347 | if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT) | ||
| 2348 | != NVM_ETS_TYPE_EMC) | ||
| 2349 | return E1000_NOT_IMPLEMENTED; | ||
| 2350 | |||
| 2351 | num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK); | ||
| 2352 | if (num_sensors > E1000_MAX_SENSORS) | ||
| 2353 | num_sensors = E1000_MAX_SENSORS; | ||
| 2354 | |||
| 2355 | for (i = 1; i < num_sensors; i++) { | ||
| 2356 | hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor); | ||
| 2357 | sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >> | ||
| 2358 | NVM_ETS_DATA_INDEX_SHIFT); | ||
| 2359 | sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >> | ||
| 2360 | NVM_ETS_DATA_LOC_SHIFT); | ||
| 2361 | |||
| 2362 | if (sensor_location != 0) | ||
| 2363 | hw->phy.ops.read_i2c_byte(hw, | ||
| 2364 | e1000_emc_temp_data[sensor_index], | ||
| 2365 | E1000_I2C_THERMAL_SENSOR_ADDR, | ||
| 2366 | &data->sensor[i].temp); | ||
| 2367 | } | ||
| 2368 | return status; | ||
| 2369 | } | ||
| 2370 | |||
| 2371 | /* igb_init_thermal_sensor_thresh_generic - Sets thermal sensor thresholds | ||
| 2372 | * @hw: pointer to hardware structure | ||
| 2373 | * | ||
| 2374 | * Sets the thermal sensor thresholds according to the NVM map | ||
| 2375 | * and save off the threshold and location values into mac.thermal_sensor_data | ||
| 2376 | */ | ||
| 2377 | s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw) | ||
| 2378 | { | ||
| 2379 | s32 status = E1000_SUCCESS; | ||
| 2380 | u16 ets_offset; | ||
| 2381 | u16 ets_cfg; | ||
| 2382 | u16 ets_sensor; | ||
| 2383 | u8 low_thresh_delta; | ||
| 2384 | u8 num_sensors; | ||
| 2385 | u8 sensor_index; | ||
| 2386 | u8 sensor_location; | ||
| 2387 | u8 therm_limit; | ||
| 2388 | u8 i; | ||
| 2389 | struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data; | ||
| 2390 | |||
| 2391 | if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0)) | ||
| 2392 | return E1000_NOT_IMPLEMENTED; | ||
| 2393 | |||
| 2394 | memset(data, 0, sizeof(struct e1000_thermal_sensor_data)); | ||
| 2395 | |||
| 2396 | data->sensor[0].location = 0x1; | ||
| 2397 | data->sensor[0].caution_thresh = | ||
| 2398 | (rd32(E1000_THHIGHTC) & 0xFF); | ||
| 2399 | data->sensor[0].max_op_thresh = | ||
| 2400 | (rd32(E1000_THLOWTC) & 0xFF); | ||
| 2401 | |||
| 2402 | /* Return the internal sensor only if ETS is unsupported */ | ||
| 2403 | hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset); | ||
| 2404 | if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF)) | ||
| 2405 | return status; | ||
| 2406 | |||
| 2407 | hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg); | ||
| 2408 | if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT) | ||
| 2409 | != NVM_ETS_TYPE_EMC) | ||
| 2410 | return E1000_NOT_IMPLEMENTED; | ||
| 2411 | |||
| 2412 | low_thresh_delta = ((ets_cfg & NVM_ETS_LTHRES_DELTA_MASK) >> | ||
| 2413 | NVM_ETS_LTHRES_DELTA_SHIFT); | ||
| 2414 | num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK); | ||
| 2415 | |||
| 2416 | for (i = 1; i <= num_sensors; i++) { | ||
| 2417 | hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor); | ||
| 2418 | sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >> | ||
| 2419 | NVM_ETS_DATA_INDEX_SHIFT); | ||
| 2420 | sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >> | ||
| 2421 | NVM_ETS_DATA_LOC_SHIFT); | ||
| 2422 | therm_limit = ets_sensor & NVM_ETS_DATA_HTHRESH_MASK; | ||
| 2423 | |||
| 2424 | hw->phy.ops.write_i2c_byte(hw, | ||
| 2425 | e1000_emc_therm_limit[sensor_index], | ||
| 2426 | E1000_I2C_THERMAL_SENSOR_ADDR, | ||
| 2427 | therm_limit); | ||
| 2428 | |||
| 2429 | if ((i < E1000_MAX_SENSORS) && (sensor_location != 0)) { | ||
| 2430 | data->sensor[i].location = sensor_location; | ||
| 2431 | data->sensor[i].caution_thresh = therm_limit; | ||
| 2432 | data->sensor[i].max_op_thresh = therm_limit - | ||
| 2433 | low_thresh_delta; | ||
| 2434 | } | ||
| 2435 | } | ||
| 2436 | return status; | ||
| 2437 | } | ||
| 2438 | |||
| 2306 | static struct e1000_mac_operations e1000_mac_ops_82575 = { | 2439 | static struct e1000_mac_operations e1000_mac_ops_82575 = { |
| 2307 | .init_hw = igb_init_hw_82575, | 2440 | .init_hw = igb_init_hw_82575, |
| 2308 | .check_for_link = igb_check_for_link_82575, | 2441 | .check_for_link = igb_check_for_link_82575, |
| 2309 | .rar_set = igb_rar_set, | 2442 | .rar_set = igb_rar_set, |
| 2310 | .read_mac_addr = igb_read_mac_addr_82575, | 2443 | .read_mac_addr = igb_read_mac_addr_82575, |
| 2311 | .get_speed_and_duplex = igb_get_speed_and_duplex_copper, | 2444 | .get_speed_and_duplex = igb_get_speed_and_duplex_copper, |
| 2445 | #ifdef CONFIG_IGB_HWMON | ||
| 2446 | .get_thermal_sensor_data = igb_get_thermal_sensor_data_generic, | ||
| 2447 | .init_thermal_sensor_thresh = igb_init_thermal_sensor_thresh_generic, | ||
| 2448 | #endif | ||
| 2312 | }; | 2449 | }; |
| 2313 | 2450 | ||
| 2314 | static struct e1000_phy_operations e1000_phy_ops_82575 = { | 2451 | static struct e1000_phy_operations e1000_phy_ops_82575 = { |
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index caf6abf9abef..444f6f521da7 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h | |||
| @@ -264,6 +264,8 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool); | |||
| 264 | void igb_vmdq_set_replication_pf(struct e1000_hw *, bool); | 264 | void igb_vmdq_set_replication_pf(struct e1000_hw *, bool); |
| 265 | u16 igb_rxpbs_adjust_82580(u32 data); | 265 | u16 igb_rxpbs_adjust_82580(u32 data); |
| 266 | s32 igb_set_eee_i350(struct e1000_hw *); | 266 | s32 igb_set_eee_i350(struct e1000_hw *); |
| 267 | s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *); | ||
| 268 | s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw); | ||
| 267 | 269 | ||
| 268 | #define E1000_I2C_THERMAL_SENSOR_ADDR 0xF8 | 270 | #define E1000_I2C_THERMAL_SENSOR_ADDR 0xF8 |
| 269 | #define E1000_EMC_INTERNAL_DATA 0x00 | 271 | #define E1000_EMC_INTERNAL_DATA 0x00 |
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index 837a274b7461..2c9b6f40e21c 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h | |||
| @@ -325,6 +325,10 @@ struct e1000_mac_operations { | |||
| 325 | s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); | 325 | s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); |
| 326 | s32 (*acquire_swfw_sync)(struct e1000_hw *, u16); | 326 | s32 (*acquire_swfw_sync)(struct e1000_hw *, u16); |
| 327 | void (*release_swfw_sync)(struct e1000_hw *, u16); | 327 | void (*release_swfw_sync)(struct e1000_hw *, u16); |
| 328 | #ifdef CONFIG_IGB_HWMON | ||
| 329 | s32 (*get_thermal_sensor_data)(struct e1000_hw *); | ||
| 330 | s32 (*init_thermal_sensor_thresh)(struct e1000_hw *); | ||
| 331 | #endif | ||
| 328 | 332 | ||
| 329 | }; | 333 | }; |
| 330 | 334 | ||
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index 9f1af1b232d5..8372c002102c 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h | |||
| @@ -308,6 +308,27 @@ struct igb_i2c_client_list { | |||
| 308 | struct igb_i2c_client_list *next; | 308 | struct igb_i2c_client_list *next; |
| 309 | }; | 309 | }; |
| 310 | 310 | ||
| 311 | #ifdef CONFIG_IGB_HWMON | ||
| 312 | |||
| 313 | #define IGB_HWMON_TYPE_LOC 0 | ||
| 314 | #define IGB_HWMON_TYPE_TEMP 1 | ||
| 315 | #define IGB_HWMON_TYPE_CAUTION 2 | ||
| 316 | #define IGB_HWMON_TYPE_MAX 3 | ||
| 317 | |||
| 318 | struct hwmon_attr { | ||
| 319 | struct device_attribute dev_attr; | ||
| 320 | struct e1000_hw *hw; | ||
| 321 | struct e1000_thermal_diode_data *sensor; | ||
| 322 | char name[12]; | ||
| 323 | }; | ||
| 324 | |||
| 325 | struct hwmon_buff { | ||
| 326 | struct device *device; | ||
| 327 | struct hwmon_attr *hwmon_list; | ||
| 328 | unsigned int n_hwmon; | ||
| 329 | }; | ||
| 330 | #endif | ||
| 331 | |||
| 311 | /* board specific private data structure */ | 332 | /* board specific private data structure */ |
| 312 | struct igb_adapter { | 333 | struct igb_adapter { |
| 313 | unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; | 334 | unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; |
| @@ -398,6 +419,10 @@ struct igb_adapter { | |||
| 398 | struct timecounter tc; | 419 | struct timecounter tc; |
| 399 | 420 | ||
| 400 | char fw_version[32]; | 421 | char fw_version[32]; |
| 422 | #ifdef CONFIG_IGB_HWMON | ||
| 423 | struct hwmon_buff igb_hwmon_buff; | ||
| 424 | bool ets; | ||
| 425 | #endif | ||
| 401 | struct i2c_algo_bit_data i2c_algo; | 426 | struct i2c_algo_bit_data i2c_algo; |
| 402 | struct i2c_adapter i2c_adap; | 427 | struct i2c_adapter i2c_adap; |
| 403 | struct igb_i2c_client_list *i2c_clients; | 428 | struct igb_i2c_client_list *i2c_clients; |
| @@ -476,6 +501,10 @@ static inline void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector, | |||
| 476 | 501 | ||
| 477 | extern int igb_ptp_hwtstamp_ioctl(struct net_device *netdev, | 502 | extern int igb_ptp_hwtstamp_ioctl(struct net_device *netdev, |
| 478 | struct ifreq *ifr, int cmd); | 503 | struct ifreq *ifr, int cmd); |
| 504 | #ifdef CONFIG_IGB_HWMON | ||
| 505 | extern void igb_sysfs_exit(struct igb_adapter *adapter); | ||
| 506 | extern int igb_sysfs_init(struct igb_adapter *adapter); | ||
| 507 | #endif | ||
| 479 | static inline s32 igb_reset_phy(struct e1000_hw *hw) | 508 | static inline s32 igb_reset_phy(struct e1000_hw *hw) |
| 480 | { | 509 | { |
| 481 | if (hw->phy.ops.reset) | 510 | if (hw->phy.ops.reset) |
diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c new file mode 100644 index 000000000000..106bd7c29bc9 --- /dev/null +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c | |||
| @@ -0,0 +1,242 @@ | |||
| 1 | /******************************************************************************* | ||
| 2 | |||
| 3 | Intel(R) Gigabit Ethernet Linux driver | ||
| 4 | Copyright(c) 2007-2012 Intel Corporation. | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify it | ||
| 7 | under the terms and conditions of the GNU General Public License, | ||
| 8 | version 2, as published by the Free Software Foundation. | ||
| 9 | |||
| 10 | This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License along with | ||
| 16 | this program; if not, write to the Free Software Foundation, Inc., | ||
| 17 | 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | |||
| 19 | The full GNU General Public License is included in this distribution in | ||
| 20 | the file called "COPYING". | ||
| 21 | |||
| 22 | Contact Information: | ||
| 23 | e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
| 24 | Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
| 25 | |||
| 26 | *******************************************************************************/ | ||
| 27 | |||
| 28 | #include "igb.h" | ||
| 29 | #include "e1000_82575.h" | ||
| 30 | #include "e1000_hw.h" | ||
| 31 | |||
| 32 | #include <linux/module.h> | ||
| 33 | #include <linux/types.h> | ||
| 34 | #include <linux/sysfs.h> | ||
| 35 | #include <linux/kobject.h> | ||
| 36 | #include <linux/device.h> | ||
| 37 | #include <linux/netdevice.h> | ||
| 38 | #include <linux/hwmon.h> | ||
| 39 | #include <linux/pci.h> | ||
| 40 | |||
| 41 | #ifdef CONFIG_IGB_HWMON | ||
| 42 | /* hwmon callback functions */ | ||
| 43 | static ssize_t igb_hwmon_show_location(struct device *dev, | ||
| 44 | struct device_attribute *attr, | ||
| 45 | char *buf) | ||
| 46 | { | ||
| 47 | struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr, | ||
| 48 | dev_attr); | ||
| 49 | return sprintf(buf, "loc%u\n", | ||
| 50 | igb_attr->sensor->location); | ||
| 51 | } | ||
| 52 | |||
| 53 | static ssize_t igb_hwmon_show_temp(struct device *dev, | ||
| 54 | struct device_attribute *attr, | ||
| 55 | char *buf) | ||
| 56 | { | ||
| 57 | struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr, | ||
| 58 | dev_attr); | ||
| 59 | unsigned int value; | ||
| 60 | |||
| 61 | /* reset the temp field */ | ||
| 62 | igb_attr->hw->mac.ops.get_thermal_sensor_data(igb_attr->hw); | ||
| 63 | |||
| 64 | value = igb_attr->sensor->temp; | ||
| 65 | |||
| 66 | /* display millidegree */ | ||
| 67 | value *= 1000; | ||
| 68 | |||
| 69 | return sprintf(buf, "%u\n", value); | ||
| 70 | } | ||
| 71 | |||
| 72 | static ssize_t igb_hwmon_show_cautionthresh(struct device *dev, | ||
| 73 | struct device_attribute *attr, | ||
| 74 | char *buf) | ||
| 75 | { | ||
| 76 | struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr, | ||
| 77 | dev_attr); | ||
| 78 | unsigned int value = igb_attr->sensor->caution_thresh; | ||
| 79 | |||
| 80 | /* display millidegree */ | ||
| 81 | value *= 1000; | ||
| 82 | |||
| 83 | return sprintf(buf, "%u\n", value); | ||
| 84 | } | ||
| 85 | |||
| 86 | static ssize_t igb_hwmon_show_maxopthresh(struct device *dev, | ||
| 87 | struct device_attribute *attr, | ||
| 88 | char *buf) | ||
| 89 | { | ||
| 90 | struct hwmon_attr *igb_attr = container_of(attr, struct hwmon_attr, | ||
| 91 | dev_attr); | ||
| 92 | unsigned int value = igb_attr->sensor->max_op_thresh; | ||
| 93 | |||
| 94 | /* display millidegree */ | ||
| 95 | value *= 1000; | ||
| 96 | |||
| 97 | return sprintf(buf, "%u\n", value); | ||
| 98 | } | ||
| 99 | |||
| 100 | /* igb_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file. | ||
| 101 | * @ adapter: pointer to the adapter structure | ||
| 102 | * @ offset: offset in the eeprom sensor data table | ||
| 103 | * @ type: type of sensor data to display | ||
| 104 | * | ||
| 105 | * For each file we want in hwmon's sysfs interface we need a device_attribute | ||
| 106 | * This is included in our hwmon_attr struct that contains the references to | ||
| 107 | * the data structures we need to get the data to display. | ||
| 108 | */ | ||
| 109 | static int igb_add_hwmon_attr(struct igb_adapter *adapter, | ||
| 110 | unsigned int offset, int type) { | ||
| 111 | int rc; | ||
| 112 | unsigned int n_attr; | ||
| 113 | struct hwmon_attr *igb_attr; | ||
| 114 | |||
| 115 | n_attr = adapter->igb_hwmon_buff.n_hwmon; | ||
| 116 | igb_attr = &adapter->igb_hwmon_buff.hwmon_list[n_attr]; | ||
| 117 | |||
| 118 | switch (type) { | ||
| 119 | case IGB_HWMON_TYPE_LOC: | ||
| 120 | igb_attr->dev_attr.show = igb_hwmon_show_location; | ||
| 121 | snprintf(igb_attr->name, sizeof(igb_attr->name), | ||
| 122 | "temp%u_label", offset); | ||
| 123 | break; | ||
| 124 | case IGB_HWMON_TYPE_TEMP: | ||
| 125 | igb_attr->dev_attr.show = igb_hwmon_show_temp; | ||
| 126 | snprintf(igb_attr->name, sizeof(igb_attr->name), | ||
| 127 | "temp%u_input", offset); | ||
| 128 | break; | ||
| 129 | case IGB_HWMON_TYPE_CAUTION: | ||
| 130 | igb_attr->dev_attr.show = igb_hwmon_show_cautionthresh; | ||
| 131 | snprintf(igb_attr->name, sizeof(igb_attr->name), | ||
| 132 | "temp%u_max", offset); | ||
| 133 | break; | ||
| 134 | case IGB_HWMON_TYPE_MAX: | ||
| 135 | igb_attr->dev_attr.show = igb_hwmon_show_maxopthresh; | ||
| 136 | snprintf(igb_attr->name, sizeof(igb_attr->name), | ||
| 137 | "temp%u_crit", offset); | ||
| 138 | break; | ||
| 139 | default: | ||
| 140 | rc = -EPERM; | ||
| 141 | return rc; | ||
| 142 | } | ||
| 143 | |||
| 144 | /* These always the same regardless of type */ | ||
| 145 | igb_attr->sensor = | ||
| 146 | &adapter->hw.mac.thermal_sensor_data.sensor[offset]; | ||
| 147 | igb_attr->hw = &adapter->hw; | ||
| 148 | igb_attr->dev_attr.store = NULL; | ||
| 149 | igb_attr->dev_attr.attr.mode = S_IRUGO; | ||
| 150 | igb_attr->dev_attr.attr.name = igb_attr->name; | ||
| 151 | sysfs_attr_init(&igb_attr->dev_attr.attr); | ||
| 152 | rc = device_create_file(&adapter->pdev->dev, | ||
| 153 | &igb_attr->dev_attr); | ||
| 154 | if (rc == 0) | ||
| 155 | ++adapter->igb_hwmon_buff.n_hwmon; | ||
| 156 | |||
| 157 | return rc; | ||
| 158 | } | ||
| 159 | |||
| 160 | static void igb_sysfs_del_adapter(struct igb_adapter *adapter) | ||
| 161 | { | ||
| 162 | int i; | ||
| 163 | |||
| 164 | if (adapter == NULL) | ||
| 165 | return; | ||
| 166 | |||
| 167 | for (i = 0; i < adapter->igb_hwmon_buff.n_hwmon; i++) { | ||
| 168 | device_remove_file(&adapter->pdev->dev, | ||
| 169 | &adapter->igb_hwmon_buff.hwmon_list[i].dev_attr); | ||
| 170 | } | ||
| 171 | |||
| 172 | kfree(adapter->igb_hwmon_buff.hwmon_list); | ||
| 173 | |||
| 174 | if (adapter->igb_hwmon_buff.device) | ||
| 175 | hwmon_device_unregister(adapter->igb_hwmon_buff.device); | ||
| 176 | } | ||
| 177 | |||
| 178 | /* called from igb_main.c */ | ||
| 179 | void igb_sysfs_exit(struct igb_adapter *adapter) | ||
| 180 | { | ||
| 181 | igb_sysfs_del_adapter(adapter); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* called from igb_main.c */ | ||
| 185 | int igb_sysfs_init(struct igb_adapter *adapter) | ||
| 186 | { | ||
| 187 | struct hwmon_buff *igb_hwmon = &adapter->igb_hwmon_buff; | ||
| 188 | unsigned int i; | ||
| 189 | int n_attrs; | ||
| 190 | int rc = 0; | ||
| 191 | |||
| 192 | /* If this method isn't defined we don't support thermals */ | ||
| 193 | if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) | ||
| 194 | goto exit; | ||
| 195 | |||
| 196 | /* Don't create thermal hwmon interface if no sensors present */ | ||
| 197 | rc = (adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw)); | ||
| 198 | if (rc) | ||
| 199 | goto exit; | ||
| 200 | |||
| 201 | /* Allocation space for max attributes | ||
| 202 | * max num sensors * values (loc, temp, max, caution) | ||
| 203 | */ | ||
| 204 | n_attrs = E1000_MAX_SENSORS * 4; | ||
| 205 | igb_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr), | ||
| 206 | GFP_KERNEL); | ||
| 207 | if (!igb_hwmon->hwmon_list) { | ||
| 208 | rc = -ENOMEM; | ||
| 209 | goto err; | ||
| 210 | } | ||
| 211 | |||
| 212 | igb_hwmon->device = hwmon_device_register(&adapter->pdev->dev); | ||
| 213 | if (IS_ERR(igb_hwmon->device)) { | ||
| 214 | rc = PTR_ERR(igb_hwmon->device); | ||
| 215 | goto err; | ||
| 216 | } | ||
| 217 | |||
| 218 | for (i = 0; i < E1000_MAX_SENSORS; i++) { | ||
| 219 | |||
| 220 | /* Only create hwmon sysfs entries for sensors that have | ||
| 221 | * meaningful data. | ||
| 222 | */ | ||
| 223 | if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0) | ||
| 224 | continue; | ||
| 225 | |||
| 226 | /* Bail if any hwmon attr struct fails to initialize */ | ||
| 227 | rc = igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_CAUTION); | ||
| 228 | rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_LOC); | ||
| 229 | rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_TEMP); | ||
| 230 | rc |= igb_add_hwmon_attr(adapter, i, IGB_HWMON_TYPE_MAX); | ||
| 231 | if (rc) | ||
| 232 | goto err; | ||
| 233 | } | ||
| 234 | |||
| 235 | goto exit; | ||
| 236 | |||
| 237 | err: | ||
| 238 | igb_sysfs_del_adapter(adapter); | ||
| 239 | exit: | ||
| 240 | return rc; | ||
| 241 | } | ||
| 242 | #endif | ||
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 0173b6118424..a9cb84a76e49 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c | |||
| @@ -1796,6 +1796,18 @@ void igb_reset(struct igb_adapter *adapter) | |||
| 1796 | igb_force_mac_fc(hw); | 1796 | igb_force_mac_fc(hw); |
| 1797 | 1797 | ||
| 1798 | igb_init_dmac(adapter, pba); | 1798 | igb_init_dmac(adapter, pba); |
| 1799 | #ifdef CONFIG_IGB_HWMON | ||
| 1800 | /* Re-initialize the thermal sensor on i350 devices. */ | ||
| 1801 | if (!test_bit(__IGB_DOWN, &adapter->state)) { | ||
| 1802 | if (mac->type == e1000_i350 && hw->bus.func == 0) { | ||
| 1803 | /* If present, re-initialize the external thermal sensor | ||
| 1804 | * interface. | ||
| 1805 | */ | ||
| 1806 | if (adapter->ets) | ||
| 1807 | mac->ops.init_thermal_sensor_thresh(hw); | ||
| 1808 | } | ||
| 1809 | } | ||
| 1810 | #endif | ||
| 1799 | if (!netif_running(adapter->netdev)) | 1811 | if (!netif_running(adapter->netdev)) |
| 1800 | igb_power_down_link(adapter); | 1812 | igb_power_down_link(adapter); |
| 1801 | 1813 | ||
| @@ -2260,7 +2272,27 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 2260 | } | 2272 | } |
| 2261 | 2273 | ||
| 2262 | #endif | 2274 | #endif |
| 2275 | #ifdef CONFIG_IGB_HWMON | ||
| 2276 | /* Initialize the thermal sensor on i350 devices. */ | ||
| 2277 | if (hw->mac.type == e1000_i350 && hw->bus.func == 0) { | ||
| 2278 | u16 ets_word; | ||
| 2263 | 2279 | ||
| 2280 | /* | ||
| 2281 | * Read the NVM to determine if this i350 device supports an | ||
| 2282 | * external thermal sensor. | ||
| 2283 | */ | ||
| 2284 | hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_word); | ||
| 2285 | if (ets_word != 0x0000 && ets_word != 0xFFFF) | ||
| 2286 | adapter->ets = true; | ||
| 2287 | else | ||
| 2288 | adapter->ets = false; | ||
| 2289 | if (igb_sysfs_init(adapter)) | ||
| 2290 | dev_err(&pdev->dev, | ||
| 2291 | "failed to allocate sysfs resources\n"); | ||
| 2292 | } else { | ||
| 2293 | adapter->ets = false; | ||
| 2294 | } | ||
| 2295 | #endif | ||
| 2264 | /* do hw tstamp init after resetting */ | 2296 | /* do hw tstamp init after resetting */ |
| 2265 | igb_ptp_init(adapter); | 2297 | igb_ptp_init(adapter); |
| 2266 | 2298 | ||
| @@ -2443,10 +2475,11 @@ static void igb_remove(struct pci_dev *pdev) | |||
| 2443 | struct e1000_hw *hw = &adapter->hw; | 2475 | struct e1000_hw *hw = &adapter->hw; |
| 2444 | 2476 | ||
| 2445 | pm_runtime_get_noresume(&pdev->dev); | 2477 | pm_runtime_get_noresume(&pdev->dev); |
| 2478 | #ifdef CONFIG_IGB_HWMON | ||
| 2479 | igb_sysfs_exit(adapter); | ||
| 2480 | #endif | ||
| 2446 | igb_remove_i2c(adapter); | 2481 | igb_remove_i2c(adapter); |
| 2447 | |||
| 2448 | igb_ptp_stop(adapter); | 2482 | igb_ptp_stop(adapter); |
| 2449 | |||
| 2450 | /* | 2483 | /* |
| 2451 | * The watchdog timer may be rescheduled, so explicitly | 2484 | * The watchdog timer may be rescheduled, so explicitly |
| 2452 | * disable watchdog from being rescheduled. | 2485 | * disable watchdog from being rescheduled. |
| @@ -7594,7 +7627,12 @@ igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr) | |||
| 7594 | } | 7627 | } |
| 7595 | } | 7628 | } |
| 7596 | 7629 | ||
| 7597 | /* no client_list found, create a new one */ | 7630 | /* no client_list found, create a new one as long as |
| 7631 | * irqs are not disabled | ||
| 7632 | */ | ||
| 7633 | if (unlikely(irqs_disabled())) | ||
| 7634 | goto exit; | ||
| 7635 | |||
| 7598 | client_list = kzalloc(sizeof(*client_list), GFP_KERNEL); | 7636 | client_list = kzalloc(sizeof(*client_list), GFP_KERNEL); |
| 7599 | if (client_list == NULL) | 7637 | if (client_list == NULL) |
| 7600 | goto exit; | 7638 | goto exit; |
| @@ -7606,7 +7644,8 @@ igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr) | |||
| 7606 | client_info.platform_data = adapter; | 7644 | client_info.platform_data = adapter; |
| 7607 | client_list->client = i2c_new_device(&adapter->i2c_adap, &client_info); | 7645 | client_list->client = i2c_new_device(&adapter->i2c_adap, &client_info); |
| 7608 | if (client_list->client == NULL) { | 7646 | if (client_list->client == NULL) { |
| 7609 | dev_info(&adapter->pdev->dev, "Failed to create new i2c device..\n"); | 7647 | dev_info(&adapter->pdev->dev, |
| 7648 | "Failed to create new i2c device..\n"); | ||
| 7610 | goto err_no_client; | 7649 | goto err_no_client; |
| 7611 | } | 7650 | } |
| 7612 | 7651 | ||
| @@ -7614,8 +7653,6 @@ igb_get_i2c_client(struct igb_adapter *adapter, u8 dev_addr) | |||
| 7614 | client_list->next = adapter->i2c_clients; | 7653 | client_list->next = adapter->i2c_clients; |
| 7615 | adapter->i2c_clients = client_list; | 7654 | adapter->i2c_clients = client_list; |
| 7616 | 7655 | ||
| 7617 | spin_unlock_irqrestore(&i2c_clients_lock, flags); | ||
| 7618 | |||
| 7619 | client = client_list->client; | 7656 | client = client_list->client; |
| 7620 | goto exit; | 7657 | goto exit; |
| 7621 | 7658 | ||
