Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e428893b authored by Carolyn Wyborny's avatar Carolyn Wyborny Committed by Jeff Kirsher
Browse files

igb: Enable hwmon data output for thermal sensors via I2C.



Some of our adapters have internal sensors that report thermal data.  This
patch enables reporting of that data via sysfs.

Signed-off-by: default avatarCarolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent aca5dae8
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -114,6 +114,17 @@ config IGB
	  To compile this driver as a module, choose M here. The module
	  will be called igb.

config IGB_HWMON
	bool "Intel(R) PCI-Express Gigabit adapters HWMON support"
	default y
	depends on IGB && HWMON && !(IGB=y && HWMON=m)
	---help---
	  Say Y if you want to expose thermal sensor data on Intel devices.

	  Some of our devices contain thermal sensors, both external and internal.
	  This data is available via the hwmon sysfs interface and exposes
	  the onboard sensors.

config IGB_DCA
	bool "Direct Cache Access (DCA) Support"
	default y
+1 −1
Original line number Diff line number Diff line
@@ -34,4 +34,4 @@ obj-$(CONFIG_IGB) += igb.o

igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
	    e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
	    e1000_i210.o igb_ptp.o
	    e1000_i210.o igb_ptp.o igb_hwmon.o
+137 −0
Original line number Diff line number Diff line
@@ -2303,12 +2303,149 @@ s32 igb_set_eee_i350(struct e1000_hw *hw)
	return ret_val;
}

static const u8 e1000_emc_temp_data[4] = {
	E1000_EMC_INTERNAL_DATA,
	E1000_EMC_DIODE1_DATA,
	E1000_EMC_DIODE2_DATA,
	E1000_EMC_DIODE3_DATA
};
static const u8 e1000_emc_therm_limit[4] = {
	E1000_EMC_INTERNAL_THERM_LIMIT,
	E1000_EMC_DIODE1_THERM_LIMIT,
	E1000_EMC_DIODE2_THERM_LIMIT,
	E1000_EMC_DIODE3_THERM_LIMIT
};

/* igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
 *  @hw: pointer to hardware structure
 *
 *  Updates the temperatures in mac.thermal_sensor_data
 */
s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
{
	s32 status = E1000_SUCCESS;
	u16 ets_offset;
	u16 ets_cfg;
	u16 ets_sensor;
	u8  num_sensors;
	u8  sensor_index;
	u8  sensor_location;
	u8  i;
	struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;

	if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
		return E1000_NOT_IMPLEMENTED;

	data->sensor[0].temp = (rd32(E1000_THMJT) & 0xFF);

	/* Return the internal sensor only if ETS is unsupported */
	hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
	if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
		return status;

	hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
	if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
	    != NVM_ETS_TYPE_EMC)
		return E1000_NOT_IMPLEMENTED;

	num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);
	if (num_sensors > E1000_MAX_SENSORS)
		num_sensors = E1000_MAX_SENSORS;

	for (i = 1; i < num_sensors; i++) {
		hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
		sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
				NVM_ETS_DATA_INDEX_SHIFT);
		sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
				   NVM_ETS_DATA_LOC_SHIFT);

		if (sensor_location != 0)
			hw->phy.ops.read_i2c_byte(hw,
					e1000_emc_temp_data[sensor_index],
					E1000_I2C_THERMAL_SENSOR_ADDR,
					&data->sensor[i].temp);
	}
	return status;
}

/* igb_init_thermal_sensor_thresh_generic - Sets thermal sensor thresholds
 *  @hw: pointer to hardware structure
 *
 *  Sets the thermal sensor thresholds according to the NVM map
 *  and save off the threshold and location values into mac.thermal_sensor_data
 */
s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
{
	s32 status = E1000_SUCCESS;
	u16 ets_offset;
	u16 ets_cfg;
	u16 ets_sensor;
	u8  low_thresh_delta;
	u8  num_sensors;
	u8  sensor_index;
	u8  sensor_location;
	u8  therm_limit;
	u8  i;
	struct e1000_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;

	if ((hw->mac.type != e1000_i350) || (hw->bus.func != 0))
		return E1000_NOT_IMPLEMENTED;

	memset(data, 0, sizeof(struct e1000_thermal_sensor_data));

	data->sensor[0].location = 0x1;
	data->sensor[0].caution_thresh =
		(rd32(E1000_THHIGHTC) & 0xFF);
	data->sensor[0].max_op_thresh =
		(rd32(E1000_THLOWTC) & 0xFF);

	/* Return the internal sensor only if ETS is unsupported */
	hw->nvm.ops.read(hw, NVM_ETS_CFG, 1, &ets_offset);
	if ((ets_offset == 0x0000) || (ets_offset == 0xFFFF))
		return status;

	hw->nvm.ops.read(hw, ets_offset, 1, &ets_cfg);
	if (((ets_cfg & NVM_ETS_TYPE_MASK) >> NVM_ETS_TYPE_SHIFT)
	    != NVM_ETS_TYPE_EMC)
		return E1000_NOT_IMPLEMENTED;

	low_thresh_delta = ((ets_cfg & NVM_ETS_LTHRES_DELTA_MASK) >>
			    NVM_ETS_LTHRES_DELTA_SHIFT);
	num_sensors = (ets_cfg & NVM_ETS_NUM_SENSORS_MASK);

	for (i = 1; i <= num_sensors; i++) {
		hw->nvm.ops.read(hw, (ets_offset + i), 1, &ets_sensor);
		sensor_index = ((ets_sensor & NVM_ETS_DATA_INDEX_MASK) >>
				NVM_ETS_DATA_INDEX_SHIFT);
		sensor_location = ((ets_sensor & NVM_ETS_DATA_LOC_MASK) >>
				   NVM_ETS_DATA_LOC_SHIFT);
		therm_limit = ets_sensor & NVM_ETS_DATA_HTHRESH_MASK;

		hw->phy.ops.write_i2c_byte(hw,
			e1000_emc_therm_limit[sensor_index],
			E1000_I2C_THERMAL_SENSOR_ADDR,
			therm_limit);

		if ((i < E1000_MAX_SENSORS) && (sensor_location != 0)) {
			data->sensor[i].location = sensor_location;
			data->sensor[i].caution_thresh = therm_limit;
			data->sensor[i].max_op_thresh = therm_limit -
							low_thresh_delta;
		}
	}
	return status;
}

static struct e1000_mac_operations e1000_mac_ops_82575 = {
	.init_hw              = igb_init_hw_82575,
	.check_for_link       = igb_check_for_link_82575,
	.rar_set              = igb_rar_set,
	.read_mac_addr        = igb_read_mac_addr_82575,
	.get_speed_and_duplex = igb_get_speed_and_duplex_copper,
#ifdef CONFIG_IGB_HWMON
	.get_thermal_sensor_data = igb_get_thermal_sensor_data_generic,
	.init_thermal_sensor_thresh = igb_init_thermal_sensor_thresh_generic,
#endif
};

static struct e1000_phy_operations e1000_phy_ops_82575 = {
+2 −0
Original line number Diff line number Diff line
@@ -264,6 +264,8 @@ void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
u16 igb_rxpbs_adjust_82580(u32 data);
s32 igb_set_eee_i350(struct e1000_hw *);
s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *);
s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw);

#define E1000_I2C_THERMAL_SENSOR_ADDR	0xF8
#define E1000_EMC_INTERNAL_DATA		0x00
+4 −0
Original line number Diff line number Diff line
@@ -325,6 +325,10 @@ struct e1000_mac_operations {
	s32  (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *);
	s32  (*acquire_swfw_sync)(struct e1000_hw *, u16);
	void (*release_swfw_sync)(struct e1000_hw *, u16);
#ifdef CONFIG_IGB_HWMON
	s32 (*get_thermal_sensor_data)(struct e1000_hw *);
	s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
#endif

};

Loading