All of lore.kernel.org
 help / color / mirror / Atom feed
* [net-next 0/3][pull request] Intel Wired LAN Driver Update
@ 2012-04-05 10:47 Jeff Kirsher
  2012-04-05 10:47 ` [net-next 1/3] ixgbe: add support functions to access thermal data Jeff Kirsher
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Jeff Kirsher @ 2012-04-05 10:47 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann, bhutchings

This series of patches contains updates for ixgbe only.

This patch set is a refactor of previous patches that export data
requested by our customers.  The thermals are exposed via hwmon as
suggested by Michal Miroslaw and Ben Hutchings.  Modeled on how Ben
did for the Solarfare driver.  The other values are exported via
sysfs read only files.

The following are changes since commit 51c56b004e2c9a46207bb8a116589c2f84b92e5d:
  net: remove k{un}map_skb_frag()
and are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next master

Don Skidmore (3):
  ixgbe: add support functions to access thermal data
  ixgbe: add hwmon interface to export thermal data
  ixgbe: add syfs interface for to export read only driver information

 drivers/net/ethernet/intel/Kconfig              |    8 +
 drivers/net/ethernet/intel/ixgbe/Makefile       |    2 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe.h        |   26 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c  |    2 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c  |    2 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_common.c |  169 ++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_common.h |   13 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c   |    6 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c  | 1035 +++++++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_type.h   |   39 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c   |    2 +
 11 files changed, 1303 insertions(+), 1 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c

-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [net-next 1/3] ixgbe: add support functions to access thermal data
  2012-04-05 10:47 [net-next 0/3][pull request] Intel Wired LAN Driver Update Jeff Kirsher
@ 2012-04-05 10:47 ` Jeff Kirsher
  2012-04-05 10:47 ` [net-next 2/3] ixgbe: add hwmon interface to export " Jeff Kirsher
  2012-04-05 10:47 ` [net-next 3/3] ixgbe: add syfs interface for to export read only driver information Jeff Kirsher
  2 siblings, 0 replies; 10+ messages in thread
From: Jeff Kirsher @ 2012-04-05 10:47 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, sassmann, bhutchings, Jeff Kirsher

From: Don Skidmore <donald.c.skidmore@intel.com>

Some 82599 adapters contain thermal data that we can get to via
an i2c interface.  These functions provide support to get at that
data.  A following patch will export this data.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_common.c |  171 +++++++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_common.h |   13 ++
 drivers/net/ethernet/intel/ixgbe/ixgbe_type.h   |   39 +++++
 3 files changed, 223 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index e598881..6c6c66e 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -3604,3 +3604,174 @@ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw)
 	IXGBE_WRITE_REG(hw, IXGBE_GCR_EXT, gcr_ext);
 	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
 }
+
+static const u8 ixgbe_emc_temp_data[4] = {
+	IXGBE_EMC_INTERNAL_DATA,
+	IXGBE_EMC_DIODE1_DATA,
+	IXGBE_EMC_DIODE2_DATA,
+	IXGBE_EMC_DIODE3_DATA
+};
+static const u8 ixgbe_emc_therm_limit[4] = {
+	IXGBE_EMC_INTERNAL_THERM_LIMIT,
+	IXGBE_EMC_DIODE1_THERM_LIMIT,
+	IXGBE_EMC_DIODE2_THERM_LIMIT,
+	IXGBE_EMC_DIODE3_THERM_LIMIT
+};
+
+/**
+ *  ixgbe_get_ets_data - Extracts the ETS bit data
+ *  @hw: pointer to hardware structure
+ *  @ets_cfg: extected ETS data
+ *  @ets_offset: offset of ETS data
+ *
+ *  Returns error code.
+ **/
+static s32 ixgbe_get_ets_data(struct ixgbe_hw *hw, u16 *ets_cfg,
+			      u16 *ets_offset)
+{
+	s32 status = 0;
+
+	status = hw->eeprom.ops.read(hw, IXGBE_ETS_CFG, ets_offset);
+	if (status)
+		goto out;
+
+	if ((*ets_offset == 0x0000) || (*ets_offset == 0xFFFF)) {
+		status = IXGBE_NOT_IMPLEMENTED;
+		goto out;
+	}
+
+	status = hw->eeprom.ops.read(hw, *ets_offset, ets_cfg);
+	if (status)
+		goto out;
+
+	if ((*ets_cfg & IXGBE_ETS_TYPE_MASK) != IXGBE_ETS_TYPE_EMC_SHIFTED) {
+		status = IXGBE_NOT_IMPLEMENTED;
+		goto out;
+	}
+
+out:
+	return status;
+}
+
+/**
+ *  ixgbe_get_thermal_sensor_data - Gathers thermal sensor data
+ *  @hw: pointer to hardware structure
+ *
+ *  Returns the thermal sensor data structure
+ **/
+s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw)
+{
+	s32 status = 0;
+	u16 ets_offset;
+	u16 ets_cfg;
+	u16 ets_sensor;
+	u8  num_sensors;
+	u8  i;
+	struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+	/* Only support thermal sensors attached to 82599 physical port 0 */
+	if ((hw->mac.type != ixgbe_mac_82599EB) ||
+	     (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) {
+		status = IXGBE_NOT_IMPLEMENTED;
+		goto out;
+	}
+
+	status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset);
+	if (status)
+		goto out;
+
+	num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK);
+	if (num_sensors > IXGBE_MAX_SENSORS)
+		num_sensors = IXGBE_MAX_SENSORS;
+
+	for (i = 0; i < num_sensors; i++) {
+		u8  sensor_index;
+		u8  sensor_location;
+
+		status = hw->eeprom.ops.read(hw, (ets_offset + 1 + i),
+					     &ets_sensor);
+		if (status)
+			goto out;
+
+		sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >>
+				IXGBE_ETS_DATA_INDEX_SHIFT);
+		sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >>
+				   IXGBE_ETS_DATA_LOC_SHIFT);
+
+		if (sensor_location != 0) {
+			status = hw->phy.ops.read_i2c_byte(hw,
+					ixgbe_emc_temp_data[sensor_index],
+					IXGBE_I2C_THERMAL_SENSOR_ADDR,
+					&data->sensor[i].temp);
+			if (status)
+				goto out;
+		}
+	}
+out:
+	return status;
+}
+
+/**
+ * ixgbe_init_thermal_sensor_thresh_generic - Inits thermal sensor thresholds
+ * @hw: pointer to hardware structure
+ *
+ * Inits the thermal sensor thresholds according to the NVM map
+ * and save off the threshold and location values into mac.thermal_sensor_data
+ **/
+s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw)
+{
+	s32 status = 0;
+	u16 ets_offset;
+	u16 ets_cfg;
+	u16 ets_sensor;
+	u8  low_thresh_delta;
+	u8  num_sensors;
+	u8  therm_limit;
+	u8  i;
+	struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
+
+	memset(data, 0, sizeof(struct ixgbe_thermal_sensor_data));
+
+	/* Only support thermal sensors attached to 82599 physical port 0 */
+	if ((hw->mac.type != ixgbe_mac_82599EB) ||
+	    (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) {
+		status = IXGBE_NOT_IMPLEMENTED;
+		goto out;
+	}
+
+	status = ixgbe_get_ets_data(hw, &ets_cfg, &ets_offset);
+	if (status)
+		goto out;
+
+	low_thresh_delta = ((ets_cfg & IXGBE_ETS_LTHRES_DELTA_MASK) >>
+			     IXGBE_ETS_LTHRES_DELTA_SHIFT);
+	num_sensors = (ets_cfg & IXGBE_ETS_NUM_SENSORS_MASK);
+	if (num_sensors > IXGBE_MAX_SENSORS)
+		num_sensors = IXGBE_MAX_SENSORS;
+
+	for (i = 0; i < num_sensors; i++) {
+		u8  sensor_index;
+		u8  sensor_location;
+
+		hw->eeprom.ops.read(hw, (ets_offset + 1 + i), &ets_sensor);
+		sensor_index = ((ets_sensor & IXGBE_ETS_DATA_INDEX_MASK) >>
+				IXGBE_ETS_DATA_INDEX_SHIFT);
+		sensor_location = ((ets_sensor & IXGBE_ETS_DATA_LOC_MASK) >>
+				   IXGBE_ETS_DATA_LOC_SHIFT);
+		therm_limit = ets_sensor & IXGBE_ETS_DATA_HTHRESH_MASK;
+
+		hw->phy.ops.write_i2c_byte(hw,
+			ixgbe_emc_therm_limit[sensor_index],
+			IXGBE_I2C_THERMAL_SENSOR_ADDR, therm_limit);
+
+		if (sensor_location == 0)
+			continue;
+
+		data->sensor[i].location = sensor_location;
+		data->sensor[i].caution_thresh = therm_limit;
+		data->sensor[i].max_op_thresh = therm_limit - low_thresh_delta;
+	}
+out:
+	return status;
+}
+
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
index d6d3432..f992777 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
@@ -107,6 +107,19 @@ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw);
 void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb,
 			     u32 headroom, int strategy);
 
+#define IXGBE_I2C_THERMAL_SENSOR_ADDR	0xF8
+#define IXGBE_EMC_INTERNAL_DATA		0x00
+#define IXGBE_EMC_INTERNAL_THERM_LIMIT	0x20
+#define IXGBE_EMC_DIODE1_DATA		0x01
+#define IXGBE_EMC_DIODE1_THERM_LIMIT	0x19
+#define IXGBE_EMC_DIODE2_DATA		0x23
+#define IXGBE_EMC_DIODE2_THERM_LIMIT	0x1A
+#define IXGBE_EMC_DIODE3_DATA		0x2A
+#define IXGBE_EMC_DIODE3_THERM_LIMIT	0x30
+
+s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
+s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
+
 #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
 
 #ifndef writeq
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index ffa6679..8bd15c3 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -110,6 +110,26 @@
 #define IXGBE_I2C_CLK_OUT   0x00000002
 #define IXGBE_I2C_DATA_IN   0x00000004
 #define IXGBE_I2C_DATA_OUT  0x00000008
+#define IXGBE_I2C_THERMAL_SENSOR_ADDR   0xF8
+#define IXGBE_EMC_INTERNAL_DATA         0x00
+#define IXGBE_EMC_INTERNAL_THERM_LIMIT  0x20
+#define IXGBE_EMC_DIODE1_DATA           0x01
+#define IXGBE_EMC_DIODE1_THERM_LIMIT    0x19
+#define IXGBE_EMC_DIODE2_DATA           0x23
+#define IXGBE_EMC_DIODE2_THERM_LIMIT    0x1A
+
+#define IXGBE_MAX_SENSORS               3
+
+struct ixgbe_thermal_diode_data {
+	u8 location;
+	u8 temp;
+	u8 caution_thresh;
+	u8 max_op_thresh;
+};
+
+struct ixgbe_thermal_sensor_data {
+	 struct ixgbe_thermal_diode_data sensor[IXGBE_MAX_SENSORS];
+};
 
 /* Interrupt Registers */
 #define IXGBE_EICR      0x00800
@@ -1677,6 +1697,22 @@ enum {
 #define IXGBE_PBANUM0_PTR       0x15
 #define IXGBE_PBANUM1_PTR       0x16
 #define IXGBE_FREE_SPACE_PTR    0X3E
+
+/* External Thermal Sensor Config */
+#define IXGBE_ETS_CFG                   0x26
+#define IXGBE_ETS_LTHRES_DELTA_MASK     0x07C0
+#define IXGBE_ETS_LTHRES_DELTA_SHIFT    6
+#define IXGBE_ETS_TYPE_MASK             0x0038
+#define IXGBE_ETS_TYPE_SHIFT            3
+#define IXGBE_ETS_TYPE_EMC              0x000
+#define IXGBE_ETS_TYPE_EMC_SHIFTED      0x000
+#define IXGBE_ETS_NUM_SENSORS_MASK      0x0007
+#define IXGBE_ETS_DATA_LOC_MASK         0x3C00
+#define IXGBE_ETS_DATA_LOC_SHIFT        10
+#define IXGBE_ETS_DATA_INDEX_MASK       0x0300
+#define IXGBE_ETS_DATA_INDEX_SHIFT      8
+#define IXGBE_ETS_DATA_HTHRESH_MASK     0x00FF
+
 #define IXGBE_SAN_MAC_ADDR_PTR  0x28
 #define IXGBE_DEVICE_CAPS       0x2C
 #define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11
@@ -2774,6 +2810,8 @@ struct ixgbe_mac_operations {
 
 	/* Manageability interface */
 	s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8);
+	s32 (*get_thermal_sensor_data)(struct ixgbe_hw *);
+	s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw);
 };
 
 struct ixgbe_phy_operations {
@@ -2831,6 +2869,7 @@ struct ixgbe_mac_info {
 	bool                            orig_link_settings_stored;
 	bool                            autotry_restart;
 	u8                              flags;
+	struct ixgbe_thermal_sensor_data  thermal_sensor_data;
 };
 
 struct ixgbe_phy_info {
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [net-next 2/3] ixgbe: add hwmon interface to export thermal data
  2012-04-05 10:47 [net-next 0/3][pull request] Intel Wired LAN Driver Update Jeff Kirsher
  2012-04-05 10:47 ` [net-next 1/3] ixgbe: add support functions to access thermal data Jeff Kirsher
@ 2012-04-05 10:47 ` Jeff Kirsher
  2012-04-05 10:47 ` [net-next 3/3] ixgbe: add syfs interface for to export read only driver information Jeff Kirsher
  2 siblings, 0 replies; 10+ messages in thread
From: Jeff Kirsher @ 2012-04-05 10:47 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, sassmann, bhutchings, Jeff Kirsher

From: Don Skidmore <donald.c.skidmore@intel.com>

Some of our adapters have thermal data available, this patch exports
this data via hwmon sysfs interface.  Other sysfs read-only file follow in
another patch.  Some of the functions introduced there take that into
account.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/Kconfig              |    8 +
 drivers/net/ethernet/intel/ixgbe/Makefile       |    2 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe.h        |   26 +++
 drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c  |    2 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c  |    2 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_common.c |   10 +-
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c   |    6 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c  |  271 +++++++++++++++++++++++
 drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c   |    2 +
 9 files changed, 322 insertions(+), 7 deletions(-)
 create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c

diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 74215c0..546efe3 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -193,6 +193,14 @@ config IXGBE
 	  To compile this driver as a module, choose M here. The module
 	  will be called ixgbe.
 
+config IXGBE_HWMON
+	bool "Intel(R) 10GbE PCI Express adapters HWMON support"
+	default y
+	depends on IXGBE && HWMON && !(IXGBE=y && HWMON=m)
+	---help---
+	  Say Y if you want to expose the thermal sensor data on some of
+	  our cards, via a hwmon sysfs interface.
+
 config IXGBE_DCA
 	bool "Direct Cache Access (DCA) Support"
 	default y
diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile
index 8be1d1b..eec1076 100644
--- a/drivers/net/ethernet/intel/ixgbe/Makefile
+++ b/drivers/net/ethernet/intel/ixgbe/Makefile
@@ -34,7 +34,7 @@ obj-$(CONFIG_IXGBE) += ixgbe.o
 
 ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
               ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
-              ixgbe_mbx.o ixgbe_x540.o ixgbe_lib.o
+              ixgbe_mbx.o ixgbe_x540.o ixgbe_lib.o ixgbe_sysfs.o
 
 ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o \
                               ixgbe_dcb_82599.o ixgbe_dcb_nl.o
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 74e1921..7d99349 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -331,6 +331,26 @@ struct ixgbe_q_vector {
 	/* for dynamic allocation of rings associated with this q_vector */
 	struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
 };
+#ifdef CONFIG_IXGBE_HWMON
+
+#define IXGBE_HWMON_TYPE_LOC		0
+#define IXGBE_HWMON_TYPE_TEMP		1
+#define IXGBE_HWMON_TYPE_CAUTION	2
+#define IXGBE_HWMON_TYPE_MAX		3
+
+struct hwmon_attr {
+	struct device_attribute dev_attr;
+	struct ixgbe_hw *hw;
+	struct ixgbe_thermal_diode_data *sensor;
+	char name[12];
+};
+
+struct hwmon_buff {
+	struct device *device;
+	struct hwmon_attr *hwmon_list;
+	unsigned int n_hwmon;
+};
+#endif /* CONFIG_IXGBE_HWMON */
 
 /*
  * microsecond values for various ITR rates shifted by 2 to fit itr register
@@ -535,6 +555,10 @@ struct ixgbe_adapter {
 
 	u32 timer_event_accumulator;
 	u32 vferr_refcount;
+	struct kobject *info_kobj;
+#ifdef CONFIG_IXGBE_HWMON
+	struct hwmon_buff ixgbe_hwmon_buff;
+#endif /* CONFIG_IXGBE_HWMON */
 };
 
 struct ixgbe_fdir_filter {
@@ -633,6 +657,8 @@ extern int ixgbe_setup_tc(struct net_device *dev, u8 tc);
 #endif
 extern void ixgbe_tx_ctxtdesc(struct ixgbe_ring *, u32, u32, u32, u32);
 extern void ixgbe_do_reset(struct net_device *netdev);
+extern void ixgbe_sysfs_exit(struct ixgbe_adapter *adapter);
+extern int ixgbe_sysfs_init(struct ixgbe_adapter *adapter);
 #ifdef IXGBE_FCOE
 extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter);
 extern int ixgbe_fso(struct ixgbe_ring *tx_ring,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
index 56fd468..6175845 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
@@ -1277,6 +1277,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
 	.set_fw_drv_ver         = NULL,
 	.acquire_swfw_sync      = &ixgbe_acquire_swfw_sync,
 	.release_swfw_sync      = &ixgbe_release_swfw_sync,
+	.get_thermal_sensor_data = NULL,
+	.init_thermal_sensor_thresh = NULL,
 };
 
 static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
index 9c14685..dee64d2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
@@ -2119,6 +2119,8 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
 	.set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing,
 	.acquire_swfw_sync      = &ixgbe_acquire_swfw_sync,
 	.release_swfw_sync      = &ixgbe_release_swfw_sync,
+	.get_thermal_sensor_data = &ixgbe_get_thermal_sensor_data_generic,
+	.init_thermal_sensor_thresh = &ixgbe_init_thermal_sensor_thresh_generic,
 
 };
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
index 6c6c66e..e2b0519 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
@@ -3669,9 +3669,8 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw)
 	u8  i;
 	struct ixgbe_thermal_sensor_data *data = &hw->mac.thermal_sensor_data;
 
-	/* Only support thermal sensors attached to 82599 physical port 0 */
-	if ((hw->mac.type != ixgbe_mac_82599EB) ||
-	     (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) {
+	/* Only support thermal sensors attached to physical port 0 */
+	if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) {
 		status = IXGBE_NOT_IMPLEMENTED;
 		goto out;
 	}
@@ -3732,9 +3731,8 @@ s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw)
 
 	memset(data, 0, sizeof(struct ixgbe_thermal_sensor_data));
 
-	/* Only support thermal sensors attached to 82599 physical port 0 */
-	if ((hw->mac.type != ixgbe_mac_82599EB) ||
-	    (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) {
+	/* Only support thermal sensors attached to physical port 0 */
+	if ((IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)) {
 		status = IXGBE_NOT_IMPLEMENTED;
 		goto out;
 	}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 3e26b1f..983a3e0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7150,6 +7150,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 
 	e_dev_info("%s\n", ixgbe_default_device_descr);
 	cards_found++;
+
+	if (ixgbe_sysfs_init(adapter))
+		e_err(probe, "failed to allocate sysfs resources\n");
+
 	return 0;
 
 err_register:
@@ -7196,6 +7200,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
 	}
 
 #endif
+	ixgbe_sysfs_exit(adapter);
+
 #ifdef IXGBE_FCOE
 	if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
 		ixgbe_cleanup_fcoe(adapter);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
new file mode 100644
index 0000000..0882fd5
--- /dev/null
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
@@ -0,0 +1,271 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2011 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "ixgbe.h"
+#include "ixgbe_common.h"
+#include "ixgbe_type.h"
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/hwmon.h>
+
+/*
+ * This file provides a sysfs interface to export information from the
+ * driver.  The information presented is READ-ONLY.
+ */
+#ifdef CONFIG_IXGBE_HWMON
+
+/* hwmon callback functions */
+static ssize_t ixgbe_hwmon_show_location(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	return sprintf(buf, "loc%u\n",
+		       ixgbe_attr->sensor->location);
+}
+
+static ssize_t ixgbe_hwmon_show_temp(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value;
+
+	/* reset the temp field */
+	ixgbe_attr->hw->mac.ops.get_thermal_sensor_data(ixgbe_attr->hw);
+
+	value = ixgbe_attr->sensor->temp;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t ixgbe_hwmon_show_cautionthresh(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value = ixgbe_attr->sensor->caution_thresh;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t ixgbe_hwmon_show_maxopthresh(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct hwmon_attr *ixgbe_attr = container_of(attr, struct hwmon_attr,
+						     dev_attr);
+	unsigned int value = ixgbe_attr->sensor->max_op_thresh;
+
+	/* display millidegree */
+	value *= 1000;
+
+	return sprintf(buf, "%u\n", value);
+}
+
+/*
+ * ixgbe_add_hwmon_attr - Create hwmon attr table for a hwmon sysfs file.
+ * @ adapter: pointer to the adapter structure
+ * @ offset: offset in the eeprom sensor data table
+ * @ type: type of sensor data to display
+ *
+ * For each file we want in hwmon's sysfs interface we need a device_attribute
+ * This is included in our hwmon_attr struct that contains the references to
+ * the data structures we need to get the data to display.
+ */
+static int ixgbe_add_hwmon_attr(struct ixgbe_adapter *adapter,
+				unsigned int offset, int type) {
+	int rc;
+	unsigned int n_attr;
+	struct hwmon_attr *ixgbe_attr;
+
+	n_attr = adapter->ixgbe_hwmon_buff.n_hwmon;
+	ixgbe_attr = &adapter->ixgbe_hwmon_buff.hwmon_list[n_attr];
+
+	switch (type) {
+	case IXGBE_HWMON_TYPE_LOC:
+		ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_location;
+		snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name),
+			 "temp%u_label", offset);
+		break;
+	case IXGBE_HWMON_TYPE_TEMP:
+		ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_temp;
+		snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name),
+			 "temp%u_input", offset);
+		break;
+	case IXGBE_HWMON_TYPE_CAUTION:
+		ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_cautionthresh;
+		snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name),
+			 "temp%u_max", offset);
+		break;
+	case IXGBE_HWMON_TYPE_MAX:
+		ixgbe_attr->dev_attr.show = ixgbe_hwmon_show_maxopthresh;
+		snprintf(ixgbe_attr->name, sizeof(ixgbe_attr->name),
+			 "temp%u_crit", offset);
+		break;
+	default:
+		rc = -EPERM;
+		return rc;
+	}
+
+	/* These always the same regardless of type */
+	ixgbe_attr->sensor =
+		&adapter->hw.mac.thermal_sensor_data.sensor[offset];
+	ixgbe_attr->hw = &adapter->hw;
+	ixgbe_attr->dev_attr.store = NULL;
+	ixgbe_attr->dev_attr.attr.mode = S_IRUGO;
+	ixgbe_attr->dev_attr.attr.name = ixgbe_attr->name;
+
+	rc = device_create_file(&adapter->pdev->dev,
+				&ixgbe_attr->dev_attr);
+
+	if (rc == 0)
+		++adapter->ixgbe_hwmon_buff.n_hwmon;
+
+	return rc;
+}
+#endif /* CONFIG_IXGBE_HWMON */
+
+static void ixgbe_sysfs_del_adapter(struct ixgbe_adapter *adapter)
+{
+#ifdef CONFIG_IXGBE_HWMON
+	int i;
+#endif /* CONFIG_IXGBE_HWMON */
+
+	if (adapter == NULL)
+		return;
+#ifdef CONFIG_IXGBE_HWMON
+
+	for (i = 0; i < adapter->ixgbe_hwmon_buff.n_hwmon; i++) {
+		device_remove_file(&adapter->pdev->dev,
+			   &adapter->ixgbe_hwmon_buff.hwmon_list[i].dev_attr);
+	}
+
+	kfree(adapter->ixgbe_hwmon_buff.hwmon_list);
+
+	if (adapter->ixgbe_hwmon_buff.device)
+		hwmon_device_unregister(adapter->ixgbe_hwmon_buff.device);
+#endif /* CONFIG_IXGBE_HWMON */
+
+	if (adapter->info_kobj != NULL)
+		kobject_put(adapter->info_kobj);
+}
+
+/* called from ixgbe_main.c */
+void ixgbe_sysfs_exit(struct ixgbe_adapter *adapter)
+{
+	ixgbe_sysfs_del_adapter(adapter);
+}
+
+/* called from ixgbe_main.c */
+int ixgbe_sysfs_init(struct ixgbe_adapter *adapter)
+{
+#ifdef CONFIG_IXGBE_HWMON
+	struct hwmon_buff *ixgbe_hwmon = &adapter->ixgbe_hwmon_buff;
+	unsigned int i;
+	int n_attrs;
+#endif /* CONFIG_IXGBE_HWMON */
+	struct net_device *netdev = adapter->netdev;
+	int rc = 0;
+
+	/* create info kobj and attribute listings in kobj */
+	adapter->info_kobj = kobject_create_and_add("info", &netdev->dev.kobj);
+	if (adapter->info_kobj == NULL) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+#ifdef CONFIG_IXGBE_HWMON
+	/* If this method isn't defined we don't support thermals */
+	if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) {
+		rc = -EPERM;
+		goto err;
+	}
+
+	/* Don't create thermal hwmon interface if no sensors present */
+	rc = adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw);
+	if (rc)
+		goto err;
+
+	/*
+	 * Allocation space for max attributs
+	 * max num sensors * values (loc, temp, max, caution)
+	 */
+	n_attrs = IXGBE_MAX_SENSORS * 4;
+	ixgbe_hwmon->hwmon_list = kcalloc(n_attrs, sizeof(struct hwmon_attr),
+					  GFP_KERNEL);
+	if (!ixgbe_hwmon->hwmon_list) {
+		rc = -ENOMEM;
+		goto err;
+	}
+
+	ixgbe_hwmon->device = hwmon_device_register(&adapter->pdev->dev);
+	if (IS_ERR(ixgbe_hwmon->device)) {
+		rc = PTR_ERR(ixgbe_hwmon->device);
+		goto err;
+	}
+
+	for (i = 0; i < IXGBE_MAX_SENSORS; i++) {
+		/*
+		 * Only create hwmon sysfs entries for sensors that have
+		 * meaningful data for.
+		 */
+		if (adapter->hw.mac.thermal_sensor_data.sensor[i].location == 0)
+			continue;
+
+		/* Bail if any hwmon attr struct fails to initialize */
+		rc = ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_CAUTION);
+		rc |= ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_LOC);
+		rc |= ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_TEMP);
+		rc |= ixgbe_add_hwmon_attr(adapter, i, IXGBE_HWMON_TYPE_MAX);
+		if (rc)
+			goto err;
+	}
+#endif /* CONFIG_IXGBE_HWMON */
+
+	goto exit;
+
+err:
+	ixgbe_sysfs_del_adapter(adapter);
+exit:
+	return rc;
+}
+
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index 97a9914..f90ec07 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -849,6 +849,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
 	.release_swfw_sync      = &ixgbe_release_swfw_sync_X540,
 	.disable_rx_buff	= &ixgbe_disable_rx_buff_generic,
 	.enable_rx_buff		= &ixgbe_enable_rx_buff_generic,
+	.get_thermal_sensor_data = NULL,
+	.init_thermal_sensor_thresh = NULL,
 };
 
 static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [net-next 3/3] ixgbe: add syfs interface for to export read only driver information
  2012-04-05 10:47 [net-next 0/3][pull request] Intel Wired LAN Driver Update Jeff Kirsher
  2012-04-05 10:47 ` [net-next 1/3] ixgbe: add support functions to access thermal data Jeff Kirsher
  2012-04-05 10:47 ` [net-next 2/3] ixgbe: add hwmon interface to export " Jeff Kirsher
@ 2012-04-05 10:47 ` Jeff Kirsher
  2012-04-05 12:19   ` Florian Fainelli
  2 siblings, 1 reply; 10+ messages in thread
From: Jeff Kirsher @ 2012-04-05 10:47 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, sassmann, bhutchings, Jeff Kirsher

From: Don Skidmore <donald.c.skidmore@intel.com>

This patch exports non-thermal (which was done via hwmon in an earlier
patch) data to syfs.  All of the fields are read only as this interface
is to only export driver data.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c |  774 +++++++++++++++++++++++-
 1 files changed, 769 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
index 0882fd5..ddcec9f 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
@@ -41,6 +41,762 @@
  * This file provides a sysfs interface to export information from the
  * driver.  The information presented is READ-ONLY.
  */
+
+static struct net_device_stats *sysfs_get_stats(struct net_device *netdev)
+{
+	if (netdev == NULL)
+		return NULL;
+
+	/* only return the current stats */
+	return &netdev->stats;
+}
+
+static struct net_device *ixgbe_get_netdev(struct kobject *kobj)
+{
+	struct net_device *netdev;
+	struct kobject *parent = kobj->parent;
+	struct device *device_info_kobj;
+
+	if (kobj == NULL)
+		return NULL;
+
+	device_info_kobj = container_of(parent, struct device, kobj);
+	if (device_info_kobj == NULL)
+		return NULL;
+
+	netdev = container_of(device_info_kobj, struct net_device, dev);
+	return netdev;
+}
+
+static struct ixgbe_adapter *ixgbe_get_adapter(struct kobject *kobj)
+{
+	struct ixgbe_adapter *adapter;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return NULL;
+
+	adapter = netdev_priv(netdev);
+	return adapter;
+}
+
+static ssize_t ixgbe_fwbanner(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+	int nvm_track_id;
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	nvm_track_id = (adapter->eeprom_verh << 16) | adapter->eeprom_verl;
+
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", nvm_track_id);
+}
+
+static ssize_t ixgbe_porttype(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			test_bit(__IXGBE_DOWN, &adapter->state));
+}
+
+static ssize_t ixgbe_portspeed(struct kobject *kobj,
+			       struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+	int speed = 0;
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	switch (adapter->link_speed) {
+	case IXGBE_LINK_SPEED_100_FULL:
+		speed = 1;
+		break;
+	case IXGBE_LINK_SPEED_1GB_FULL:
+		speed = 10;
+		break;
+	case IXGBE_LINK_SPEED_10GB_FULL:
+		speed = 100;
+		break;
+	}
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", speed);
+}
+
+static ssize_t ixgbe_wqlflag(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->wol);
+}
+
+static ssize_t ixgbe_xflowctl(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+	struct ixgbe_hw *hw;
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", hw->fc.current_mode);
+}
+
+static ssize_t ixgbe_rxdrops(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n",
+			net_stats->rx_dropped);
+}
+
+static ssize_t ixgbe_rxerrors(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->rx_errors);
+}
+
+static ssize_t ixgbe_rxupacks(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_TPR));
+}
+
+static ssize_t ixgbe_rxmpacks(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_MPRC));
+}
+
+static ssize_t ixgbe_rxbpacks(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_BPRC));
+}
+
+static ssize_t ixgbe_txupacks(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_TPT));
+}
+
+static ssize_t ixgbe_txmpacks(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_MPTC));
+}
+
+static ssize_t ixgbe_txbpacks(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_BPTC));
+}
+
+static ssize_t ixgbe_txerrors(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_errors);
+}
+
+static ssize_t ixgbe_txdrops(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_dropped);
+}
+
+static ssize_t ixgbe_rxframes(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->rx_packets);
+}
+
+static ssize_t ixgbe_rxbytes(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->rx_bytes);
+}
+
+static ssize_t ixgbe_txframes(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_packets);
+}
+
+static ssize_t ixgbe_txbytes(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct net_device_stats *net_stats;
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	net_stats  = sysfs_get_stats(netdev);
+	if (net_stats == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_bytes);
+}
+
+static ssize_t ixgbe_linkstat(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	u32 link_speed;
+	bool link_up = false;
+	int bitmask = 0;
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	if (test_bit(__IXGBE_DOWN, &adapter->state))
+		bitmask |= 1;
+
+	if (hw->mac.ops.check_link)
+		hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+	else
+		/* always assume link is up, if no check link function */
+		link_up = true;
+
+	if (link_up)
+		bitmask |= 2;
+
+	return snprintf(buf, PAGE_SIZE, "0x%X\n", bitmask);
+}
+
+static ssize_t ixgbe_funcid(struct kobject *kobj,
+			    struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+	struct ixgbe_hw *hw;
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "0x%X\n", hw->bus.func);
+}
+
+static ssize_t ixgbe_funcvers(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", ixgbe_driver_version);
+}
+
+static ssize_t ixgbe_macburn(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "0x%X%X%X%X%X%X\n",
+			(unsigned int)hw->mac.perm_addr[0],
+			(unsigned int)hw->mac.perm_addr[1],
+			(unsigned int)hw->mac.perm_addr[2],
+			(unsigned int)hw->mac.perm_addr[3],
+			(unsigned int)hw->mac.perm_addr[4],
+			(unsigned int)hw->mac.perm_addr[5]);
+}
+
+static ssize_t ixgbe_macadmn(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	return snprintf(buf, PAGE_SIZE, "0x%X%X%X%X%X%X\n",
+			(unsigned int)hw->mac.addr[0],
+			(unsigned int)hw->mac.addr[1],
+			(unsigned int)hw->mac.addr[2],
+			(unsigned int)hw->mac.addr[3],
+			(unsigned int)hw->mac.addr[4],
+			(unsigned int)hw->mac.addr[5]);
+}
+
+static ssize_t ixgbe_maclla1(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_hw *hw;
+	u16 eeprom_buff[6];
+	int first_word = 0x37;
+	int word_count = 6;
+	int rc;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	hw = &adapter->hw;
+	if (hw == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
+
+	rc = hw->eeprom.ops.read_buffer(hw, first_word, word_count,
+					eeprom_buff);
+	if (rc)
+		return snprintf(buf, PAGE_SIZE, "error: reading buffer\n");
+
+	switch (hw->bus.func) {
+	case 0:
+		return snprintf(buf, PAGE_SIZE, "0x%04X%04X%04X\n",
+				eeprom_buff[0],
+				eeprom_buff[1],
+				eeprom_buff[2]);
+	case 1:
+		return snprintf(buf, PAGE_SIZE, "0x%04X%04X%04X\n",
+				eeprom_buff[3],
+				eeprom_buff[4],
+				eeprom_buff[5]);
+	}
+
+	return snprintf(buf, PAGE_SIZE, "unexpected port %d\n", hw->bus.func);
+}
+
+static ssize_t ixgbe_mtusize(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", netdev->mtu);
+}
+
+static ssize_t ixgbe_featflag(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	int bitmask = 0;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	if (netdev->features & NETIF_F_RXCSUM)
+		bitmask |= 1;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", bitmask);
+}
+
+static ssize_t ixgbe_lsominct(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", 1);
+}
+
+static ssize_t ixgbe_prommode(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct net_device *netdev = ixgbe_get_netdev(kobj);
+
+	if (netdev == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", netdev->flags & IFF_PROMISC);
+}
+
+static ssize_t ixgbe_txdscqsz(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->tx_ring[0]->count);
+}
+
+static ssize_t ixgbe_rxdscqsz(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->rx_ring[0]->count);
+}
+
+static ssize_t ixgbe_rxqavg(struct kobject *kobj,
+			    struct kobj_attribute *attr, char *buf)
+{
+	int index;
+	int diff = 0;
+	u16 ntc;
+	u16 ntu;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	for (index = 0; index < adapter->num_rx_queues; index++) {
+		ntc = adapter->rx_ring[index]->next_to_clean;
+		ntu = adapter->rx_ring[index]->next_to_use;
+
+		if (ntc >= ntu)
+			diff += (ntc - ntu);
+		else
+			diff += (adapter->rx_ring[index]->count - ntu + ntc);
+	}
+
+	if (adapter->num_rx_queues <= 0)
+		return snprintf(buf, PAGE_SIZE,
+				"can't calculate, number of queues %d\n",
+				adapter->num_rx_queues);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", diff/adapter->num_rx_queues);
+}
+
+static ssize_t ixgbe_txqavg(struct kobject *kobj,
+			    struct kobj_attribute *attr, char *buf)
+{
+	int index;
+	int diff = 0;
+	u16 ntc;
+	u16 ntu;
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	for (index = 0; index < adapter->num_tx_queues; index++) {
+		ntc = adapter->tx_ring[index]->next_to_clean;
+		ntu = adapter->tx_ring[index]->next_to_use;
+
+		if (ntc >= ntu)
+			diff += (ntc - ntu);
+		else
+			diff += (adapter->tx_ring[index]->count - ntu + ntc);
+	}
+
+	if (adapter->num_tx_queues <= 0)
+		return snprintf(buf, PAGE_SIZE,
+				"can't calculate, number of queues %d\n",
+				adapter->num_tx_queues);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", diff/adapter->num_tx_queues);
+}
+
+static ssize_t ixgbe_iovotype(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "2\n");
+}
+
+static ssize_t ixgbe_funcnbr(struct kobject *kobj,
+			     struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->num_vfs);
+}
+
+static ssize_t ixgbe_pciebnbr(struct kobject *kobj,
+			      struct kobj_attribute *attr, char *buf)
+{
+	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
+
+	if (adapter == NULL)
+		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->pdev->bus->number);
+}
+
+/* Initialize the attributes */
+static struct kobj_attribute ixgbe_sysfs_fwbanner_attr =
+	__ATTR(fwbanner, 0444, ixgbe_fwbanner, NULL);
+static struct kobj_attribute ixgbe_sysfs_porttype_attr =
+	__ATTR(porttype, 0444, ixgbe_porttype, NULL);
+static struct kobj_attribute ixgbe_sysfs_portspeed_attr =
+	__ATTR(portspeed, 0444, ixgbe_portspeed, NULL);
+static struct kobj_attribute ixgbe_sysfs_wqlflag_attr =
+	__ATTR(wqlflag, 0444, ixgbe_wqlflag, NULL);
+static struct kobj_attribute ixgbe_sysfs_xflowctl_attr =
+	__ATTR(xflowctl, 0444, ixgbe_xflowctl, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxdrops_attr =
+	__ATTR(rxdrops, 0444, ixgbe_rxdrops, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxerrors_attr =
+	__ATTR(rxerrors, 0444, ixgbe_rxerrors, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxupacks_attr =
+	__ATTR(rxupacks, 0444, ixgbe_rxupacks, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxmpacks_attr =
+	__ATTR(rxmpacks, 0444, ixgbe_rxmpacks, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxbpacks_attr =
+	__ATTR(rxbpacks, 0444, ixgbe_rxbpacks, NULL);
+static struct kobj_attribute ixgbe_sysfs_txupacks_attr =
+	__ATTR(txupacks, 0444, ixgbe_txupacks, NULL);
+static struct kobj_attribute ixgbe_sysfs_txmpacks_attr =
+	__ATTR(txmpacks, 0444, ixgbe_txmpacks, NULL);
+static struct kobj_attribute ixgbe_sysfs_txbpacks_attr =
+	__ATTR(txbpacks, 0444, ixgbe_txbpacks, NULL);
+static struct kobj_attribute ixgbe_sysfs_txerrors_attr =
+	__ATTR(txerrors, 0444, ixgbe_txerrors, NULL);
+static struct kobj_attribute ixgbe_sysfs_txdrops_attr =
+	__ATTR(txdrops, 0444, ixgbe_txdrops, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxframes_attr =
+	__ATTR(rxframes, 0444, ixgbe_rxframes, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxbytes_attr =
+	__ATTR(rxbytes, 0444, ixgbe_rxbytes, NULL);
+static struct kobj_attribute ixgbe_sysfs_txframes_attr =
+	__ATTR(txframes, 0444, ixgbe_txframes, NULL);
+static struct kobj_attribute ixgbe_sysfs_txbytes_attr =
+	__ATTR(txbytes, 0444, ixgbe_txbytes, NULL);
+static struct kobj_attribute ixgbe_sysfs_linkstat_attr =
+	__ATTR(linkstat, 0444, ixgbe_linkstat, NULL);
+static struct kobj_attribute ixgbe_sysfs_funcid_attr =
+	__ATTR(funcid, 0444, ixgbe_funcid, NULL);
+static struct kobj_attribute ixgbe_sysfs_funvers_attr =
+	__ATTR(funcvers, 0444, ixgbe_funcvers, NULL);
+static struct kobj_attribute ixgbe_sysfs_macburn_attr =
+	__ATTR(macburn, 0444, ixgbe_macburn, NULL);
+static struct kobj_attribute ixgbe_sysfs_macadmn_attr =
+	__ATTR(macadmn, 0444, ixgbe_macadmn, NULL);
+static struct kobj_attribute ixgbe_sysfs_maclla1_attr =
+	__ATTR(maclla1, 0444, ixgbe_maclla1, NULL);
+static struct kobj_attribute ixgbe_sysfs_mtusize_attr =
+	__ATTR(mtusize, 0444, ixgbe_mtusize, NULL);
+static struct kobj_attribute ixgbe_sysfs_featflag_attr =
+	__ATTR(featflag, 0444, ixgbe_featflag, NULL);
+static struct kobj_attribute ixgbe_sysfs_lsominct_attr =
+	__ATTR(lsominct, 0444, ixgbe_lsominct, NULL);
+static struct kobj_attribute ixgbe_sysfs_prommode_attr =
+	__ATTR(prommode, 0444, ixgbe_prommode, NULL);
+static struct kobj_attribute ixgbe_sysfs_txdscqsz_attr =
+	__ATTR(txdscqsz, 0444, ixgbe_txdscqsz, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxdscqsz_attr =
+	__ATTR(rxdscqsz, 0444, ixgbe_rxdscqsz, NULL);
+static struct kobj_attribute ixgbe_sysfs_txqavg_attr =
+	__ATTR(txqavg, 0444, ixgbe_txqavg, NULL);
+static struct kobj_attribute ixgbe_sysfs_rxqavg_attr =
+	__ATTR(rxqavg, 0444, ixgbe_rxqavg, NULL);
+static struct kobj_attribute ixgbe_sysfs_iovotype_attr =
+	__ATTR(iovotype, 0444, ixgbe_iovotype, NULL);
+static struct kobj_attribute ixgbe_sysfs_funcnbr_attr =
+	__ATTR(funcnbr, 0444, ixgbe_funcnbr, NULL);
+static struct kobj_attribute ixgbe_sysfs_pciebnbr_attr =
+	__ATTR(pciebnbr, 0444, ixgbe_pciebnbr, NULL);
+
+static struct attribute *attrs[] = {
+	&ixgbe_sysfs_fwbanner_attr.attr,
+	&ixgbe_sysfs_porttype_attr.attr,
+	&ixgbe_sysfs_portspeed_attr.attr,
+	&ixgbe_sysfs_wqlflag_attr.attr,
+	&ixgbe_sysfs_xflowctl_attr.attr,
+	&ixgbe_sysfs_rxdrops_attr.attr,
+	&ixgbe_sysfs_rxerrors_attr.attr,
+	&ixgbe_sysfs_rxupacks_attr.attr,
+	&ixgbe_sysfs_rxmpacks_attr.attr,
+	&ixgbe_sysfs_rxbpacks_attr.attr,
+	&ixgbe_sysfs_txdrops_attr.attr,
+	&ixgbe_sysfs_txerrors_attr.attr,
+	&ixgbe_sysfs_txupacks_attr.attr,
+	&ixgbe_sysfs_txmpacks_attr.attr,
+	&ixgbe_sysfs_txbpacks_attr.attr,
+	&ixgbe_sysfs_rxframes_attr.attr,
+	&ixgbe_sysfs_rxbytes_attr.attr,
+	&ixgbe_sysfs_txframes_attr.attr,
+	&ixgbe_sysfs_txbytes_attr.attr,
+	&ixgbe_sysfs_linkstat_attr.attr,
+	&ixgbe_sysfs_funcid_attr.attr,
+	&ixgbe_sysfs_funvers_attr.attr,
+	&ixgbe_sysfs_macburn_attr.attr,
+	&ixgbe_sysfs_macadmn_attr.attr,
+	&ixgbe_sysfs_maclla1_attr.attr,
+	&ixgbe_sysfs_mtusize_attr.attr,
+	&ixgbe_sysfs_featflag_attr.attr,
+	&ixgbe_sysfs_lsominct_attr.attr,
+	&ixgbe_sysfs_prommode_attr.attr,
+	&ixgbe_sysfs_txdscqsz_attr.attr,
+	&ixgbe_sysfs_rxdscqsz_attr.attr,
+	&ixgbe_sysfs_txqavg_attr.attr,
+	&ixgbe_sysfs_rxqavg_attr.attr,
+	&ixgbe_sysfs_iovotype_attr.attr,
+	&ixgbe_sysfs_funcnbr_attr.attr,
+	&ixgbe_sysfs_pciebnbr_attr.attr,
+	NULL
+};
+
+/* add attributes to a group */
+static struct attribute_group attr_group = {
+	.attrs = attrs,
+};
+
 #ifdef CONFIG_IXGBE_HWMON
 
 /* hwmon callback functions */
@@ -185,8 +941,11 @@ static void ixgbe_sysfs_del_adapter(struct ixgbe_adapter *adapter)
 		hwmon_device_unregister(adapter->ixgbe_hwmon_buff.device);
 #endif /* CONFIG_IXGBE_HWMON */
 
-	if (adapter->info_kobj != NULL)
+	if (adapter->info_kobj != NULL) {
+		sysfs_remove_group(adapter->info_kobj, &attr_group);
 		kobject_put(adapter->info_kobj);
+		adapter->info_kobj = NULL;
+	}
 }
 
 /* called from ixgbe_main.c */
@@ -213,17 +972,22 @@ int ixgbe_sysfs_init(struct ixgbe_adapter *adapter)
 		goto err;
 	}
 
+	rc = sysfs_create_group(adapter->info_kobj, &attr_group);
+	if (rc)
+		goto err;
+
 #ifdef CONFIG_IXGBE_HWMON
 	/* If this method isn't defined we don't support thermals */
 	if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) {
-		rc = -EPERM;
-		goto err;
+		goto exit;
 	}
 
 	/* Don't create thermal hwmon interface if no sensors present */
 	rc = adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw);
-	if (rc)
-		goto err;
+	if (rc) {
+		rc = 0;
+		goto exit;
+	}
 
 	/*
 	 * Allocation space for max attributs
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [net-next 3/3] ixgbe: add syfs interface for to export read only driver information
  2012-04-05 10:47 ` [net-next 3/3] ixgbe: add syfs interface for to export read only driver information Jeff Kirsher
@ 2012-04-05 12:19   ` Florian Fainelli
  2012-04-05 16:32     ` Ben Hutchings
  0 siblings, 1 reply; 10+ messages in thread
From: Florian Fainelli @ 2012-04-05 12:19 UTC (permalink / raw)
  To: Jeff Kirsher; +Cc: davem, Don Skidmore, netdev, gospo, sassmann, bhutchings

Hi,

Le 04/05/12 12:47, Jeff Kirsher a écrit :
> From: Don Skidmore<donald.c.skidmore@intel.com>
>
> This patch exports non-thermal (which was done via hwmon in an earlier
> patch) data to syfs.  All of the fields are read only as this interface
> is to only export driver data.
>
> Signed-off-by: Don Skidmore<donald.c.skidmore@intel.com>
> Tested-by: Stephen Ko<stephen.s.ko@intel.com>
> Signed-off-by: Jeff Kirsher<jeffrey.t.kirsher@intel.com>
> ---

I only looked briefly at the exported attributes, but most of them can 
already be queried using ethtool, can't they?

Also, if you want to go that way, you might want to make the sysfs 
interface configurable through a Kconfig knob, and use one or several 
macros to define attributes accessors and reduce the amount of lines of 
code.

>   drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c |  774 +++++++++++++++++++++++-
>   1 files changed, 769 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
> index 0882fd5..ddcec9f 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
> @@ -41,6 +41,762 @@
>    * This file provides a sysfs interface to export information from the
>    * driver.  The information presented is READ-ONLY.
>    */
> +
> +static struct net_device_stats *sysfs_get_stats(struct net_device *netdev)
> +{
> +	if (netdev == NULL)
> +		return NULL;
> +
> +	/* only return the current stats */
> +	return&netdev->stats;
> +}
> +
> +static struct net_device *ixgbe_get_netdev(struct kobject *kobj)
> +{
> +	struct net_device *netdev;
> +	struct kobject *parent = kobj->parent;
> +	struct device *device_info_kobj;
> +
> +	if (kobj == NULL)
> +		return NULL;
> +
> +	device_info_kobj = container_of(parent, struct device, kobj);
> +	if (device_info_kobj == NULL)
> +		return NULL;
> +
> +	netdev = container_of(device_info_kobj, struct net_device, dev);
> +	return netdev;
> +}
> +
> +static struct ixgbe_adapter *ixgbe_get_adapter(struct kobject *kobj)
> +{
> +	struct ixgbe_adapter *adapter;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return NULL;
> +
> +	adapter = netdev_priv(netdev);
> +	return adapter;
> +}
> +
> +static ssize_t ixgbe_fwbanner(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +	int nvm_track_id;
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	nvm_track_id = (adapter->eeprom_verh<<  16) | adapter->eeprom_verl;
> +
> +	return snprintf(buf, PAGE_SIZE, "0x%08x\n", nvm_track_id);
> +}
> +
> +static ssize_t ixgbe_porttype(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n",
> +			test_bit(__IXGBE_DOWN,&adapter->state));
> +}
> +
> +static ssize_t ixgbe_portspeed(struct kobject *kobj,
> +			       struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +	int speed = 0;
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	switch (adapter->link_speed) {
> +	case IXGBE_LINK_SPEED_100_FULL:
> +		speed = 1;
> +		break;
> +	case IXGBE_LINK_SPEED_1GB_FULL:
> +		speed = 10;
> +		break;
> +	case IXGBE_LINK_SPEED_10GB_FULL:
> +		speed = 100;
> +		break;
> +	}
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", speed);
> +}
> +
> +static ssize_t ixgbe_wqlflag(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->wol);
> +}
> +
> +static ssize_t ixgbe_xflowctl(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +	struct ixgbe_hw *hw;
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", hw->fc.current_mode);
> +}
> +
> +static ssize_t ixgbe_rxdrops(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n",
> +			net_stats->rx_dropped);
> +}
> +
> +static ssize_t ixgbe_rxerrors(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->rx_errors);
> +}
> +
> +static ssize_t ixgbe_rxupacks(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_TPR));
> +}
> +
> +static ssize_t ixgbe_rxmpacks(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_MPRC));
> +}
> +
> +static ssize_t ixgbe_rxbpacks(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_BPRC));
> +}
> +
> +static ssize_t ixgbe_txupacks(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_TPT));
> +}
> +
> +static ssize_t ixgbe_txmpacks(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_MPTC));
> +}
> +
> +static ssize_t ixgbe_txbpacks(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", IXGBE_READ_REG(hw, IXGBE_BPTC));
> +}
> +
> +static ssize_t ixgbe_txerrors(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_errors);
> +}
> +
> +static ssize_t ixgbe_txdrops(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_dropped);
> +}
> +
> +static ssize_t ixgbe_rxframes(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->rx_packets);
> +}
> +
> +static ssize_t ixgbe_rxbytes(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->rx_bytes);
> +}
> +
> +static ssize_t ixgbe_txframes(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_packets);
> +}
> +
> +static ssize_t ixgbe_txbytes(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device_stats *net_stats;
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	net_stats  = sysfs_get_stats(netdev);
> +	if (net_stats == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net stats\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%lu\n", net_stats->tx_bytes);
> +}
> +
> +static ssize_t ixgbe_linkstat(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	u32 link_speed;
> +	bool link_up = false;
> +	int bitmask = 0;
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	if (test_bit(__IXGBE_DOWN,&adapter->state))
> +		bitmask |= 1;
> +
> +	if (hw->mac.ops.check_link)
> +		hw->mac.ops.check_link(hw,&link_speed,&link_up, false);
> +	else
> +		/* always assume link is up, if no check link function */
> +		link_up = true;
> +
> +	if (link_up)
> +		bitmask |= 2;
> +
> +	return snprintf(buf, PAGE_SIZE, "0x%X\n", bitmask);
> +}
> +
> +static ssize_t ixgbe_funcid(struct kobject *kobj,
> +			    struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +	struct ixgbe_hw *hw;
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "0x%X\n", hw->bus.func);
> +}
> +
> +static ssize_t ixgbe_funcvers(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	return snprintf(buf, PAGE_SIZE, "%s\n", ixgbe_driver_version);
> +}
> +
> +static ssize_t ixgbe_macburn(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "0x%X%X%X%X%X%X\n",
> +			(unsigned int)hw->mac.perm_addr[0],
> +			(unsigned int)hw->mac.perm_addr[1],
> +			(unsigned int)hw->mac.perm_addr[2],
> +			(unsigned int)hw->mac.perm_addr[3],
> +			(unsigned int)hw->mac.perm_addr[4],
> +			(unsigned int)hw->mac.perm_addr[5]);
> +}
> +
> +static ssize_t ixgbe_macadmn(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "0x%X%X%X%X%X%X\n",
> +			(unsigned int)hw->mac.addr[0],
> +			(unsigned int)hw->mac.addr[1],
> +			(unsigned int)hw->mac.addr[2],
> +			(unsigned int)hw->mac.addr[3],
> +			(unsigned int)hw->mac.addr[4],
> +			(unsigned int)hw->mac.addr[5]);
> +}
> +
> +static ssize_t ixgbe_maclla1(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_hw *hw;
> +	u16 eeprom_buff[6];
> +	int first_word = 0x37;
> +	int word_count = 6;
> +	int rc;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	hw =&adapter->hw;
> +	if (hw == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no hw data\n");
> +
> +	rc = hw->eeprom.ops.read_buffer(hw, first_word, word_count,
> +					eeprom_buff);
> +	if (rc)
> +		return snprintf(buf, PAGE_SIZE, "error: reading buffer\n");
> +
> +	switch (hw->bus.func) {
> +	case 0:
> +		return snprintf(buf, PAGE_SIZE, "0x%04X%04X%04X\n",
> +				eeprom_buff[0],
> +				eeprom_buff[1],
> +				eeprom_buff[2]);
> +	case 1:
> +		return snprintf(buf, PAGE_SIZE, "0x%04X%04X%04X\n",
> +				eeprom_buff[3],
> +				eeprom_buff[4],
> +				eeprom_buff[5]);
> +	}
> +
> +	return snprintf(buf, PAGE_SIZE, "unexpected port %d\n", hw->bus.func);
> +}
> +
> +static ssize_t ixgbe_mtusize(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", netdev->mtu);
> +}
> +
> +static ssize_t ixgbe_featflag(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	int bitmask = 0;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	if (netdev->features&  NETIF_F_RXCSUM)
> +		bitmask |= 1;
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", bitmask);
> +}
> +
> +static ssize_t ixgbe_lsominct(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	return snprintf(buf, PAGE_SIZE, "%d\n", 1);
> +}
> +
> +static ssize_t ixgbe_prommode(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct net_device *netdev = ixgbe_get_netdev(kobj);
> +
> +	if (netdev == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no net device\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", netdev->flags&  IFF_PROMISC);
> +}
> +
> +static ssize_t ixgbe_txdscqsz(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->tx_ring[0]->count);
> +}
> +
> +static ssize_t ixgbe_rxdscqsz(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->rx_ring[0]->count);
> +}
> +
> +static ssize_t ixgbe_rxqavg(struct kobject *kobj,
> +			    struct kobj_attribute *attr, char *buf)
> +{
> +	int index;
> +	int diff = 0;
> +	u16 ntc;
> +	u16 ntu;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	for (index = 0; index<  adapter->num_rx_queues; index++) {
> +		ntc = adapter->rx_ring[index]->next_to_clean;
> +		ntu = adapter->rx_ring[index]->next_to_use;
> +
> +		if (ntc>= ntu)
> +			diff += (ntc - ntu);
> +		else
> +			diff += (adapter->rx_ring[index]->count - ntu + ntc);
> +	}
> +
> +	if (adapter->num_rx_queues<= 0)
> +		return snprintf(buf, PAGE_SIZE,
> +				"can't calculate, number of queues %d\n",
> +				adapter->num_rx_queues);
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", diff/adapter->num_rx_queues);
> +}
> +
> +static ssize_t ixgbe_txqavg(struct kobject *kobj,
> +			    struct kobj_attribute *attr, char *buf)
> +{
> +	int index;
> +	int diff = 0;
> +	u16 ntc;
> +	u16 ntu;
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	for (index = 0; index<  adapter->num_tx_queues; index++) {
> +		ntc = adapter->tx_ring[index]->next_to_clean;
> +		ntu = adapter->tx_ring[index]->next_to_use;
> +
> +		if (ntc>= ntu)
> +			diff += (ntc - ntu);
> +		else
> +			diff += (adapter->tx_ring[index]->count - ntu + ntc);
> +	}
> +
> +	if (adapter->num_tx_queues<= 0)
> +		return snprintf(buf, PAGE_SIZE,
> +				"can't calculate, number of queues %d\n",
> +				adapter->num_tx_queues);
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", diff/adapter->num_tx_queues);
> +}
> +
> +static ssize_t ixgbe_iovotype(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	return snprintf(buf, PAGE_SIZE, "2\n");
> +}
> +
> +static ssize_t ixgbe_funcnbr(struct kobject *kobj,
> +			     struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->num_vfs);
> +}
> +
> +static ssize_t ixgbe_pciebnbr(struct kobject *kobj,
> +			      struct kobj_attribute *attr, char *buf)
> +{
> +	struct ixgbe_adapter *adapter = ixgbe_get_adapter(kobj);
> +
> +	if (adapter == NULL)
> +		return snprintf(buf, PAGE_SIZE, "error: no adapter\n");
> +
> +	return snprintf(buf, PAGE_SIZE, "%d\n", adapter->pdev->bus->number);
> +}
> +
> +/* Initialize the attributes */
> +static struct kobj_attribute ixgbe_sysfs_fwbanner_attr =
> +	__ATTR(fwbanner, 0444, ixgbe_fwbanner, NULL);
> +static struct kobj_attribute ixgbe_sysfs_porttype_attr =
> +	__ATTR(porttype, 0444, ixgbe_porttype, NULL);
> +static struct kobj_attribute ixgbe_sysfs_portspeed_attr =
> +	__ATTR(portspeed, 0444, ixgbe_portspeed, NULL);
> +static struct kobj_attribute ixgbe_sysfs_wqlflag_attr =
> +	__ATTR(wqlflag, 0444, ixgbe_wqlflag, NULL);
> +static struct kobj_attribute ixgbe_sysfs_xflowctl_attr =
> +	__ATTR(xflowctl, 0444, ixgbe_xflowctl, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxdrops_attr =
> +	__ATTR(rxdrops, 0444, ixgbe_rxdrops, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxerrors_attr =
> +	__ATTR(rxerrors, 0444, ixgbe_rxerrors, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxupacks_attr =
> +	__ATTR(rxupacks, 0444, ixgbe_rxupacks, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxmpacks_attr =
> +	__ATTR(rxmpacks, 0444, ixgbe_rxmpacks, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxbpacks_attr =
> +	__ATTR(rxbpacks, 0444, ixgbe_rxbpacks, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txupacks_attr =
> +	__ATTR(txupacks, 0444, ixgbe_txupacks, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txmpacks_attr =
> +	__ATTR(txmpacks, 0444, ixgbe_txmpacks, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txbpacks_attr =
> +	__ATTR(txbpacks, 0444, ixgbe_txbpacks, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txerrors_attr =
> +	__ATTR(txerrors, 0444, ixgbe_txerrors, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txdrops_attr =
> +	__ATTR(txdrops, 0444, ixgbe_txdrops, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxframes_attr =
> +	__ATTR(rxframes, 0444, ixgbe_rxframes, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxbytes_attr =
> +	__ATTR(rxbytes, 0444, ixgbe_rxbytes, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txframes_attr =
> +	__ATTR(txframes, 0444, ixgbe_txframes, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txbytes_attr =
> +	__ATTR(txbytes, 0444, ixgbe_txbytes, NULL);
> +static struct kobj_attribute ixgbe_sysfs_linkstat_attr =
> +	__ATTR(linkstat, 0444, ixgbe_linkstat, NULL);
> +static struct kobj_attribute ixgbe_sysfs_funcid_attr =
> +	__ATTR(funcid, 0444, ixgbe_funcid, NULL);
> +static struct kobj_attribute ixgbe_sysfs_funvers_attr =
> +	__ATTR(funcvers, 0444, ixgbe_funcvers, NULL);
> +static struct kobj_attribute ixgbe_sysfs_macburn_attr =
> +	__ATTR(macburn, 0444, ixgbe_macburn, NULL);
> +static struct kobj_attribute ixgbe_sysfs_macadmn_attr =
> +	__ATTR(macadmn, 0444, ixgbe_macadmn, NULL);
> +static struct kobj_attribute ixgbe_sysfs_maclla1_attr =
> +	__ATTR(maclla1, 0444, ixgbe_maclla1, NULL);
> +static struct kobj_attribute ixgbe_sysfs_mtusize_attr =
> +	__ATTR(mtusize, 0444, ixgbe_mtusize, NULL);
> +static struct kobj_attribute ixgbe_sysfs_featflag_attr =
> +	__ATTR(featflag, 0444, ixgbe_featflag, NULL);
> +static struct kobj_attribute ixgbe_sysfs_lsominct_attr =
> +	__ATTR(lsominct, 0444, ixgbe_lsominct, NULL);
> +static struct kobj_attribute ixgbe_sysfs_prommode_attr =
> +	__ATTR(prommode, 0444, ixgbe_prommode, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txdscqsz_attr =
> +	__ATTR(txdscqsz, 0444, ixgbe_txdscqsz, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxdscqsz_attr =
> +	__ATTR(rxdscqsz, 0444, ixgbe_rxdscqsz, NULL);
> +static struct kobj_attribute ixgbe_sysfs_txqavg_attr =
> +	__ATTR(txqavg, 0444, ixgbe_txqavg, NULL);
> +static struct kobj_attribute ixgbe_sysfs_rxqavg_attr =
> +	__ATTR(rxqavg, 0444, ixgbe_rxqavg, NULL);
> +static struct kobj_attribute ixgbe_sysfs_iovotype_attr =
> +	__ATTR(iovotype, 0444, ixgbe_iovotype, NULL);
> +static struct kobj_attribute ixgbe_sysfs_funcnbr_attr =
> +	__ATTR(funcnbr, 0444, ixgbe_funcnbr, NULL);
> +static struct kobj_attribute ixgbe_sysfs_pciebnbr_attr =
> +	__ATTR(pciebnbr, 0444, ixgbe_pciebnbr, NULL);
> +
> +static struct attribute *attrs[] = {
> +	&ixgbe_sysfs_fwbanner_attr.attr,
> +	&ixgbe_sysfs_porttype_attr.attr,
> +	&ixgbe_sysfs_portspeed_attr.attr,
> +	&ixgbe_sysfs_wqlflag_attr.attr,
> +	&ixgbe_sysfs_xflowctl_attr.attr,
> +	&ixgbe_sysfs_rxdrops_attr.attr,
> +	&ixgbe_sysfs_rxerrors_attr.attr,
> +	&ixgbe_sysfs_rxupacks_attr.attr,
> +	&ixgbe_sysfs_rxmpacks_attr.attr,
> +	&ixgbe_sysfs_rxbpacks_attr.attr,
> +	&ixgbe_sysfs_txdrops_attr.attr,
> +	&ixgbe_sysfs_txerrors_attr.attr,
> +	&ixgbe_sysfs_txupacks_attr.attr,
> +	&ixgbe_sysfs_txmpacks_attr.attr,
> +	&ixgbe_sysfs_txbpacks_attr.attr,
> +	&ixgbe_sysfs_rxframes_attr.attr,
> +	&ixgbe_sysfs_rxbytes_attr.attr,
> +	&ixgbe_sysfs_txframes_attr.attr,
> +	&ixgbe_sysfs_txbytes_attr.attr,
> +	&ixgbe_sysfs_linkstat_attr.attr,
> +	&ixgbe_sysfs_funcid_attr.attr,
> +	&ixgbe_sysfs_funvers_attr.attr,
> +	&ixgbe_sysfs_macburn_attr.attr,
> +	&ixgbe_sysfs_macadmn_attr.attr,
> +	&ixgbe_sysfs_maclla1_attr.attr,
> +	&ixgbe_sysfs_mtusize_attr.attr,
> +	&ixgbe_sysfs_featflag_attr.attr,
> +	&ixgbe_sysfs_lsominct_attr.attr,
> +	&ixgbe_sysfs_prommode_attr.attr,
> +	&ixgbe_sysfs_txdscqsz_attr.attr,
> +	&ixgbe_sysfs_rxdscqsz_attr.attr,
> +	&ixgbe_sysfs_txqavg_attr.attr,
> +	&ixgbe_sysfs_rxqavg_attr.attr,
> +	&ixgbe_sysfs_iovotype_attr.attr,
> +	&ixgbe_sysfs_funcnbr_attr.attr,
> +	&ixgbe_sysfs_pciebnbr_attr.attr,
> +	NULL
> +};
> +
> +/* add attributes to a group */
> +static struct attribute_group attr_group = {
> +	.attrs = attrs,
> +};
> +
>   #ifdef CONFIG_IXGBE_HWMON
>
>   /* hwmon callback functions */
> @@ -185,8 +941,11 @@ static void ixgbe_sysfs_del_adapter(struct ixgbe_adapter *adapter)
>   		hwmon_device_unregister(adapter->ixgbe_hwmon_buff.device);
>   #endif /* CONFIG_IXGBE_HWMON */
>
> -	if (adapter->info_kobj != NULL)
> +	if (adapter->info_kobj != NULL) {
> +		sysfs_remove_group(adapter->info_kobj,&attr_group);
>   		kobject_put(adapter->info_kobj);
> +		adapter->info_kobj = NULL;
> +	}
>   }
>
>   /* called from ixgbe_main.c */
> @@ -213,17 +972,22 @@ int ixgbe_sysfs_init(struct ixgbe_adapter *adapter)
>   		goto err;
>   	}
>
> +	rc = sysfs_create_group(adapter->info_kobj,&attr_group);
> +	if (rc)
> +		goto err;
> +
>   #ifdef CONFIG_IXGBE_HWMON
>   	/* If this method isn't defined we don't support thermals */
>   	if (adapter->hw.mac.ops.init_thermal_sensor_thresh == NULL) {
> -		rc = -EPERM;
> -		goto err;
> +		goto exit;
>   	}
>
>   	/* Don't create thermal hwmon interface if no sensors present */
>   	rc = adapter->hw.mac.ops.init_thermal_sensor_thresh(&adapter->hw);
> -	if (rc)
> -		goto err;
> +	if (rc) {
> +		rc = 0;
> +		goto exit;
> +	}
>
>   	/*
>   	 * Allocation space for max attributs

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [net-next 3/3] ixgbe: add syfs interface for to export read only driver information
  2012-04-05 12:19   ` Florian Fainelli
@ 2012-04-05 16:32     ` Ben Hutchings
  2012-04-05 22:49       ` David Miller
  2012-04-05 23:52       ` Rustad, Mark D
  0 siblings, 2 replies; 10+ messages in thread
From: Ben Hutchings @ 2012-04-05 16:32 UTC (permalink / raw)
  To: Florian Fainelli
  Cc: Jeff Kirsher, davem, Don Skidmore, netdev, gospo, sassmann

On Thu, 2012-04-05 at 14:19 +0200, Florian Fainelli wrote:
> Hi,
> 
> Le 04/05/12 12:47, Jeff Kirsher a écrit :
> > From: Don Skidmore<donald.c.skidmore@intel.com>
> >
> > This patch exports non-thermal (which was done via hwmon in an earlier
> > patch) data to syfs.  All of the fields are read only as this interface
> > is to only export driver data.
> >
> > Signed-off-by: Don Skidmore<donald.c.skidmore@intel.com>
> > Tested-by: Stephen Ko<stephen.s.ko@intel.com>
> > Signed-off-by: Jeff Kirsher<jeffrey.t.kirsher@intel.com>
> > ---
> 
> I only looked briefly at the exported attributes, but most of them can 
> already be queried using ethtool, can't they?
[...]

I agree, it looks like most of these are:

(1) already exposed through ethtool commands (ETHTOOL_GSET,
ETHTOOL_GDRVINFO, ETHTOOL_GLINK and ETHTOOL_GPERMADDR), or
(2) already exposed through rtnetlink or the net device in sysfs, or
(3) statistics that should be exposed through ETHTOOL_GSTATS

I imagine there are some that don't fall into those categories, but I
don't see why they should *all* be exposed in a non-standard and/or
redundant way.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [net-next 3/3] ixgbe: add syfs interface for to export read only driver information
  2012-04-05 16:32     ` Ben Hutchings
@ 2012-04-05 22:49       ` David Miller
  2012-04-05 23:01         ` Skidmore, Donald C
  2012-04-05 23:52       ` Rustad, Mark D
  1 sibling, 1 reply; 10+ messages in thread
From: David Miller @ 2012-04-05 22:49 UTC (permalink / raw)
  To: bhutchings
  Cc: florian, jeffrey.t.kirsher, donald.c.skidmore, netdev, gospo, sassmann

From: Ben Hutchings <bhutchings@solarflare.com>
Date: Thu, 5 Apr 2012 17:32:05 +0100

> On Thu, 2012-04-05 at 14:19 +0200, Florian Fainelli wrote:
>> Hi,
>> 
>> Le 04/05/12 12:47, Jeff Kirsher a écrit :
>> > From: Don Skidmore<donald.c.skidmore@intel.com>
>> >
>> > This patch exports non-thermal (which was done via hwmon in an earlier
>> > patch) data to syfs.  All of the fields are read only as this interface
>> > is to only export driver data.
>> >
>> > Signed-off-by: Don Skidmore<donald.c.skidmore@intel.com>
>> > Tested-by: Stephen Ko<stephen.s.ko@intel.com>
>> > Signed-off-by: Jeff Kirsher<jeffrey.t.kirsher@intel.com>
>> > ---
>> 
>> I only looked briefly at the exported attributes, but most of them can 
>> already be queried using ethtool, can't they?
> [...]
> 
> I agree, it looks like most of these are:
> 
> (1) already exposed through ethtool commands (ETHTOOL_GSET,
> ETHTOOL_GDRVINFO, ETHTOOL_GLINK and ETHTOOL_GPERMADDR), or
> (2) already exposed through rtnetlink or the net device in sysfs, or
> (3) statistics that should be exposed through ETHTOOL_GSTATS
> 
> I imagine there are some that don't fall into those categories, but I
> don't see why they should *all* be exposed in a non-standard and/or
> redundant way.

Agreed.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [net-next 3/3] ixgbe: add syfs interface for to export read only driver information
  2012-04-05 22:49       ` David Miller
@ 2012-04-05 23:01         ` Skidmore, Donald C
  0 siblings, 0 replies; 10+ messages in thread
From: Skidmore, Donald C @ 2012-04-05 23:01 UTC (permalink / raw)
  To: David Miller, bhutchings
  Cc: florian, Kirsher, Jeffrey T, netdev, gospo, sassmann

>-----Original Message-----
>From: David Miller [mailto:davem@davemloft.net]
>Sent: Thursday, April 05, 2012 3:50 PM
>To: bhutchings@solarflare.com
>Cc: florian@openwrt.org; Kirsher, Jeffrey T; Skidmore, Donald C;
>netdev@vger.kernel.org; gospo@redhat.com; sassmann@redhat.com
>Subject: Re: [net-next 3/3] ixgbe: add syfs interface for to export read
>only driver information
>
>From: Ben Hutchings <bhutchings@solarflare.com>
>Date: Thu, 5 Apr 2012 17:32:05 +0100
>
>> On Thu, 2012-04-05 at 14:19 +0200, Florian Fainelli wrote:
>>> Hi,
>>>
>>> Le 04/05/12 12:47, Jeff Kirsher a écrit :
>>> > From: Don Skidmore<donald.c.skidmore@intel.com>
>>> >
>>> > This patch exports non-thermal (which was done via hwmon in an
>earlier
>>> > patch) data to syfs.  All of the fields are read only as this
>interface
>>> > is to only export driver data.
>>> >
>>> > Signed-off-by: Don Skidmore<donald.c.skidmore@intel.com>
>>> > Tested-by: Stephen Ko<stephen.s.ko@intel.com>
>>> > Signed-off-by: Jeff Kirsher<jeffrey.t.kirsher@intel.com>
>>> > ---
>>>
>>> I only looked briefly at the exported attributes, but most of them
>can
>>> already be queried using ethtool, can't they?
>> [...]
>>
>> I agree, it looks like most of these are:
>>
>> (1) already exposed through ethtool commands (ETHTOOL_GSET,
>> ETHTOOL_GDRVINFO, ETHTOOL_GLINK and ETHTOOL_GPERMADDR), or
>> (2) already exposed through rtnetlink or the net device in sysfs, or
>> (3) statistics that should be exposed through ETHTOOL_GSTATS
>>
>> I imagine there are some that don't fall into those categories, but I
>> don't see why they should *all* be exposed in a non-standard and/or
>> redundant way.
>
>Agreed.

Thanks for the input.  I'll start on refactoring the patch to exclude all items that are exposed in any other way.

-Don Skidmore <donald.c.skidmore@intel.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [net-next 3/3] ixgbe: add syfs interface for to export read only driver information
  2012-04-05 16:32     ` Ben Hutchings
  2012-04-05 22:49       ` David Miller
@ 2012-04-05 23:52       ` Rustad, Mark D
  2012-04-06  0:59         ` David Miller
  1 sibling, 1 reply; 10+ messages in thread
From: Rustad, Mark D @ 2012-04-05 23:52 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: Florian Fainelli, Kirsher, Jeffrey T, <davem@davemloft.net>,
	Skidmore, Donald C, <netdev@vger.kernel.org>,
	<gospo@redhat.com>, <sassmann@redhat.com>

On Apr 5, 2012, at 9:32 AM, Ben Hutchings wrote:

> On Thu, 2012-04-05 at 14:19 +0200, Florian Fainelli wrote:
>> Hi,
>> 
>> Le 04/05/12 12:47, Jeff Kirsher a écrit :
>>> From: Don Skidmore<donald.c.skidmore@intel.com>
>>> 
>>> This patch exports non-thermal (which was done via hwmon in an earlier
>>> patch) data to syfs.  All of the fields are read only as this interface
>>> is to only export driver data.
>>> 
>>> Signed-off-by: Don Skidmore<donald.c.skidmore@intel.com>
>>> Tested-by: Stephen Ko<stephen.s.ko@intel.com>
>>> Signed-off-by: Jeff Kirsher<jeffrey.t.kirsher@intel.com>
>>> ---
>> 
>> I only looked briefly at the exported attributes, but most of them can 
>> already be queried using ethtool, can't they?
> [...]
> 
> I agree, it looks like most of these are:
> 
> (1) already exposed through ethtool commands (ETHTOOL_GSET,
> ETHTOOL_GDRVINFO, ETHTOOL_GLINK and ETHTOOL_GPERMADDR), or
> (2) already exposed through rtnetlink or the net device in sysfs, or
> (3) statistics that should be exposed through ETHTOOL_GSTATS
> 
> I imagine there are some that don't fall into those categories, but I
> don't see why they should *all* be exposed in a non-standard and/or
> redundant way.


The redundancy with ethtool doesn't bother me much, because I think sysfs is a more general way to export driver information, and I find it very convenient to get as much as is practical from a single source. I really like doing "grep . * */*" in sysfs and getting as much information as possible about a driver.

That said, there does appear to be duplication with some existing sysfs statistics, which should not be needed, and I think the volume of code in the implementation can be reduced as well.

-- 
Mark Rustad, LAN Access Division, Intel Corporation

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [net-next 3/3] ixgbe: add syfs interface for to export read only driver information
  2012-04-05 23:52       ` Rustad, Mark D
@ 2012-04-06  0:59         ` David Miller
  0 siblings, 0 replies; 10+ messages in thread
From: David Miller @ 2012-04-06  0:59 UTC (permalink / raw)
  To: mark.d.rustad
  Cc: bhutchings, florian, jeffrey.t.kirsher, donald.c.skidmore,
	netdev, gospo, sassmann

From: "Rustad, Mark D" <mark.d.rustad@intel.com>
Date: Thu, 5 Apr 2012 23:52:40 +0000

> The redundancy with ethtool doesn't bother me much, because I think
> sysfs is a more general way to export driver information, and I find
> it very convenient to get as much as is practical from a single
> source. I really like doing "grep . * */*" in sysfs and getting as
> much information as possible about a driver.

That's not our position, we have flexible, extensible, interfaces
such as ethtool and netlink so that people don't get the urge
to toss random unnecessary junk into sysfs.

There are no damn APIs for what driver guys want to put into
sysfs, making it terrible from a user's perspective.

Whereas ethtool and netlink give you something consistent and
reliable.

Therefore there will be hard pushback on anything one tries to
export via sysfs, it is almost guarenteed that ethtool and
netlink fit the bill properly.
 

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-04-06  0:59 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-05 10:47 [net-next 0/3][pull request] Intel Wired LAN Driver Update Jeff Kirsher
2012-04-05 10:47 ` [net-next 1/3] ixgbe: add support functions to access thermal data Jeff Kirsher
2012-04-05 10:47 ` [net-next 2/3] ixgbe: add hwmon interface to export " Jeff Kirsher
2012-04-05 10:47 ` [net-next 3/3] ixgbe: add syfs interface for to export read only driver information Jeff Kirsher
2012-04-05 12:19   ` Florian Fainelli
2012-04-05 16:32     ` Ben Hutchings
2012-04-05 22:49       ` David Miller
2012-04-05 23:01         ` Skidmore, Donald C
2012-04-05 23:52       ` Rustad, Mark D
2012-04-06  0:59         ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.