[Intel-wired-lan] i350 software defined pins sysfs access
Max Lapshin
max at flussonic.com
Tue Jun 11 21:01:49 UTC 2019
Hi.
Intel i350 nic has software defined pins. I have a custom hardware where these pins are connected to
some peripheral and I need to enable/disable them.
Here is patch that enables access to them. I can turn off peripheral device by:
echo 0 > /sys/class/net/eth1/device/pin2
and turn on by:
echo 1 > /sys/class/net/eth1/device/pin2
Please, give any corrections and advices if this patch requires any changes.
It is made again git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git <git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git> dev-queue
Subject: [PATCH] i350: Add support for Intel i350 software defined pins
NIC i350 with igb driver has software defined pins.
Allow to access them via sysfs files.
---
drivers/net/ethernet/intel/igb/igb.h | 28 +++++
drivers/net/ethernet/intel/igb/igb_main.c | 127 +++++++++++++++++++++-
2 files changed, 154 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index ca54e268d157..2453674464fa 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -79,6 +79,20 @@ struct igb_adapter;
#define IGB_I210_RX_LATENCY_100 2213
#define IGB_I210_RX_LATENCY_1000 448
+
+/* Software defined pins 0-1 */
+#define IGB_CTRL_SDP0_DATA 0x00040000 /* Value of SW Defineable Pin 0 */
+#define IGB_CTRL_SDP1_DATA 0x00080000 /* Value of SW Defineable Pin 1 */
+#define IGB_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
+#define IGB_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
+
+/* Software defined pins 2-3 */
+#define IGB_CTRL_EXT_SDP2_DATA E1000_CTRL_EXT_SDP2_DATA /* Value of SW Defineable Pin 2 */
+#define IGB_CTRL_EXT_SDP3_DATA E1000_CTRL_EXT_SDP3_DATA /* Value of SW Defineable Pin 3 */
+#define IGB_CTRL_EXT_SDP2_DIR E1000_CTRL_EXT_SDP2_DIR /* SDP2 Data direction */
+#define IGB_CTRL_EXT_SDP3_DIR E1000_CTRL_EXT_SDP3_DIR /* SDP3 Data direction */
+
+
struct vf_data_storage {
unsigned char vf_mac_addresses[ETH_ALEN];
u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
@@ -380,6 +394,16 @@ static inline int igb_desc_unused(struct igb_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
+#define IGB_SDP_COUNT 4
+#define IGB_MAX_SDPS 4
+// Software defined pins
+struct sdp_attr {
+ struct device_attribute dev_attr;
+ u32 pin;
+ struct igb_adapter *adapter;
+ char name[12];
+};
+
#ifdef CONFIG_IGB_HWMON
#define IGB_HWMON_TYPE_LOC 0
@@ -568,6 +592,10 @@ struct igb_adapter {
} perout[IGB_N_PEROUT];
char fw_version[32];
+
+ u32 n_sdp;
+ struct sdp_attr sdp_attrs[IGB_MAX_SDPS];
+
#ifdef CONFIG_IGB_HWMON
struct hwmon_buff *igb_hwmon_buff;
bool ets;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index fc925adbd9fa..447417fb4d3f 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -40,7 +40,7 @@
#define MAJ 5
#define MIN 6
-#define BUILD 0
+#define BUILD 1
#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
__stringify(BUILD) "-k"
@@ -2484,6 +2484,129 @@ static int igb_set_features(struct net_device *netdev,
return 1;
}
+static u32 igb_sdp_direction_bit(u32 pin)
+{
+ return pin == 0 ? IGB_CTRL_SDP0_DIR :
+ pin == 1 ? IGB_CTRL_SDP1_DIR :
+ pin == 2 ? IGB_CTRL_EXT_SDP2_DIR :
+ pin == 3 ? IGB_CTRL_EXT_SDP3_DIR : 0xFFFFFFFF;
+}
+
+static u32 igb_sdp_value_bit(u32 pin)
+{
+ return pin == IGB_CTRL_SDP0_DIR ? 18 :
+ pin == 1 ? IGB_CTRL_SDP1_DIR :
+ pin == 2 ? IGB_CTRL_EXT_SDP2_DIR :
+ pin == 3 ? IGB_CTRL_EXT_SDP3_DIR : 0xFFFFFFFF;
+}
+
+static u32 igb_sdp_register(u32 pin)
+{
+ return pin <= 1 ? E1000_CTRL : E1000_CTRL_EXT;
+}
+
+static ssize_t igb_sdp_get(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ volatile u32 ctrl_value;
+ struct sdp_attr *igb_attr = container_of(attr, struct sdp_attr,
+ dev_attr);
+ struct e1000_hw *hw = &igb_attr->adapter->hw;
+ u32 reg_number;
+
+ reg_number = igb_sdp_register(igb_attr->pin);
+ ctrl_value = rd32(reg_number);
+ wr32(reg_number, ctrl_value & ~(1 << igb_sdp_direction_bit(igb_attr->pin)));
+ ctrl_value = rd32(reg_number);
+
+ return sprintf(buf, "%d\n", (ctrl_value >> igb_sdp_value_bit(igb_attr->pin)) & 1);
+}
+
+static ssize_t igb_sdp_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sdp_attr *igb_attr = container_of(attr, struct sdp_attr,
+ dev_attr);
+ struct e1000_hw *hw = &igb_attr->adapter->hw;
+ int on = -1;
+ volatile u32 ctrl_value;
+ u32 reg_number;
+ u32 value_bit;
+
+
+ sscanf(buf, "%d", &on);
+ on = on == 0 ? 0 : 1;
+
+ //Software defined pins live on different registers:
+ //0 and 1 live on CTRL, 2 and 3 live on CTRL_EXT
+ reg_number = igb_sdp_register(igb_attr->pin);
+
+ ctrl_value = rd32(reg_number);
+ ctrl_value |= (1 << igb_sdp_direction_bit(igb_attr->pin));
+
+ value_bit = igb_sdp_value_bit(igb_attr->pin);
+ if(on) {
+ ctrl_value |= 1 << value_bit;
+ } else {
+ ctrl_value &= ~(1 << value_bit);
+ }
+
+ wr32(reg_number, ctrl_value);
+ return count;
+}
+
+
+static int igb_add_sdp_attr(struct igb_adapter *adapter, u32 pin)
+{
+
+ struct sdp_attr *igb_attr;
+
+ u32 n_sdp;
+ n_sdp = adapter->n_sdp;
+ if(n_sdp > IGB_MAX_SDPS) {
+ return ENOMEM;
+ }
+
+ igb_attr = &adapter->sdp_attrs[n_sdp];
+ igb_attr->adapter = adapter;
+ igb_attr->pin = pin;
+ snprintf(igb_attr->name, sizeof(igb_attr->name), "pin%d", pin);
+
+ igb_attr->dev_attr.show = igb_sdp_get;
+ igb_attr->dev_attr.store = igb_sdp_set;
+ igb_attr->dev_attr.attr.mode = 0660;
+ igb_attr->dev_attr.attr.name = igb_attr->name;
+ sysfs_attr_init(&igb_attr->dev_attr.attr);
+
+ adapter->n_sdp++;
+ return device_create_file(&adapter->pdev->dev,
+ &igb_attr->dev_attr);
+}
+
+
+static void igb_sdp_del(struct igb_adapter *adapter)
+{
+ u32 i;
+ for(i = 0; i < adapter->n_sdp; i++) {
+ device_remove_file(&adapter->pdev->dev, &adapter->sdp_attrs[i].dev_attr);
+ }
+}
+
+static int igb_sdp_init(struct igb_adapter *adapter)
+{
+ u32 i;
+ int rc = 0;
+ for(i = 0; i < IGB_SDP_COUNT; i++) {
+ rc = igb_add_sdp_attr(adapter, i);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+
static int igb_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid,
@@ -3383,6 +3506,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->ets = false;
}
#endif
+ igb_sdp_init(adapter);
/* Check if Media Autosense is enabled */
adapter->ei = *ei;
if (hw->dev_spec._82575.mas_capable)
@@ -3642,6 +3766,7 @@ static void igb_remove(struct pci_dev *pdev)
#ifdef CONFIG_IGB_HWMON
igb_sysfs_exit(adapter);
#endif
+ igb_sdp_del(adapter);
igb_remove_i2c(adapter);
igb_ptp_stop(adapter);
/* The watchdog timer may be rescheduled, so explicitly
--
2.17.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osuosl.org/pipermail/intel-wired-lan/attachments/20190612/872c2c28/attachment-0001.html>
More information about the Intel-wired-lan
mailing list