Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next 2/2] net: phy: add phy_speed_down and phy_speed_up
From: Andrew Lunn @ 2018-07-12 19:09 UTC (permalink / raw)
  To: Heiner Kallweit; +Cc: Florian Fainelli, David Miller, netdev@vger.kernel.org
In-Reply-To: <0354bc0f-4bac-9715-e183-1a74b9cc6f1b@gmail.com>

> Like r8169 also tg3 driver doesn't wait for the speed-down-renegotiation
> to finish. Therefore, even though I share Andrew's concerns, there seem
> to be chips where it's safe to not wait for the renegotiation to finish
> (e.g. because device is in PCI D3 already and can't generate an interrupt).
> Having said that I'd keep the sync parameter for phy_speed_down so that
> the driver can decide.

Hi Heiner

Please put a big fat comment about the dangers of sync=false in the
function header. We want people to known it is dangerous by default,
and should only be used in special conditions, when it is known to be
safe.
	Andrew

^ permalink raw reply

* [PATCH v2 net-next 9/9] lan743x: Add PTP support
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

PTP support includes:
    Ingress, and egress timestamping.
    PTP clock support
    Pulse per second output on GPIO

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/Makefile          |    2 +-
 drivers/net/ethernet/microchip/lan743x_ethtool.c |   28 +
 drivers/net/ethernet/microchip/lan743x_main.c    |   81 +-
 drivers/net/ethernet/microchip/lan743x_main.h    |   96 +-
 drivers/net/ethernet/microchip/lan743x_ptp.c     | 1194 ++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_ptp.h     |   78 ++
 6 files changed, 1474 insertions(+), 5 deletions(-)
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ptp.c
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ptp.h

diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index 43f47cb..538926d 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_ENCX24J600) += encx24j600.o encx24j600-regmap.o
 obj-$(CONFIG_LAN743X) += lan743x.o
 
-lan743x-objs := lan743x_main.o lan743x_ethtool.o
+lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 33d6c2d..8800716 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -4,6 +4,7 @@
 #include <linux/netdevice.h>
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
+#include <linux/net_tstamp.h>
 #include <linux/pci.h>
 #include <linux/phy.h>
 
@@ -542,6 +543,32 @@ static int lan743x_ethtool_set_rxfh(struct net_device *netdev,
 	return 0;
 }
 
+static int lan743x_ethtool_get_ts_info(struct net_device *netdev,
+				       struct ethtool_ts_info *ts_info)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
+				   SOF_TIMESTAMPING_RX_SOFTWARE |
+				   SOF_TIMESTAMPING_SOFTWARE |
+				   SOF_TIMESTAMPING_TX_HARDWARE |
+				   SOF_TIMESTAMPING_RX_HARDWARE |
+				   SOF_TIMESTAMPING_RAW_HARDWARE;
+#ifdef CONFIG_PTP_1588_CLOCK
+	if (adapter->ptp.ptp_clock)
+		ts_info->phc_index = ptp_clock_index(adapter->ptp.ptp_clock);
+	else
+		ts_info->phc_index = -1;
+#else
+	ts_info->phc_index = -1;
+#endif
+	ts_info->tx_types = BIT(HWTSTAMP_TX_OFF) |
+			    BIT(HWTSTAMP_TX_ON);
+	ts_info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+			      BIT(HWTSTAMP_FILTER_ALL);
+	return 0;
+}
+
 static int lan743x_ethtool_get_eee(struct net_device *netdev,
 				   struct ethtool_eee *eee)
 {
@@ -690,6 +717,7 @@ const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_rxfh_indir_size = lan743x_ethtool_get_rxfh_indir_size,
 	.get_rxfh = lan743x_ethtool_get_rxfh,
 	.set_rxfh = lan743x_ethtool_set_rxfh,
+	.get_ts_info = lan743x_ethtool_get_ts_info,
 	.get_eee = lan743x_ethtool_get_eee,
 	.set_eee = lan743x_ethtool_set_eee,
 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 953b581..ca9ae49 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -267,6 +267,10 @@ static void lan743x_intr_shared_isr(void *context, u32 int_sts, u32 flags)
 			lan743x_intr_software_isr(adapter);
 			int_sts &= ~INT_BIT_SW_GP_;
 		}
+		if (int_sts & INT_BIT_1588_) {
+			lan743x_ptp_isr(adapter);
+			int_sts &= ~INT_BIT_1588_;
+		}
 	}
 	if (int_sts)
 		lan743x_csr_write(adapter, INT_EN_CLR, int_sts);
@@ -976,6 +980,7 @@ static void lan743x_phy_link_status_change(struct net_device *netdev)
 					       ksettings.base.duplex,
 					       local_advertisement,
 					       remote_advertisement);
+		lan743x_ptp_update_latency(adapter, ksettings.base.speed);
 	}
 }
 
@@ -1256,11 +1261,29 @@ static void lan743x_tx_release_desc(struct lan743x_tx *tx,
 		buffer_info->dma_ptr = 0;
 		buffer_info->buffer_length = 0;
 	}
-	if (buffer_info->skb) {
+	if (!buffer_info->skb)
+		goto clear_active;
+
+	if (!(buffer_info->flags &
+		TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED)) {
 		dev_kfree_skb(buffer_info->skb);
-		buffer_info->skb = NULL;
+		goto clear_skb;
 	}
 
+	if (cleanup) {
+		lan743x_ptp_unrequest_tx_timestamp(tx->adapter);
+		dev_kfree_skb(buffer_info->skb);
+	} else {
+		lan743x_ptp_tx_timestamp_skb(tx->adapter,
+					     buffer_info->skb,
+					     (buffer_info->flags &
+					     TX_BUFFER_INFO_FLAG_IGNORE_SYNC)
+					     != 0);
+	}
+
+clear_skb:
+	buffer_info->skb = NULL;
+
 clear_active:
 	buffer_info->flags &= ~TX_BUFFER_INFO_FLAG_ACTIVE;
 
@@ -1321,10 +1344,25 @@ static int lan743x_tx_get_avail_desc(struct lan743x_tx *tx)
 		return last_head - last_tail - 1;
 }
 
+void lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx,
+				      bool enable_timestamping,
+				      bool enable_onestep_sync)
+{
+	if (enable_timestamping)
+		tx->ts_flags |= TX_TS_FLAG_TIMESTAMPING_ENABLED;
+	else
+		tx->ts_flags &= ~TX_TS_FLAG_TIMESTAMPING_ENABLED;
+	if (enable_onestep_sync)
+		tx->ts_flags |= TX_TS_FLAG_ONE_STEP_SYNC;
+	else
+		tx->ts_flags &= ~TX_TS_FLAG_ONE_STEP_SYNC;
+}
+
 static int lan743x_tx_frame_start(struct lan743x_tx *tx,
 				  unsigned char *first_buffer,
 				  unsigned int first_buffer_length,
 				  unsigned int frame_length,
+				  bool time_stamp,
 				  bool check_sum)
 {
 	/* called only from within lan743x_tx_xmit_frame.
@@ -1362,6 +1400,8 @@ static int lan743x_tx_frame_start(struct lan743x_tx *tx,
 		TX_DESC_DATA0_DTYPE_DATA_ |
 		TX_DESC_DATA0_FS_ |
 		TX_DESC_DATA0_FCS_;
+	if (time_stamp)
+		tx->frame_data0 |= TX_DESC_DATA0_TSE_;
 
 	if (check_sum)
 		tx->frame_data0 |= TX_DESC_DATA0_ICE_ |
@@ -1475,6 +1515,7 @@ static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx,
 
 static void lan743x_tx_frame_end(struct lan743x_tx *tx,
 				 struct sk_buff *skb,
+				 bool time_stamp,
 				 bool ignore_sync)
 {
 	/* called only from within lan743x_tx_xmit_frame
@@ -1492,6 +1533,8 @@ static void lan743x_tx_frame_end(struct lan743x_tx *tx,
 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
 	buffer_info = &tx->buffer_info[tx->frame_tail];
 	buffer_info->skb = skb;
+	if (time_stamp)
+		buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED;
 	if (ignore_sync)
 		buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC;
 
@@ -1520,6 +1563,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	unsigned int frame_length = 0;
 	unsigned int head_length = 0;
 	unsigned long irq_flags = 0;
+	bool do_timestamp = false;
 	bool ignore_sync = false;
 	int nr_frags = 0;
 	bool gso = false;
@@ -1541,6 +1585,16 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	}
 
 	/* space available, transmit skb  */
+	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
+		if (tx->ts_flags & TX_TS_FLAG_TIMESTAMPING_ENABLED) {
+			if (lan743x_ptp_request_tx_timestamp(tx->adapter)) {
+				skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+				do_timestamp = true;
+				if (tx->ts_flags & TX_TS_FLAG_ONE_STEP_SYNC)
+					ignore_sync = true;
+			}
+		}
+	}
 	head_length = skb_headlen(skb);
 	frame_length = skb_pagelen(skb);
 	nr_frags = skb_shinfo(skb)->nr_frags;
@@ -1554,6 +1608,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	if (lan743x_tx_frame_start(tx,
 				   skb->data, head_length,
 				   start_frame_length,
+				   do_timestamp,
 				   skb->ip_summed == CHECKSUM_PARTIAL)) {
 		dev_kfree_skb(skb);
 		goto unlock;
@@ -1581,7 +1636,7 @@ static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
 	}
 
 finish:
-	lan743x_tx_frame_end(tx, skb, ignore_sync);
+	lan743x_tx_frame_end(tx, skb, do_timestamp, ignore_sync);
 
 unlock:
 	spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
@@ -2410,6 +2465,8 @@ static int lan743x_netdev_close(struct net_device *netdev)
 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++)
 		lan743x_rx_close(&adapter->rx[index]);
 
+	lan743x_ptp_close(adapter);
+
 	lan743x_phy_close(adapter);
 
 	lan743x_mac_close(adapter);
@@ -2437,6 +2494,10 @@ static int lan743x_netdev_open(struct net_device *netdev)
 	if (ret)
 		goto close_mac;
 
+	ret = lan743x_ptp_open(adapter);
+	if (ret)
+		goto close_phy;
+
 	lan743x_rfe_open(adapter);
 
 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
@@ -2456,6 +2517,9 @@ static int lan743x_netdev_open(struct net_device *netdev)
 		if (adapter->rx[index].ring_cpu_ptr)
 			lan743x_rx_close(&adapter->rx[index]);
 	}
+	lan743x_ptp_close(adapter);
+
+close_phy:
 	lan743x_phy_close(adapter);
 
 close_mac:
@@ -2483,6 +2547,8 @@ static int lan743x_netdev_ioctl(struct net_device *netdev,
 {
 	if (!netif_running(netdev))
 		return -EINVAL;
+	if (cmd == SIOCSHWTSTAMP)
+		return lan743x_ptp_ioctl(netdev, ifr, cmd);
 	return phy_mii_ioctl(netdev->phydev, ifr, cmd);
 }
 
@@ -2607,6 +2673,11 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
 	adapter->intr.irq = adapter->pdev->irq;
 	lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
 	mutex_init(&adapter->dp_lock);
+
+	ret = lan743x_gpio_init(adapter);
+	if (ret)
+		return ret;
+
 	ret = lan743x_mac_init(adapter);
 	if (ret)
 		return ret;
@@ -2615,6 +2686,10 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
 	if (ret)
 		return ret;
 
+	ret = lan743x_ptp_init(adapter);
+	if (ret)
+		return ret;
+
 	lan743x_rfe_update_mac_address(adapter);
 
 	ret = lan743x_dmac_init(adapter);
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 4fa7a5e..578a618 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -4,12 +4,17 @@
 #ifndef _LAN743X_H
 #define _LAN743X_H
 
+#include "lan743x_ptp.h"
+
 #define DRIVER_AUTHOR   "Bryan Whitehead <Bryan.Whitehead@microchip.com>"
 #define DRIVER_DESC "LAN743x PCIe Gigabit Ethernet Driver"
 #define DRIVER_NAME "lan743x"
 
 /* Register Definitions */
 #define ID_REV				(0x00)
+#define ID_REV_ID_MASK_			(0xFFFF0000)
+#define ID_REV_ID_LAN7430_		(0x74300000)
+#define ID_REV_ID_LAN7431_		(0x74310000)
 #define ID_REV_IS_VALID_CHIP_ID_(id_rev)	\
 	(((id_rev) & 0xFFF00000) == 0x74300000)
 #define ID_REV_CHIP_REV_MASK_		(0x0000FFFF)
@@ -62,6 +67,21 @@
 
 #define E2P_DATA			(0x044)
 
+#define GPIO_CFG0			(0x050)
+#define GPIO_CFG0_GPIO_DIR_BIT_(bit)	BIT(16 + (bit))
+#define GPIO_CFG0_GPIO_DATA_BIT_(bit)	BIT(0 + (bit))
+
+#define GPIO_CFG1			(0x054)
+#define GPIO_CFG1_GPIOEN_BIT_(bit)	BIT(16 + (bit))
+#define GPIO_CFG1_GPIOBUF_BIT_(bit)	BIT(0 + (bit))
+
+#define GPIO_CFG2			(0x058)
+#define GPIO_CFG2_1588_POL_BIT_(bit)	BIT(0 + (bit))
+
+#define GPIO_CFG3			(0x05C)
+#define GPIO_CFG3_1588_CH_SEL_BIT_(bit)	BIT(16 + (bit))
+#define GPIO_CFG3_1588_OE_BIT_(bit)	BIT(0 + (bit))
+
 #define FCT_RX_CTL			(0xAC)
 #define FCT_RX_CTL_EN_(channel)		BIT(28 + (channel))
 #define FCT_RX_CTL_DIS_(channel)	BIT(24 + (channel))
@@ -193,7 +213,8 @@
 #define INT_BIT_DMA_TX_(channel)	BIT(16 + (channel))
 #define INT_BIT_ALL_TX_			(0x000F0000)
 #define INT_BIT_SW_GP_			BIT(9)
-#define INT_BIT_ALL_OTHER_		(0x00000280)
+#define INT_BIT_1588_			BIT(7)
+#define INT_BIT_ALL_OTHER_		(INT_BIT_SW_GP_ | INT_BIT_1588_)
 #define INT_BIT_MAS_			BIT(0)
 
 #define INT_SET				(0x784)
@@ -234,6 +255,66 @@
 #define INT_MOD_CFG6			(0x7D8)
 #define INT_MOD_CFG7			(0x7DC)
 
+#define PTP_CMD_CTL					(0x0A00)
+#define PTP_CMD_CTL_PTP_CLK_STP_NSEC_			BIT(6)
+#define PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_			BIT(5)
+#define PTP_CMD_CTL_PTP_CLOCK_LOAD_			BIT(4)
+#define PTP_CMD_CTL_PTP_CLOCK_READ_			BIT(3)
+#define PTP_CMD_CTL_PTP_ENABLE_				BIT(2)
+#define PTP_CMD_CTL_PTP_DISABLE_			BIT(1)
+#define PTP_CMD_CTL_PTP_RESET_				BIT(0)
+#define PTP_GENERAL_CONFIG				(0x0A04)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_(channel) \
+	(0x7 << (1 + ((channel) << 2)))
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_	(2)
+#define PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_(channel, value) \
+	(((value) & 0x7) << (1 + ((channel) << 2)))
+#define PTP_GENERAL_CONFIG_RELOAD_ADD_X_(channel)	(BIT((channel) << 2))
+
+#define PTP_INT_STS				(0x0A08)
+#define PTP_INT_EN_SET				(0x0A0C)
+#define PTP_INT_EN_CLR				(0x0A10)
+#define PTP_INT_BIT_TX_SWTS_ERR_		BIT(13)
+#define PTP_INT_BIT_TX_TS_			BIT(12)
+#define PTP_INT_BIT_TIMER_B_			BIT(1)
+#define PTP_INT_BIT_TIMER_A_			BIT(0)
+
+#define PTP_CLOCK_SEC				(0x0A14)
+#define PTP_CLOCK_NS				(0x0A18)
+#define PTP_CLOCK_SUBNS				(0x0A1C)
+#define PTP_CLOCK_RATE_ADJ			(0x0A20)
+#define PTP_CLOCK_RATE_ADJ_DIR_			BIT(31)
+#define PTP_CLOCK_STEP_ADJ			(0x0A2C)
+#define PTP_CLOCK_STEP_ADJ_DIR_			BIT(31)
+#define PTP_CLOCK_STEP_ADJ_VALUE_MASK_		(0x3FFFFFFF)
+#define PTP_CLOCK_TARGET_SEC_X(channel)		(0x0A30 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_NS_X(channel)		(0x0A34 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_RELOAD_SEC_X(channel)	(0x0A38 + ((channel) << 4))
+#define PTP_CLOCK_TARGET_RELOAD_NS_X(channel)	(0x0A3C + ((channel) << 4))
+#define PTP_LATENCY				(0x0A5C)
+#define PTP_LATENCY_TX_SET_(tx_latency)		(((u32)(tx_latency)) << 16)
+#define PTP_LATENCY_RX_SET_(rx_latency)		\
+	(((u32)(rx_latency)) & 0x0000FFFF)
+#define PTP_CAP_INFO				(0x0A60)
+#define PTP_CAP_INFO_TX_TS_CNT_GET_(reg_val)	((reg_val & 0x00000070) >> 4)
+
+#define PTP_TX_MOD				(0x0AA4)
+#define PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_	(0x10000000)
+
+#define PTP_TX_MOD2				(0x0AA8)
+#define PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_	(0x00000001)
+
+#define PTP_TX_EGRESS_SEC			(0x0AAC)
+#define PTP_TX_EGRESS_NS			(0x0AB0)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_	(0xC0000000)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_	(0x00000000)
+#define PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_	(0x40000000)
+#define PTP_TX_EGRESS_NS_TS_NS_MASK_		(0x3FFFFFFF)
+
+#define PTP_TX_MSG_HEADER			(0x0AB4)
+#define PTP_TX_MSG_HEADER_MSG_TYPE_		(0x000F0000)
+#define PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_	(0x00000000)
+
 #define DMAC_CFG				(0xC00)
 #define DMAC_CFG_COAL_EN_			BIT(16)
 #define DMAC_CFG_CH_ARB_SEL_RX_HIGH_		(0x00000000)
@@ -542,8 +623,12 @@ struct lan743x_tx_buffer_info;
 
 #define TX_FRAME_FLAG_IN_PROGRESS	BIT(0)
 
+#define TX_TS_FLAG_TIMESTAMPING_ENABLED	BIT(0)
+#define TX_TS_FLAG_ONE_STEP_SYNC	BIT(1)
+
 struct lan743x_tx {
 	struct lan743x_adapter *adapter;
+	u32	ts_flags;
 	u32	vector_flags;
 	int	channel_number;
 
@@ -570,6 +655,10 @@ struct lan743x_tx {
 	struct sk_buff *overflow_skb;
 };
 
+void lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx,
+				      bool enable_timestamping,
+				      bool enable_onestep_sync);
+
 /* RX */
 struct lan743x_rx_descriptor;
 struct lan743x_rx_buffer_info;
@@ -610,6 +699,9 @@ struct lan743x_adapter {
 	/* lock, used to prevent concurrent access to data port */
 	struct mutex		dp_lock;
 
+	struct lan743x_gpio	gpio;
+	struct lan743x_ptp	ptp;
+
 	u8			mac_address[ETH_ALEN];
 
 	struct lan743x_phy      phy;
@@ -660,6 +752,7 @@ struct lan743x_adapter {
 #define TX_DESC_DATA0_IPE_			(0x00200000)
 #define TX_DESC_DATA0_TPE_			(0x00100000)
 #define TX_DESC_DATA0_FCS_			(0x00020000)
+#define TX_DESC_DATA0_TSE_			(0x00010000)
 #define TX_DESC_DATA0_BUF_LENGTH_MASK_		(0x0000FFFF)
 #define TX_DESC_DATA0_EXT_LSO_			(0x00200000)
 #define TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_	(0x000FFFFF)
@@ -673,6 +766,7 @@ struct lan743x_tx_descriptor {
 } __aligned(DEFAULT_DMA_DESCRIPTOR_SPACING);
 
 #define TX_BUFFER_INFO_FLAG_ACTIVE		BIT(0)
+#define TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED	BIT(1)
 #define TX_BUFFER_INFO_FLAG_IGNORE_SYNC		BIT(2)
 #define TX_BUFFER_INFO_FLAG_SKB_FRAGMENT	BIT(3)
 struct lan743x_tx_buffer_info {
diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c
new file mode 100644
index 0000000..f14565b
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_ptp.c
@@ -0,0 +1,1194 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2018 Microchip Technology Inc. */
+
+#include <linux/netdevice.h>
+#include "lan743x_main.h"
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/net_tstamp.h>
+
+#include "lan743x_ptp.h"
+
+/* GPIO */
+#define LAN743X_NUMBER_OF_GPIO          (12)
+
+int lan743x_gpio_init(struct lan743x_adapter *adapter)
+{
+	struct lan743x_gpio *gpio = &adapter->gpio;
+
+	spin_lock_init(&gpio->gpio_lock);
+
+	gpio->gpio_cfg0 = 0; /* set all direction to input, data = 0 */
+	gpio->gpio_cfg1 = 0x0FFF0000;/* disable all gpio, set to open drain */
+	gpio->gpio_cfg2 = 0;/* set all to 1588 low polarity level */
+	gpio->gpio_cfg3 = 0;/* disable all 1588 output */
+	lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+	lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+	lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
+	lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
+
+	return 0;
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_gpio_reserve_ptp_output(struct lan743x_adapter *adapter,
+					   int bit, int ptp_channel)
+{
+	struct lan743x_gpio *gpio = &adapter->gpio;
+	unsigned long irq_flags = 0;
+	int bit_mask = BIT(bit);
+	int ret = -EBUSY;
+
+	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
+
+	if (!(gpio->used_bits & bit_mask)) {
+		gpio->used_bits |= bit_mask;
+		gpio->output_bits |= bit_mask;
+		gpio->ptp_bits |= bit_mask;
+
+		/* set as output, and zero initial value */
+		gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(bit);
+		gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+
+		/* enable gpio , and set buffer type to push pull */
+		gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(bit);
+		gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+
+		/* set 1588 polarity to high */
+		gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2);
+
+		if (!ptp_channel) {
+			/* use channel A */
+			gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(bit);
+		} else {
+			/* use channel B */
+			gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(bit);
+		}
+		gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(bit);
+		lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3);
+
+		ret = bit;
+	}
+	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
+	return ret;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_gpio_release(struct lan743x_adapter *adapter, int bit)
+{
+	struct lan743x_gpio *gpio = &adapter->gpio;
+	unsigned long irq_flags = 0;
+	int bit_mask = BIT(bit);
+
+	spin_lock_irqsave(&gpio->gpio_lock, irq_flags);
+	if (gpio->used_bits & bit_mask) {
+		gpio->used_bits &= ~bit_mask;
+		if (gpio->output_bits & bit_mask) {
+			gpio->output_bits &= ~bit_mask;
+
+			if (gpio->ptp_bits & bit_mask) {
+				gpio->ptp_bits &= ~bit_mask;
+				/* disable ptp output */
+				gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(bit);
+				lan743x_csr_write(adapter, GPIO_CFG3,
+						  gpio->gpio_cfg3);
+			}
+			/* release gpio output */
+
+			/* disable gpio */
+			gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(bit);
+			gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(bit);
+			lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1);
+
+			/* reset back to input */
+			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(bit);
+			gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit);
+			lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0);
+		}
+	}
+	spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags);
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+/* PTP */
+#define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB (31249999)
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter);
+static void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter,
+					 int event_channel);
+#endif
+
+static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter);
+static void lan743x_ptp_enable(struct lan743x_adapter *adapter);
+static void lan743x_ptp_disable(struct lan743x_adapter *adapter);
+static void lan743x_ptp_reset(struct lan743x_adapter *adapter);
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
+				  u32 *seconds, u32 *nano_seconds,
+				  u32 *sub_nano_seconds);
+static int lan743x_ptp_enable_pps(struct lan743x_adapter *adapter);
+static void lan743x_ptp_disable_pps(struct lan743x_adapter *adapter);
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
+				   s64 time_step_ns);
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
+				  u32 seconds, u32 nano_seconds,
+				  u32 sub_nano_seconds);
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_adjfreq(struct ptp_clock_info *ptpci, s32 delta_ppb)
+{
+	struct lan743x_ptp *ptp = container_of(ptpci, struct lan743x_ptp,
+					       ptp_clock_info);
+	struct lan743x_adapter *adapter = container_of(ptp,
+						       struct lan743x_adapter,
+						       ptp);
+	u32 lan743x_rate_adj = 0;
+	bool positive = true;
+	u32 u32_delta = 0;
+	u64 u64_delta = 0;
+
+	if ((delta_ppb < (-LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB)) ||
+	    delta_ppb > LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB) {
+		return -EINVAL;
+	}
+	if (delta_ppb > 0) {
+		u32_delta = (u32)delta_ppb;
+		positive = true;
+	} else {
+		u32_delta = (u32)(-delta_ppb);
+		positive = false;
+	}
+	u64_delta = (((u64)u32_delta) * 0x800000000ULL);
+	lan743x_rate_adj = (u32)(u64_delta / 1000000000);
+
+	if (positive)
+		lan743x_rate_adj |= PTP_CLOCK_RATE_ADJ_DIR_;
+
+	lan743x_csr_write(adapter, PTP_CLOCK_RATE_ADJ,
+			  lan743x_rate_adj);
+
+	netif_info(adapter, drv, adapter->netdev,
+		   "adjfreq, delta_ppb = %d, lan743x_rate_adj = 0x%08X\n",
+		   delta_ppb, lan743x_rate_adj);
+	return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_adjtime(struct ptp_clock_info *ptpci, s64 delta)
+{
+	struct lan743x_ptp *ptp = container_of(ptpci, struct lan743x_ptp,
+					       ptp_clock_info);
+	struct lan743x_adapter *adapter = container_of(ptp,
+						       struct lan743x_adapter,
+						       ptp);
+	bool enable_pps = false;
+
+	if (ptp->pps_event_ch >= 0) {
+		lan743x_ptp_disable_pps(adapter);
+		enable_pps = true;
+	}
+
+	lan743x_ptp_clock_step(adapter, delta);
+	netif_info(adapter, drv, adapter->netdev,
+		   "adjtime, delta = %lld\n", delta);
+
+	if (enable_pps)
+		lan743x_ptp_enable_pps(adapter);
+
+	return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_gettime64(struct ptp_clock_info *ptpci,
+				   struct timespec64 *ts)
+{
+	struct lan743x_ptp *ptp = container_of(ptpci, struct lan743x_ptp,
+					       ptp_clock_info);
+	struct lan743x_adapter *adapter = container_of(ptp,
+						       struct lan743x_adapter,
+						       ptp);
+
+	if (ts) {
+		u32 seconds = 0;
+		u32 nano_seconds = 0;
+
+		lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
+		ts->tv_sec = seconds;
+		ts->tv_nsec = nano_seconds;
+		netif_info(adapter, drv, adapter->netdev,
+			   "gettime = %u.%09u\n", seconds, nano_seconds);
+	} else {
+		netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci,
+				   const struct timespec64 *ts)
+{
+	struct lan743x_ptp *ptp = container_of(ptpci, struct lan743x_ptp,
+					       ptp_clock_info);
+	struct lan743x_adapter *adapter = container_of(ptp,
+						       struct lan743x_adapter,
+						       ptp);
+	bool enable_pps = false;
+
+	if (ptp->pps_event_ch >= 0) {
+		lan743x_ptp_disable_pps(adapter);
+		enable_pps = true;
+	}
+
+	if (ts) {
+		u32 seconds = 0;
+		u32 nano_seconds = 0;
+
+		if (ts->tv_sec > 0xFFFFFFFFLL ||
+		    ts->tv_sec < 0) {
+			netif_warn(adapter, drv, adapter->netdev,
+				   "ts->tv_sec out of range, %lld\n",
+				   ts->tv_sec);
+			return -EINVAL;
+		}
+		if (ts->tv_nsec >= 1000000000L ||
+		    ts->tv_nsec < 0) {
+			netif_warn(adapter, drv, adapter->netdev,
+				   "ts->tv_nsec out of range, %ld\n",
+				   ts->tv_nsec);
+			return -EINVAL;
+		}
+		seconds = ts->tv_sec;
+		nano_seconds = ts->tv_nsec;
+		netif_info(adapter, drv, adapter->netdev,
+			   "settime = %u.%09u\n", seconds, nano_seconds);
+		lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
+	} else {
+		netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n");
+		return -EINVAL;
+	}
+
+	if (enable_pps)
+		lan743x_ptp_enable_pps(adapter);
+
+	return 0;
+}
+#endif /*CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_enable_pps(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	u32 current_seconds = 0;
+	u32 target_seconds = 0;
+	u32 general_config = 0;
+	int result = -ENODEV;
+	int pps_bit = 0;
+
+	if (ptp->pps_event_ch >= 0) {
+		result = 0;
+		goto done;
+	}
+
+	ptp->pps_event_ch = lan743x_ptp_reserve_event_ch(adapter);
+	if (ptp->pps_event_ch < 0) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "Failed to reserve event channel for PPS\n");
+		goto done;
+	}
+
+	switch(adapter->csr.id_rev & ID_REV_ID_MASK_) {
+	case ID_REV_ID_LAN7430_:
+		pps_bit = 2;/* GPIO 2 is preferred on EVB LAN7430 */
+		break;
+	case ID_REV_ID_LAN7431_:
+		pps_bit = 4;/* GPIO 4 is preferred on EVB LAN7431 */
+		break;
+	}
+
+	ptp->pps_gpio_bit = lan743x_gpio_reserve_ptp_output(adapter, pps_bit,
+							    ptp->pps_event_ch);
+
+	if (ptp->pps_gpio_bit < 0) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "Failed to reserve gpio 0 for PPS\n");
+		goto done;
+	}
+
+	lan743x_ptp_clock_get(adapter, &current_seconds, NULL, NULL);
+
+	/* set the first target ahead by 2 seconds
+	 *	to make sure its not missed
+	 */
+	target_seconds = current_seconds + 2;
+
+	/* set the new target */
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_SEC_X(ptp->pps_event_ch),
+			  0xFFFF0000);
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_NS_X(ptp->pps_event_ch), 0);
+
+	general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
+
+	general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_
+			  (ptp->pps_event_ch));
+	general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_
+			  (ptp->pps_event_ch,
+			   PTP_GENERAL_CONFIG_CLOCK_EVENT_100US_);
+	general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_
+			  (ptp->pps_event_ch);
+	lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
+
+	/* set the reload to one second steps */
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_RELOAD_SEC_X(ptp->pps_event_ch),
+			  1);
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_RELOAD_NS_X(ptp->pps_event_ch),
+			  0);
+
+	/* set the new target */
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_SEC_X(ptp->pps_event_ch),
+			  target_seconds);
+	lan743x_csr_write(adapter,
+			  PTP_CLOCK_TARGET_NS_X(ptp->pps_event_ch),
+			  0);
+	return 0;
+
+done:
+	if (ptp->pps_gpio_bit >= 0) {
+		lan743x_gpio_release(adapter, ptp->pps_gpio_bit);
+		ptp->pps_gpio_bit = -1;
+	}
+	if (ptp->pps_event_ch >= 0) {
+		lan743x_ptp_release_event_ch(adapter,
+					     ptp->pps_event_ch);
+		ptp->pps_event_ch = -1;
+	}
+	return result;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_disable_pps(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	if (ptp->pps_gpio_bit >= 0) {
+		lan743x_gpio_release(adapter, ptp->pps_gpio_bit);
+		ptp->pps_gpio_bit = -1;
+	}
+
+	if (ptp->pps_event_ch >= 0) {
+		u32 general_config = 0;
+
+		/* set target to far in the future, effectively disabling it */
+		lan743x_csr_write(adapter,
+				  PTP_CLOCK_TARGET_SEC_X(ptp->pps_event_ch),
+				  0xFFFF0000);
+		lan743x_csr_write(adapter,
+				  PTP_CLOCK_TARGET_NS_X(ptp->pps_event_ch), 0);
+
+		general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG);
+		general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_
+				  (ptp->pps_event_ch);
+		lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config);
+		lan743x_ptp_release_event_ch(adapter, ptp->pps_event_ch);
+		ptp->pps_event_ch = -1;
+	}
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci,
+				struct ptp_clock_request *request, int on)
+{
+	struct lan743x_ptp *ptp = container_of(ptpci, struct lan743x_ptp,
+					       ptp_clock_info);
+	struct lan743x_adapter *adapter = container_of(ptp,
+						       struct lan743x_adapter,
+						       ptp);
+
+	if (request) {
+		switch (request->type) {
+		case PTP_CLK_REQ_EXTTS:
+			return -EINVAL;
+		case PTP_CLK_REQ_PEROUT:
+			return -EINVAL;
+		case PTP_CLK_REQ_PPS:
+			if (on) {
+				if (lan743x_ptp_enable_pps(adapter) >= 0)
+					netif_info(adapter, drv,
+						   adapter->netdev,
+						   "PPS is ON\n");
+				else
+					netif_warn(adapter, drv,
+						   adapter->netdev,
+						   "Error starting PPS\n");
+			} else {
+				lan743x_ptp_disable_pps(adapter);
+				netif_info(adapter, drv, adapter->netdev,
+					   "PPS is OFF\n");
+			}
+			break;
+		default:
+			netif_err(adapter, drv, adapter->netdev,
+				  "request->type == %d, Unknown\n",
+				  request->type);
+			break;
+		}
+	} else {
+		netif_err(adapter, drv, adapter->netdev, "request == NULL\n");
+	}
+	return 0;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+void lan743x_ptp_isr(void *context)
+{
+	struct lan743x_adapter *adapter = (struct lan743x_adapter *)context;
+	struct lan743x_ptp *ptp = NULL;
+	int enable_flag = 1;
+	u32 ptp_int_sts = 0;
+
+	ptp = &adapter->ptp;
+
+	lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
+
+	ptp_int_sts = lan743x_csr_read(adapter, PTP_INT_STS);
+	ptp_int_sts &= lan743x_csr_read(adapter, PTP_INT_EN_SET);
+
+	if (ptp_int_sts & PTP_INT_BIT_TX_TS_) {
+		tasklet_schedule(&ptp->ptp_isr_bottom_half);
+		enable_flag = 0;/* tasklet will re-enable later */
+	}
+	if (ptp_int_sts & PTP_INT_BIT_TX_SWTS_ERR_) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "PTP TX Software Timestamp Error\n");
+		/* clear int status bit */
+		lan743x_csr_write(adapter, PTP_INT_STS,
+				  PTP_INT_BIT_TX_SWTS_ERR_);
+	}
+	if (ptp_int_sts & PTP_INT_BIT_TIMER_B_) {
+		netif_info(adapter, drv, adapter->netdev,
+			   "PTP TIMER B Interrupt\n");
+		/* clear int status bit */
+		lan743x_csr_write(adapter, PTP_INT_STS,
+				  PTP_INT_BIT_TIMER_B_);
+	}
+	if (ptp_int_sts & PTP_INT_BIT_TIMER_A_) {
+		netif_info(adapter, drv, adapter->netdev,
+			   "PTP TIMER A Interrupt\n");
+		/* clear int status bit */
+		lan743x_csr_write(adapter, PTP_INT_STS,
+				  PTP_INT_BIT_TIMER_A_);
+	}
+
+	if (enable_flag) {
+		/* re-enable isr */
+		lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+	}
+}
+
+static void lan743x_ptp_tx_ts_complete(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	int i;
+	int c;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	c = ptp->tx_ts_skb_queue_size;
+
+	if (c > ptp->tx_ts_queue_size)
+		c = ptp->tx_ts_queue_size;
+	if (c <= 0)
+		goto done;
+
+	for (i = 0; i < c; i++) {
+		bool ignore_sync = ((ptp->tx_ts_ignore_sync_queue &
+				    BIT(i)) != 0);
+		struct sk_buff *skb = ptp->tx_ts_skb_queue[i];
+		u32 nseconds = ptp->tx_ts_nseconds_queue[i];
+		u32 seconds = ptp->tx_ts_seconds_queue[i];
+		u32 header = ptp->tx_ts_header_queue[i];
+		struct skb_shared_hwtstamps tstamps;
+
+		memset(&tstamps, 0, sizeof(tstamps));
+		tstamps.hwtstamp = ktime_set(seconds, nseconds);
+		if (!ignore_sync ||
+		    ((header & PTP_TX_MSG_HEADER_MSG_TYPE_) !=
+		    PTP_TX_MSG_HEADER_MSG_TYPE_SYNC_))
+			skb_tstamp_tx(skb, &tstamps);
+
+		dev_kfree_skb(skb);
+
+		ptp->tx_ts_skb_queue[i] = NULL;
+		ptp->tx_ts_seconds_queue[i] = 0;
+		ptp->tx_ts_nseconds_queue[i] = 0;
+		ptp->tx_ts_header_queue[i] = 0;
+	}
+
+	/* shift queue */
+	ptp->tx_ts_ignore_sync_queue >>= c;
+	for (i = c; i < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS; i++) {
+		ptp->tx_ts_skb_queue[i - c] = ptp->tx_ts_skb_queue[i];
+		ptp->tx_ts_seconds_queue[i - c] = ptp->tx_ts_seconds_queue[i];
+		ptp->tx_ts_nseconds_queue[i - c] = ptp->tx_ts_nseconds_queue[i];
+		ptp->tx_ts_header_queue[i - c] = ptp->tx_ts_header_queue[i];
+
+		ptp->tx_ts_skb_queue[i] = NULL;
+		ptp->tx_ts_seconds_queue[i] = 0;
+		ptp->tx_ts_nseconds_queue[i] = 0;
+		ptp->tx_ts_header_queue[i] = 0;
+	}
+	ptp->tx_ts_skb_queue_size -= c;
+	ptp->tx_ts_queue_size -= c;
+done:
+	ptp->pending_tx_timestamps -= c;
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_tx_ts_enqueue_skb(struct lan743x_adapter *adapter,
+					  struct sk_buff *skb, bool ignore_sync)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->tx_ts_skb_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+		ptp->tx_ts_skb_queue[ptp->tx_ts_skb_queue_size] = skb;
+		if (ignore_sync)
+			ptp->tx_ts_ignore_sync_queue |=
+				BIT(ptp->tx_ts_skb_queue_size);
+		ptp->tx_ts_skb_queue_size++;
+	} else {
+		/* this should never happen, so long as the tx channel
+		 * calls and honors the result from
+		 * lan743x_ptp_request_tx_timestamp
+		 */
+		netif_err(adapter, drv, adapter->netdev,
+			  "tx ts skb queue overflow\n");
+		dev_kfree_skb(skb);
+	}
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_tx_ts_enqueue_ts(struct lan743x_adapter *adapter,
+					 u32 seconds, u32 nano_seconds,
+					 u32 header)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->tx_ts_queue_size < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+		ptp->tx_ts_seconds_queue[ptp->tx_ts_queue_size] = seconds;
+		ptp->tx_ts_nseconds_queue[ptp->tx_ts_queue_size] = nano_seconds;
+		ptp->tx_ts_header_queue[ptp->tx_ts_queue_size] = header;
+		ptp->tx_ts_queue_size++;
+	} else {
+		netif_err(adapter, drv, adapter->netdev,
+			  "tx ts queue overflow\n");
+	}
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+static void lan743x_ptp_isr_bottom_half(unsigned long param)
+{
+	struct lan743x_adapter *adapter = (struct lan743x_adapter *)param;
+	bool new_timestamp_available = false;
+
+	while (lan743x_csr_read(adapter, PTP_INT_STS) & PTP_INT_BIT_TX_TS_) {
+		u32 cap_info = lan743x_csr_read(adapter, PTP_CAP_INFO);
+
+		if (PTP_CAP_INFO_TX_TS_CNT_GET_(cap_info) > 0) {
+			u32 seconds = lan743x_csr_read(adapter,
+				PTP_TX_EGRESS_SEC);
+			u32 nsec = lan743x_csr_read(adapter, PTP_TX_EGRESS_NS);
+			u32 cause = (nsec &
+				     PTP_TX_EGRESS_NS_CAPTURE_CAUSE_MASK_);
+			u32 header = lan743x_csr_read(adapter,
+						      PTP_TX_MSG_HEADER);
+
+			if (cause == PTP_TX_EGRESS_NS_CAPTURE_CAUSE_SW_) {
+				nsec &= PTP_TX_EGRESS_NS_TS_NS_MASK_;
+				lan743x_ptp_tx_ts_enqueue_ts(adapter,
+							     seconds, nsec,
+							     header);
+				new_timestamp_available = true;
+			} else if (cause ==
+				PTP_TX_EGRESS_NS_CAPTURE_CAUSE_AUTO_) {
+				netif_err(adapter, drv, adapter->netdev,
+					  "Auto capture cause not supported\n");
+			} else {
+				netif_warn(adapter, drv, adapter->netdev,
+					   "unknown tx timestamp capture cause\n");
+			}
+		} else {
+			netif_warn(adapter, drv, adapter->netdev,
+				   "TX TS INT but no TX TS CNT\n");
+		}
+		lan743x_csr_write(adapter, PTP_INT_STS, PTP_INT_BIT_TX_TS_);
+	}
+
+	if (new_timestamp_available)
+		lan743x_ptp_tx_ts_complete(adapter);
+
+	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+}
+
+static void lan743x_ptp_sync_to_system_clock(struct lan743x_adapter *adapter)
+{
+	struct timeval tv;
+
+	memset(&tv, 0, sizeof(tv));
+	do_gettimeofday(&tv);
+	lan743x_ptp_clock_set(adapter, tv.tv_sec, tv.tv_usec * 1000, 0);
+}
+
+void lan743x_ptp_update_latency(struct lan743x_adapter *adapter,
+				u32 link_speed)
+{
+	switch (link_speed) {
+	case 10:
+		lan743x_csr_write(adapter, PTP_LATENCY,
+				  PTP_LATENCY_TX_SET_(0) |
+				  PTP_LATENCY_RX_SET_(0));
+		break;
+	case 100:
+		lan743x_csr_write(adapter, PTP_LATENCY,
+				  PTP_LATENCY_TX_SET_(181) |
+				  PTP_LATENCY_RX_SET_(594));
+		break;
+	case 1000:
+		lan743x_csr_write(adapter, PTP_LATENCY,
+				  PTP_LATENCY_TX_SET_(30) |
+				  PTP_LATENCY_RX_SET_(525));
+		break;
+	}
+}
+
+int lan743x_ptp_init(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_init(&ptp->command_lock);
+	spin_lock_init(&ptp->tx_ts_lock);
+	tasklet_init(&ptp->ptp_isr_bottom_half,
+		     lan743x_ptp_isr_bottom_half, (unsigned long)adapter);
+	tasklet_disable(&ptp->ptp_isr_bottom_half);
+	ptp->used_event_ch = 0;
+	ptp->pps_event_ch = -1;
+	ptp->pps_gpio_bit = -1;
+	return 0;
+}
+
+int lan743x_ptp_open(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	int ret = -ENODEV;
+	u32 temp;
+
+	lan743x_ptp_reset(adapter);
+	lan743x_ptp_sync_to_system_clock(adapter);
+	temp = lan743x_csr_read(adapter, PTP_TX_MOD2);
+	temp |= PTP_TX_MOD2_TX_PTP_CLR_UDPV4_CHKSUM_;
+	lan743x_csr_write(adapter, PTP_TX_MOD2, temp);
+	lan743x_ptp_enable(adapter);
+	tasklet_enable(&ptp->ptp_isr_bottom_half);
+	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_1588_);
+	lan743x_csr_write(adapter, PTP_INT_EN_SET,
+			  PTP_INT_BIT_TX_SWTS_ERR_ | PTP_INT_BIT_TX_TS_);
+	ptp->flags |= PTP_FLAG_ISR_ENABLED;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+	snprintf(ptp->pin_config[0].name, 32, "lan743x_ptp_pin_0");
+	ptp->pin_config[0].index = 0;
+	ptp->pin_config[0].func = PTP_PF_PEROUT;
+	ptp->pin_config[0].chan = 0;
+
+	ptp->ptp_clock_info.owner = THIS_MODULE;
+	snprintf(ptp->ptp_clock_info.name, 16, "%pm",
+		 adapter->netdev->dev_addr);
+	ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB;
+	ptp->ptp_clock_info.n_alarm = 0;
+	ptp->ptp_clock_info.n_ext_ts = 0;
+	ptp->ptp_clock_info.n_per_out = 0;
+	ptp->ptp_clock_info.n_pins = 0;
+	ptp->ptp_clock_info.pps = 1;
+	ptp->ptp_clock_info.pin_config = NULL;
+	ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq;
+	ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime;
+	ptp->ptp_clock_info.gettime64 = lan743x_ptpci_gettime64;
+	ptp->ptp_clock_info.getcrosststamp = NULL;
+	ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64;
+	ptp->ptp_clock_info.enable = lan743x_ptpci_enable;
+	ptp->ptp_clock_info.verify = NULL;
+
+	ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info,
+					    &adapter->pdev->dev);
+
+	if (IS_ERR(ptp->ptp_clock)) {
+		netif_err(adapter, ifup, adapter->netdev,
+			  "ptp_clock_register failed\n");
+		goto done;
+	}
+	ptp->flags |= PTP_FLAG_PTP_CLOCK_REGISTERED;
+	netif_info(adapter, ifup, adapter->netdev,
+		   "successfully registered ptp clock\n");
+#endif
+
+	return 0;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+done:
+	lan743x_ptp_close(adapter);
+	return ret;
+#endif
+}
+
+void lan743x_ptp_close(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	int index;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+	if (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED) {
+		ptp_clock_unregister(ptp->ptp_clock);
+		ptp->ptp_clock = NULL;
+		ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED;
+		netif_info(adapter, drv, adapter->netdev,
+			   "ptp clock unregister\n");
+	}
+#endif
+
+	if (ptp->flags & PTP_FLAG_ISR_ENABLED) {
+		lan743x_csr_write(adapter, PTP_INT_EN_CLR,
+				  PTP_INT_BIT_TX_SWTS_ERR_ |
+				  PTP_INT_BIT_TX_TS_);
+		lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_1588_);
+		tasklet_disable(&ptp->ptp_isr_bottom_half);
+		ptp->flags &= ~PTP_FLAG_ISR_ENABLED;
+	}
+
+	/* clean up pending timestamp requests */
+	lan743x_ptp_tx_ts_complete(adapter);
+	spin_lock_bh(&ptp->tx_ts_lock);
+	for (index = 0;
+		index < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS;
+		index++) {
+		struct sk_buff *skb = ptp->tx_ts_skb_queue[index];
+
+		if (skb)
+			dev_kfree_skb(skb);
+		ptp->tx_ts_skb_queue[index] = NULL;
+		ptp->tx_ts_seconds_queue[index] = 0;
+		ptp->tx_ts_nseconds_queue[index] = 0;
+	}
+	ptp->tx_ts_skb_queue_size = 0;
+	ptp->tx_ts_queue_size = 0;
+	ptp->pending_tx_timestamps = 0;
+	spin_unlock_bh(&ptp->tx_ts_lock);
+
+	lan743x_ptp_disable(adapter);
+}
+
+void lan743x_ptp_set_sync_ts_insert(struct lan743x_adapter *adapter,
+				    bool ts_insert_enable)
+{
+	u32 ptp_tx_mod = lan743x_csr_read(adapter, PTP_TX_MOD);
+
+	if (ts_insert_enable)
+		ptp_tx_mod |= PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
+	else
+		ptp_tx_mod &= ~PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_;
+
+	lan743x_csr_write(adapter, PTP_TX_MOD, ptp_tx_mod);
+}
+
+static bool lan743x_ptp_is_enabled(struct lan743x_adapter *adapter)
+{
+	if (lan743x_csr_read(adapter, PTP_CMD_CTL) & PTP_CMD_CTL_PTP_ENABLE_)
+		return true;
+	return false;
+}
+
+static void lan743x_ptp_wait_till_cmd_done(struct lan743x_adapter *adapter,
+					   u32 bit_mask)
+{
+	int timeout = 1000;
+	u32 data = 0;
+
+	while (timeout &&
+	       (data = (lan743x_csr_read(adapter, PTP_CMD_CTL) &
+	       bit_mask))) {
+		usleep_range(1000, 20000);
+		timeout--;
+	}
+	if (data) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "timeout waiting for cmd to be done, cmd = 0x%08X\n",
+			  bit_mask);
+	}
+}
+
+static void lan743x_ptp_enable(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	if (lan743x_ptp_is_enabled(adapter)) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "PTP already enabled\n");
+		goto done;
+	}
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_ENABLE_);
+done:
+	mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_disable(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+	if (!lan743x_ptp_is_enabled(adapter)) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "PTP already disabled\n");
+		goto done;
+	}
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_DISABLE_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_ENABLE_);
+done:
+	mutex_unlock(&ptp->command_lock);
+}
+
+static void lan743x_ptp_reset(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	if (lan743x_ptp_is_enabled(adapter)) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Attempting reset while enabled\n");
+		goto done;
+	}
+
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_RESET_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_RESET_);
+done:
+	mutex_unlock(&ptp->command_lock);
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	int result = -ENODEV;
+	int index = 0;
+
+	mutex_lock(&ptp->command_lock);
+	for (index = 0; index < LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS; index++) {
+		if (!(test_bit(index, &ptp->used_event_ch))) {
+			ptp->used_event_ch |= BIT(index);
+			result = index;
+			break;
+		}
+	}
+	mutex_unlock(&ptp->command_lock);
+	return result;
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_release_event_ch(struct lan743x_adapter *adapter,
+					 int event_channel)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+	if (test_bit(event_channel, &ptp->used_event_ch)) {
+		ptp->used_event_ch &= ~BIT(event_channel);
+	} else {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "attempted release on a not used event_channel = %d\n",
+			   event_channel);
+	}
+	mutex_unlock(&ptp->command_lock);
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter,
+				  u32 *seconds, u32 *nano_seconds,
+				  u32 *sub_nano_seconds)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_READ_);
+
+	if (seconds)
+		(*seconds) = lan743x_csr_read(adapter, PTP_CLOCK_SEC);
+
+	if (nano_seconds)
+		(*nano_seconds) = lan743x_csr_read(adapter, PTP_CLOCK_NS);
+
+	if (sub_nano_seconds)
+		(*sub_nano_seconds) =
+		lan743x_csr_read(adapter, PTP_CLOCK_SUBNS);
+
+	mutex_unlock(&ptp->command_lock);
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+static void lan743x_ptp_clock_set(struct lan743x_adapter *adapter,
+				  u32 seconds, u32 nano_seconds,
+				  u32 sub_nano_seconds)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	mutex_lock(&ptp->command_lock);
+
+	lan743x_csr_write(adapter, PTP_CLOCK_SEC, seconds);
+	lan743x_csr_write(adapter, PTP_CLOCK_NS, nano_seconds);
+	lan743x_csr_write(adapter, PTP_CLOCK_SUBNS, sub_nano_seconds);
+
+	lan743x_csr_write(adapter, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
+	lan743x_ptp_wait_till_cmd_done(adapter, PTP_CMD_CTL_PTP_CLOCK_LOAD_);
+	mutex_unlock(&ptp->command_lock);
+}
+
+#ifdef CONFIG_PTP_1588_CLOCK
+static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter,
+				   s64 time_step_ns)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	u64 abs_time_step_ns = 0;
+	u32 nano_seconds = 0;
+	s32 seconds = 0;
+
+	if (time_step_ns >  15000000000LL) {
+		/* convert to clock set */
+		u32 nano_seconds = 0;
+		u32 seconds = 0;
+
+		lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
+		seconds += (time_step_ns / 1000000000LL);
+		nano_seconds += (time_step_ns % 1000000000LL);
+		if (nano_seconds >= 1000000000) {
+			seconds++;
+			nano_seconds -= 1000000000;
+		}
+		lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
+		return;
+	} else if (time_step_ns < -15000000000LL) {
+		/* convert to clock set */
+		u32 nano_seconds_step = 0;
+		u32 nano_seconds = 0;
+		u32 seconds = 0;
+
+		time_step_ns = -time_step_ns;
+
+		lan743x_ptp_clock_get(adapter, &seconds, &nano_seconds, NULL);
+		seconds -= (time_step_ns / 1000000000LL);
+		nano_seconds_step = (time_step_ns % 1000000000LL);
+		if (nano_seconds < nano_seconds_step) {
+			seconds--;
+			nano_seconds += 1000000000;
+		}
+		nano_seconds -= nano_seconds_step;
+		lan743x_ptp_clock_set(adapter, seconds, nano_seconds, 0);
+		return;
+	}
+
+	/* do clock step */
+
+	if (time_step_ns >= 0) {
+		abs_time_step_ns = (u64)(time_step_ns);
+		seconds = (s32)(abs_time_step_ns / 1000000000);
+		nano_seconds = (u32)(abs_time_step_ns % 1000000000);
+	} else {
+		abs_time_step_ns = (u64)(-time_step_ns);
+		seconds = -((s32)(abs_time_step_ns / 1000000000));
+		nano_seconds = (u32)(abs_time_step_ns % 1000000000);
+		if (nano_seconds > 0) {
+			/* subtracting nano seconds is not allowed
+			 * convert to subtracting from seconds,
+			 * and adding to nanoseconds
+			 */
+			seconds--;
+			nano_seconds = (1000000000 - nano_seconds);
+		}
+	}
+
+	if (nano_seconds > 0) {
+		/* add 8 ns to cover the likely normal increment */
+		nano_seconds += 8;
+	}
+
+	if (nano_seconds >= 1000000000) {
+		/* carry into seconds */
+		seconds++;
+		nano_seconds -= 1000000000;
+	}
+
+	while (seconds) {
+		mutex_lock(&ptp->command_lock);
+		if (seconds > 0) {
+			u32 adjustment_value = (u32)seconds;
+
+			if (adjustment_value > 0xF)
+				adjustment_value = 0xF;
+			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+					  PTP_CLOCK_STEP_ADJ_DIR_ |
+					  adjustment_value);
+			seconds -= ((s32)adjustment_value);
+		} else {
+			u32 adjustment_value = (u32)(-seconds);
+
+			if (adjustment_value > 0xF)
+				adjustment_value = 0xF;
+			lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+					  adjustment_value);
+			seconds += ((s32)adjustment_value);
+		}
+		lan743x_csr_write(adapter, PTP_CMD_CTL,
+				  PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
+		lan743x_ptp_wait_till_cmd_done(adapter,
+					       PTP_CMD_CTL_PTP_CLOCK_STEP_SEC_);
+		mutex_unlock(&ptp->command_lock);
+	}
+	if (nano_seconds) {
+		mutex_lock(&ptp->command_lock);
+		lan743x_csr_write(adapter, PTP_CLOCK_STEP_ADJ,
+				  PTP_CLOCK_STEP_ADJ_DIR_ |
+				  (nano_seconds &
+				  PTP_CLOCK_STEP_ADJ_VALUE_MASK_));
+		lan743x_csr_write(adapter, PTP_CMD_CTL,
+				  PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
+		lan743x_ptp_wait_till_cmd_done(adapter,
+					       PTP_CMD_CTL_PTP_CLK_STP_NSEC_);
+		mutex_unlock(&ptp->command_lock);
+	}
+}
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+	bool result = false;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) {
+		ptp->pending_tx_timestamps++;
+		result = true;/* request granted */
+	}
+	spin_unlock_bh(&ptp->tx_ts_lock);
+	return result;
+}
+
+void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter)
+{
+	struct lan743x_ptp *ptp = &adapter->ptp;
+
+	spin_lock_bh(&ptp->tx_ts_lock);
+	if (ptp->pending_tx_timestamps > 0)
+		ptp->pending_tx_timestamps--;
+	else
+		netif_err(adapter, drv, adapter->netdev,
+			  "unrequest failed, pending_tx_timestamps==0\n");
+	spin_unlock_bh(&ptp->tx_ts_lock);
+}
+
+void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
+				  struct sk_buff *skb, bool ignore_sync)
+{
+	lan743x_ptp_tx_ts_enqueue_skb(adapter, skb, ignore_sync);
+
+	lan743x_ptp_tx_ts_complete(adapter);
+}
+
+int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	struct hwtstamp_config config;
+	int ret = 0;
+	int index;
+
+	if (!ifr) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "SIOCSHWTSTAMP, ifr == NULL\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	if (config.flags) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "ignoring hwtstamp_config.flags == 0x%08X, expected 0\n",
+			   config.flags);
+	}
+
+	switch (config.tx_type) {
+	case HWTSTAMP_TX_OFF:
+		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
+			index++)
+			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
+							 false, false);
+		lan743x_ptp_set_sync_ts_insert(adapter, false);
+		netif_info(adapter, drv, adapter->netdev,
+			   "  tx_type = HWTSTAMP_TX_OFF\n");
+		break;
+	case HWTSTAMP_TX_ON:
+		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
+			index++)
+			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
+							 true, false);
+		lan743x_ptp_set_sync_ts_insert(adapter, false);
+		netif_info(adapter, drv, adapter->netdev,
+			   "  tx_type = HWTSTAMP_TX_ON\n");
+		break;
+	case HWTSTAMP_TX_ONESTEP_SYNC:
+		for (index = 0; index < LAN743X_MAX_TX_CHANNELS;
+			index++)
+			lan743x_tx_set_timestamping_mode(&adapter->tx[index],
+							 true, true);
+
+		lan743x_ptp_set_sync_ts_insert(adapter, true);
+		netif_info(adapter, drv, adapter->netdev,
+			   "  tx_type = HWTSTAMP_TX_ONESTEP_SYNC\n");
+		break;
+	default:
+		netif_info(adapter, drv, adapter->netdev,
+			   "  tx_type = %d, UNKNOWN\n", config.tx_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	if (!ret)
+		return copy_to_user(ifr->ifr_data, &config,
+			sizeof(config)) ? -EFAULT : 0;
+	return ret;
+}
diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.h b/drivers/net/ethernet/microchip/lan743x_ptp.h
new file mode 100644
index 0000000..979ffce
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_ptp.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2018 Microchip Technology Inc. */
+
+#ifndef _LAN743X_PTP_H
+#define _LAN743X_PTP_H
+
+#include "linux/ptp_clock_kernel.h"
+#include "linux/netdevice.h"
+
+struct lan743x_adapter;
+
+/* GPIO */
+struct lan743x_gpio {
+	/* gpio_lock: used to prevent concurrent access to gpio settings */
+	spinlock_t gpio_lock;
+
+	int used_bits;
+	int output_bits;
+	int ptp_bits;
+	u32 gpio_cfg0;
+	u32 gpio_cfg1;
+	u32 gpio_cfg2;
+	u32 gpio_cfg3;
+};
+
+int lan743x_gpio_init(struct lan743x_adapter *adapter);
+
+void lan743x_ptp_isr(void *context);
+bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter);
+void lan743x_ptp_unrequest_tx_timestamp(struct lan743x_adapter *adapter);
+void lan743x_ptp_tx_timestamp_skb(struct lan743x_adapter *adapter,
+				  struct sk_buff *skb, bool ignore_sync);
+int lan743x_ptp_init(struct lan743x_adapter *adapter);
+int lan743x_ptp_open(struct lan743x_adapter *adapter);
+void lan743x_ptp_close(struct lan743x_adapter *adapter);
+void lan743x_ptp_update_latency(struct lan743x_adapter *adapter,
+				u32 link_speed);
+
+int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+
+#define LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS (4)
+
+#define PTP_FLAG_PTP_CLOCK_REGISTERED	BIT(1)
+#define PTP_FLAG_ISR_ENABLED			BIT(2)
+
+struct lan743x_ptp {
+	int flags;
+
+	/* command_lock: used to prevent concurrent ptp commands */
+	struct mutex	command_lock;
+
+#ifdef CONFIG_PTP_1588_CLOCK
+	struct ptp_clock *ptp_clock;
+	struct ptp_clock_info ptp_clock_info;
+	struct ptp_pin_desc pin_config[1];
+#endif /* CONFIG_PTP_1588_CLOCK */
+
+	struct tasklet_struct	ptp_isr_bottom_half;
+
+#define LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS (2)
+	unsigned long used_event_ch;
+
+	int pps_event_ch;
+	int pps_gpio_bit;
+
+	/* tx_ts_lock: used to prevent concurrent access to timestamp arrays */
+	spinlock_t	tx_ts_lock;
+	int pending_tx_timestamps;
+	struct sk_buff *tx_ts_skb_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	unsigned int	tx_ts_ignore_sync_queue;
+	int tx_ts_skb_queue_size;
+	u32 tx_ts_seconds_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	u32 tx_ts_nseconds_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	u32 tx_ts_header_queue[LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS];
+	int tx_ts_queue_size;
+};
+
+#endif /* _LAN743X_PTP_H */
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 8/9] lan743x: Add RSS support
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Implement RSS support

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_ethtool.c | 132 +++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_main.c    |  20 ++++
 drivers/net/ethernet/microchip/lan743x_main.h    |  19 ++++
 3 files changed, 171 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 3d95290..33d6c2d 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -415,6 +415,133 @@ static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
 	}
 }
 
+static int lan743x_ethtool_get_rxnfc(struct net_device *netdev,
+				     struct ethtool_rxnfc *rxnfc,
+				     u32 *rule_locs)
+{
+	switch (rxnfc->cmd) {
+	case ETHTOOL_GRXFH:
+		rxnfc->data = 0;
+		switch (rxnfc->flow_type) {
+		case TCP_V4_FLOW:case UDP_V4_FLOW:
+		case TCP_V6_FLOW:case UDP_V6_FLOW:
+			rxnfc->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+			/* fall through */
+		case IPV4_FLOW: case IPV6_FLOW:
+			rxnfc->data |= RXH_IP_SRC | RXH_IP_DST;
+			return 0;
+		}
+		break;
+	case ETHTOOL_GRXRINGS:
+		rxnfc->data = LAN743X_USED_RX_CHANNELS;
+		return 0;
+	}
+	return -EOPNOTSUPP;
+}
+
+static u32 lan743x_ethtool_get_rxfh_key_size(struct net_device *netdev)
+{
+	return 40;
+}
+
+static u32 lan743x_ethtool_get_rxfh_indir_size(struct net_device *netdev)
+{
+	return 128;
+}
+
+static int lan743x_ethtool_get_rxfh(struct net_device *netdev,
+				    u32 *indir, u8 *key, u8 *hfunc)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	if (indir) {
+		int dw_index;
+		int byte_index = 0;
+
+		for (dw_index = 0; dw_index < 32; dw_index++) {
+			u32 four_entries =
+				lan743x_csr_read(adapter, RFE_INDX(dw_index));
+
+			byte_index = dw_index << 2;
+			indir[byte_index + 0] =
+				((four_entries >> 0) & 0x000000FF);
+			indir[byte_index + 1] =
+				((four_entries >> 8) & 0x000000FF);
+			indir[byte_index + 2] =
+				((four_entries >> 16) & 0x000000FF);
+			indir[byte_index + 3] =
+				((four_entries >> 24) & 0x000000FF);
+		}
+	}
+	if (key) {
+		int dword_index;
+		int byte_index = 0;
+
+		for (dword_index = 0; dword_index < 10; dword_index++) {
+			u32 four_entries =
+				lan743x_csr_read(adapter,
+						 RFE_HASH_KEY(dword_index));
+
+			byte_index = dword_index << 2;
+			key[byte_index + 0] =
+				((four_entries >> 0) & 0x000000FF);
+			key[byte_index + 1] =
+				((four_entries >> 8) & 0x000000FF);
+			key[byte_index + 2] =
+				((four_entries >> 16) & 0x000000FF);
+			key[byte_index + 3] =
+				((four_entries >> 24) & 0x000000FF);
+		}
+	}
+	if (hfunc)
+		(*hfunc) = ETH_RSS_HASH_TOP;
+	return 0;
+}
+
+static int lan743x_ethtool_set_rxfh(struct net_device *netdev,
+				    const u32 *indir, const u8 *key,
+				    const u8 hfunc)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
+		return -EOPNOTSUPP;
+
+	if (indir) {
+		u32 indir_value = 0;
+		int dword_index = 0;
+		int byte_index = 0;
+
+		for (dword_index = 0; dword_index < 32; dword_index++) {
+			byte_index = dword_index << 2;
+			indir_value =
+				(((indir[byte_index + 0] & 0x000000FF) << 0) |
+				((indir[byte_index + 1] & 0x000000FF) << 8) |
+				((indir[byte_index + 2] & 0x000000FF) << 16) |
+				((indir[byte_index + 3] & 0x000000FF) << 24));
+			lan743x_csr_write(adapter, RFE_INDX(dword_index),
+					  indir_value);
+		}
+	}
+	if (key) {
+		int dword_index = 0;
+		int byte_index = 0;
+		u32 key_value = 0;
+
+		for (dword_index = 0; dword_index < 10; dword_index++) {
+			byte_index = dword_index << 2;
+			key_value =
+				((((u32)(key[byte_index + 0])) << 0) |
+				(((u32)(key[byte_index + 1])) << 8) |
+				(((u32)(key[byte_index + 2])) << 16) |
+				(((u32)(key[byte_index + 3])) << 24));
+			lan743x_csr_write(adapter, RFE_HASH_KEY(dword_index),
+					  key_value);
+		}
+	}
+	return 0;
+}
+
 static int lan743x_ethtool_get_eee(struct net_device *netdev,
 				   struct ethtool_eee *eee)
 {
@@ -558,6 +685,11 @@ const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_strings = lan743x_ethtool_get_strings,
 	.get_ethtool_stats = lan743x_ethtool_get_ethtool_stats,
 	.get_sset_count = lan743x_ethtool_get_sset_count,
+	.get_rxnfc = lan743x_ethtool_get_rxnfc,
+	.get_rxfh_key_size = lan743x_ethtool_get_rxfh_key_size,
+	.get_rxfh_indir_size = lan743x_ethtool_get_rxfh_indir_size,
+	.get_rxfh = lan743x_ethtool_get_rxfh,
+	.set_rxfh = lan743x_ethtool_set_rxfh,
 	.get_eee = lan743x_ethtool_get_eee,
 	.set_eee = lan743x_ethtool_set_eee,
 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 8e9eff8..953b581 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -1025,6 +1025,24 @@ static int lan743x_phy_open(struct lan743x_adapter *adapter)
 	return ret;
 }
 
+static void lan743x_rfe_open(struct lan743x_adapter *adapter)
+{
+	lan743x_csr_write(adapter, RFE_RSS_CFG,
+		RFE_RSS_CFG_UDP_IPV6_EX_ |
+		RFE_RSS_CFG_TCP_IPV6_EX_ |
+		RFE_RSS_CFG_IPV6_EX_ |
+		RFE_RSS_CFG_UDP_IPV6_ |
+		RFE_RSS_CFG_TCP_IPV6_ |
+		RFE_RSS_CFG_IPV6_ |
+		RFE_RSS_CFG_UDP_IPV4_ |
+		RFE_RSS_CFG_TCP_IPV4_ |
+		RFE_RSS_CFG_IPV4_ |
+		RFE_RSS_CFG_VALID_HASH_BITS_ |
+		RFE_RSS_CFG_RSS_QUEUE_ENABLE_ |
+		RFE_RSS_CFG_RSS_HASH_STORE_ |
+		RFE_RSS_CFG_RSS_ENABLE_);
+}
+
 static void lan743x_rfe_update_mac_address(struct lan743x_adapter *adapter)
 {
 	u8 *mac_addr;
@@ -2419,6 +2437,8 @@ static int lan743x_netdev_open(struct net_device *netdev)
 	if (ret)
 		goto close_mac;
 
+	lan743x_rfe_open(adapter);
+
 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
 		ret = lan743x_rx_open(&adapter->rx[index]);
 		if (ret)
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 93cb60a..4fa7a5e 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -166,6 +166,25 @@
 #define RFE_CTL_MCAST_HASH_		BIT(3)
 #define RFE_CTL_DA_PERFECT_		BIT(1)
 
+#define RFE_RSS_CFG			(0x554)
+#define RFE_RSS_CFG_UDP_IPV6_EX_	BIT(16)
+#define RFE_RSS_CFG_TCP_IPV6_EX_	BIT(15)
+#define RFE_RSS_CFG_IPV6_EX_		BIT(14)
+#define RFE_RSS_CFG_UDP_IPV6_		BIT(13)
+#define RFE_RSS_CFG_TCP_IPV6_		BIT(12)
+#define RFE_RSS_CFG_IPV6_		BIT(11)
+#define RFE_RSS_CFG_UDP_IPV4_		BIT(10)
+#define RFE_RSS_CFG_TCP_IPV4_		BIT(9)
+#define RFE_RSS_CFG_IPV4_		BIT(8)
+#define RFE_RSS_CFG_VALID_HASH_BITS_	(0x000000E0)
+#define RFE_RSS_CFG_RSS_QUEUE_ENABLE_	BIT(2)
+#define RFE_RSS_CFG_RSS_HASH_STORE_	BIT(1)
+#define RFE_RSS_CFG_RSS_ENABLE_		BIT(0)
+
+#define RFE_HASH_KEY(index)		(0x558 + (index << 2))
+
+#define RFE_INDX(index)			(0x580 + (index << 2))
+
 #define MAC_WUCSR2			(0x600)
 
 #define INT_STS				(0x780)
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 7/9] lan743x: Add EEE support
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Implement EEE support

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_ethtool.c | 89 ++++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_main.h    |  3 +
 2 files changed, 92 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index f9d875d..3d95290 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -415,6 +415,93 @@ static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
 	}
 }
 
+static int lan743x_ethtool_get_eee(struct net_device *netdev,
+				   struct ethtool_eee *eee)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	struct phy_device *phydev = netdev->phydev;
+	u32 buf;
+	int ret;
+
+	if (!phydev)
+		return -EIO;
+	if (!phydev->drv) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Missing PHY Driver\n");
+		return -EIO;
+	}
+
+	ret = phy_ethtool_get_eee(phydev, eee);
+	if (ret < 0)
+		return ret;
+
+	buf = lan743x_csr_read(adapter, MAC_CR);
+	if (buf & MAC_CR_EEE_EN_) {
+		eee->eee_enabled = true;
+		eee->eee_active = !!(eee->advertised & eee->lp_advertised);
+		eee->tx_lpi_enabled = true;
+		/* EEE_TX_LPI_REQ_DLY & tx_lpi_timer are same uSec unit */
+		buf = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT);
+		eee->tx_lpi_timer = buf;
+	} else {
+		eee->eee_enabled = false;
+		eee->eee_active = false;
+		eee->tx_lpi_enabled = false;
+		eee->tx_lpi_timer = 0;
+	}
+
+	return 0;
+}
+
+static int lan743x_ethtool_set_eee(struct net_device *netdev,
+				   struct ethtool_eee *eee)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	struct phy_device *phydev = NULL;
+	u32 buf = 0;
+	int ret = 0;
+
+	if (!netdev)
+		return -EINVAL;
+	adapter = netdev_priv(netdev);
+	if (!adapter)
+		return -EINVAL;
+	phydev = netdev->phydev;
+	if (!phydev)
+		return -EIO;
+	if (!phydev->drv) {
+		netif_err(adapter, drv, adapter->netdev,
+			  "Missing PHY Driver\n");
+		return -EIO;
+	}
+
+	if (eee->eee_enabled) {
+		ret = phy_init_eee(phydev, 0);
+		if (ret) {
+			netif_err(adapter, drv, adapter->netdev,
+				  "EEE initialization failed\n");
+			return ret;
+		}
+
+		buf = lan743x_csr_read(adapter, MAC_CR);
+		buf |= MAC_CR_EEE_EN_;
+		lan743x_csr_write(adapter, MAC_CR, buf);
+
+		phy_ethtool_set_eee(phydev, eee);
+
+		buf = (u32)eee->tx_lpi_timer;
+		lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT, buf);
+		netif_info(adapter, drv, adapter->netdev, "Enabled EEE\n");
+	} else {
+		buf = lan743x_csr_read(adapter, MAC_CR);
+		buf &= ~MAC_CR_EEE_EN_;
+		lan743x_csr_write(adapter, MAC_CR, buf);
+		netif_info(adapter, drv, adapter->netdev, "Disabled EEE\n");
+	}
+
+	return 0;
+}
+
 #ifdef CONFIG_PM
 static void lan743x_ethtool_get_wol(struct net_device *netdev,
 				    struct ethtool_wolinfo *wol)
@@ -471,6 +558,8 @@ const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_strings = lan743x_ethtool_get_strings,
 	.get_ethtool_stats = lan743x_ethtool_get_ethtool_stats,
 	.get_sset_count = lan743x_ethtool_get_sset_count,
+	.get_eee = lan743x_ethtool_get_eee,
+	.set_eee = lan743x_ethtool_set_eee,
 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
 #ifdef CONFIG_PM
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 72b9beb..93cb60a 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -82,6 +82,7 @@
 	((value << 0) & FCT_FLOW_CTL_ON_THRESHOLD_)
 
 #define MAC_CR				(0x100)
+#define MAC_CR_EEE_EN_			BIT(17)
 #define MAC_CR_ADD_			BIT(12)
 #define MAC_CR_ASD_			BIT(11)
 #define MAC_CR_CNTR_RST_		BIT(5)
@@ -117,6 +118,8 @@
 
 #define MAC_MII_DATA			(0x124)
 
+#define MAC_EEE_TX_LPI_REQ_DLY_CNT		(0x130)
+
 #define MAC_WUCSR				(0x140)
 #define MAC_WUCSR_RFE_WAKE_EN_			BIT(14)
 #define MAC_WUCSR_PFDA_EN_			BIT(3)
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 6/9] lan743x: Add power management support
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Implement power management.
Supports suspend, resume, and Wake On LAN

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_ethtool.c |  48 ++++++
 drivers/net/ethernet/microchip/lan743x_main.c    | 184 +++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_main.h    |  47 ++++++
 3 files changed, 279 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index f9ad237..f9d875d 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -415,6 +415,50 @@ static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
 	}
 }
 
+#ifdef CONFIG_PM
+static void lan743x_ethtool_get_wol(struct net_device *netdev,
+				    struct ethtool_wolinfo *wol)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	wol->supported = WAKE_BCAST | WAKE_UCAST | WAKE_MCAST |
+		WAKE_MAGIC | WAKE_PHY | WAKE_ARP;
+
+	wol->wolopts = adapter->wolopts;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM
+static int lan743x_ethtool_set_wol(struct net_device *netdev,
+				   struct ethtool_wolinfo *wol)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	if (wol->wolopts & WAKE_MAGICSECURE)
+		return -EOPNOTSUPP;
+
+	adapter->wolopts = 0;
+	if (wol->wolopts & WAKE_UCAST)
+		adapter->wolopts |= WAKE_UCAST;
+	if (wol->wolopts & WAKE_MCAST)
+		adapter->wolopts |= WAKE_MCAST;
+	if (wol->wolopts & WAKE_BCAST)
+		adapter->wolopts |= WAKE_BCAST;
+	if (wol->wolopts & WAKE_MAGIC)
+		adapter->wolopts |= WAKE_MAGIC;
+	if (wol->wolopts & WAKE_PHY)
+		adapter->wolopts |= WAKE_PHY;
+	if (wol->wolopts & WAKE_ARP)
+		adapter->wolopts |= WAKE_ARP;
+
+	device_set_wakeup_enable(&adapter->pdev->dev, (bool)wol->wolopts);
+
+	phy_ethtool_set_wol(netdev->phydev, wol);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
 const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_drvinfo = lan743x_ethtool_get_drvinfo,
 	.get_msglevel = lan743x_ethtool_get_msglevel,
@@ -429,4 +473,8 @@ const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_sset_count = lan743x_ethtool_get_sset_count,
 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
+#ifdef CONFIG_PM
+	.get_wol = lan743x_ethtool_get_wol,
+	.set_wol = lan743x_ethtool_set_wol,
+#endif
 };
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 1e2f8c6..8e9eff8 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -11,6 +11,7 @@
 #include <linux/phy.h>
 #include <linux/rtnetlink.h>
 #include <linux/iopoll.h>
+#include <linux/crc16.h>
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
 
@@ -2749,10 +2750,190 @@ static void lan743x_pcidev_shutdown(struct pci_dev *pdev)
 		lan743x_netdev_close(netdev);
 	rtnl_unlock();
 
+#ifdef CONFIG_PM
+	pci_save_state(pdev);
+#endif
+
 	/* clean up lan743x portion */
 	lan743x_hardware_cleanup(adapter);
 }
 
+#ifdef CONFIG_PM
+static u16 lan743x_pm_wakeframe_crc16(const u8 *buf, int len)
+{
+	return bitrev16(crc16(0xFFFF, buf, len));
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM
+static void lan743x_pm_set_wol(struct lan743x_adapter *adapter)
+{
+	const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E };
+	const u8 ipv6_multicast[3] = { 0x33, 0x33 };
+	const u8 arp_type[2] = { 0x08, 0x06 };
+	int mask_index;
+	u32 pmtctl;
+	u32 wucsr;
+	u32 macrx;
+	u16 crc;
+
+	for (mask_index = 0; mask_index < MAC_NUM_OF_WUF_CFG; mask_index++)
+		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 0);
+
+	/* clear wake settings */
+	pmtctl = lan743x_csr_read(adapter, PMT_CTL);
+	pmtctl |= PMT_CTL_WUPS_MASK_;
+	pmtctl &= ~(PMT_CTL_GPIO_WAKEUP_EN_ | PMT_CTL_EEE_WAKEUP_EN_ |
+		PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ |
+		PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ | PMT_CTL_ETH_PHY_WAKE_EN_);
+
+	macrx = lan743x_csr_read(adapter, MAC_RX);
+
+	wucsr = 0;
+	mask_index = 0;
+
+	pmtctl |= PMT_CTL_ETH_PHY_D3_COLD_OVR_ | PMT_CTL_ETH_PHY_D3_OVR_;
+
+	if (adapter->wolopts & WAKE_PHY) {
+		pmtctl |= PMT_CTL_ETH_PHY_EDPD_PLL_CTL_;
+		pmtctl |= PMT_CTL_ETH_PHY_WAKE_EN_;
+	}
+	if (adapter->wolopts & WAKE_MAGIC) {
+		wucsr |= MAC_WUCSR_MPEN_;
+		macrx |= MAC_RX_RXEN_;
+		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
+	}
+	if (adapter->wolopts & WAKE_UCAST) {
+		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_PFDA_EN_;
+		macrx |= MAC_RX_RXEN_;
+		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
+		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
+	}
+	if (adapter->wolopts & WAKE_BCAST) {
+		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_BCST_EN_;
+		macrx |= MAC_RX_RXEN_;
+		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
+		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
+	}
+	if (adapter->wolopts & WAKE_MCAST) {
+		/* IPv4 multicast */
+		crc = lan743x_pm_wakeframe_crc16(ipv4_multicast, 3);
+		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
+				  MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
+				  (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
+				  (crc & MAC_WUF_CFG_CRC16_MASK_));
+		lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 7);
+		lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
+		lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
+		lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
+		mask_index++;
+
+		/* IPv6 multicast */
+		crc = lan743x_pm_wakeframe_crc16(ipv6_multicast, 2);
+		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
+				  MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
+				  (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
+				  (crc & MAC_WUF_CFG_CRC16_MASK_));
+		lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 3);
+		lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
+		lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
+		lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
+		mask_index++;
+
+		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_;
+		macrx |= MAC_RX_RXEN_;
+		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
+		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
+	}
+	if (adapter->wolopts & WAKE_ARP) {
+		/* set MAC_WUF_CFG & WUF_MASK
+		 * for packettype (offset 12,13) = ARP (0x0806)
+		 */
+		crc = lan743x_pm_wakeframe_crc16(arp_type, 2);
+		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
+				  MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_ALL_ |
+				  (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
+				  (crc & MAC_WUF_CFG_CRC16_MASK_));
+		lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 0x3000);
+		lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
+		lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
+		lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
+		mask_index++;
+
+		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_;
+		macrx |= MAC_RX_RXEN_;
+		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
+		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
+	}
+
+	lan743x_csr_write(adapter, MAC_WUCSR, wucsr);
+	lan743x_csr_write(adapter, PMT_CTL, pmtctl);
+	lan743x_csr_write(adapter, MAC_RX, macrx);
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM
+static int lan743x_pm_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	int ret;
+
+	lan743x_pcidev_shutdown(pdev);
+
+	/* clear all wakes */
+	lan743x_csr_write(adapter, MAC_WUCSR, 0);
+	lan743x_csr_write(adapter, MAC_WUCSR2, 0);
+	lan743x_csr_write(adapter, MAC_WK_SRC, 0xFFFFFFFF);
+
+	if (adapter->wolopts)
+		lan743x_pm_set_wol(adapter);
+
+	/* Host sets PME_En, put D3hot */
+	ret = pci_prepare_to_sleep(pdev);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM
+static int lan743x_pm_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	int ret;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	pci_save_state(pdev);
+
+	ret = lan743x_hardware_init(adapter, pdev);
+	if (ret) {
+		netif_err(adapter, probe, adapter->netdev,
+			  "lan743x_hardware_init returned %d\n", ret);
+	}
+
+	/* open netdev when netdev is at running state while resume.
+	 * For instance, it is true when system wakesup after pm-suspend
+	 * However, it is false when system wakes up after suspend GUI menu
+	 */
+	if (netif_running(netdev))
+		lan743x_netdev_open(netdev);
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM
+const struct dev_pm_ops lan743x_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(lan743x_pm_suspend, lan743x_pm_resume)
+};
+#endif /*CONFIG_PM */
+
 static const struct pci_device_id lan743x_pcidev_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7430) },
 	{ 0, }
@@ -2763,6 +2944,9 @@ static struct pci_driver lan743x_pcidev_driver = {
 	.id_table = lan743x_pcidev_tbl,
 	.probe    = lan743x_pcidev_probe,
 	.remove   = lan743x_pcidev_remove,
+#ifdef CONFIG_PM
+	.driver.pm = &lan743x_pm_ops,
+#endif
 	.shutdown = lan743x_pcidev_shutdown,
 };
 
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index c026b8d..72b9beb 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -24,8 +24,18 @@
 #define HW_CFG_LRST_				BIT(1)
 
 #define PMT_CTL					(0x014)
+#define PMT_CTL_ETH_PHY_D3_COLD_OVR_		BIT(27)
+#define PMT_CTL_MAC_D3_RX_CLK_OVR_		BIT(25)
+#define PMT_CTL_ETH_PHY_EDPD_PLL_CTL_		BIT(24)
+#define PMT_CTL_ETH_PHY_D3_OVR_			BIT(23)
+#define PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_		BIT(18)
+#define PMT_CTL_GPIO_WAKEUP_EN_			BIT(15)
+#define PMT_CTL_EEE_WAKEUP_EN_			BIT(13)
 #define PMT_CTL_READY_				BIT(7)
 #define PMT_CTL_ETH_PHY_RST_			BIT(4)
+#define PMT_CTL_WOL_EN_				BIT(3)
+#define PMT_CTL_ETH_PHY_WAKE_EN_		BIT(2)
+#define PMT_CTL_WUPS_MASK_			(0x00000003)
 
 #define DP_SEL				(0x024)
 #define DP_SEL_DPRDY_			BIT(31)
@@ -107,6 +117,38 @@
 
 #define MAC_MII_DATA			(0x124)
 
+#define MAC_WUCSR				(0x140)
+#define MAC_WUCSR_RFE_WAKE_EN_			BIT(14)
+#define MAC_WUCSR_PFDA_EN_			BIT(3)
+#define MAC_WUCSR_WAKE_EN_			BIT(2)
+#define MAC_WUCSR_MPEN_				BIT(1)
+#define MAC_WUCSR_BCST_EN_			BIT(0)
+
+#define MAC_WK_SRC				(0x144)
+
+#define MAC_WUF_CFG0			(0x150)
+#define MAC_NUM_OF_WUF_CFG		(32)
+#define MAC_WUF_CFG_BEGIN		(MAC_WUF_CFG0)
+#define MAC_WUF_CFG(index)		(MAC_WUF_CFG_BEGIN + (4 * (index)))
+#define MAC_WUF_CFG_EN_			BIT(31)
+#define MAC_WUF_CFG_TYPE_MCAST_		(0x02000000)
+#define MAC_WUF_CFG_TYPE_ALL_		(0x01000000)
+#define MAC_WUF_CFG_OFFSET_SHIFT_	(16)
+#define MAC_WUF_CFG_CRC16_MASK_		(0x0000FFFF)
+
+#define MAC_WUF_MASK0_0			(0x200)
+#define MAC_WUF_MASK0_1			(0x204)
+#define MAC_WUF_MASK0_2			(0x208)
+#define MAC_WUF_MASK0_3			(0x20C)
+#define MAC_WUF_MASK0_BEGIN		(MAC_WUF_MASK0_0)
+#define MAC_WUF_MASK1_BEGIN		(MAC_WUF_MASK0_1)
+#define MAC_WUF_MASK2_BEGIN		(MAC_WUF_MASK0_2)
+#define MAC_WUF_MASK3_BEGIN		(MAC_WUF_MASK0_3)
+#define MAC_WUF_MASK0(index)		(MAC_WUF_MASK0_BEGIN + (0x10 * (index)))
+#define MAC_WUF_MASK1(index)		(MAC_WUF_MASK1_BEGIN + (0x10 * (index)))
+#define MAC_WUF_MASK2(index)		(MAC_WUF_MASK2_BEGIN + (0x10 * (index)))
+#define MAC_WUF_MASK3(index)		(MAC_WUF_MASK3_BEGIN + (0x10 * (index)))
+
 /* offset 0x400 - 0x500, x may range from 0 to 32, for a total of 33 entries */
 #define RFE_ADDR_FILT_HI(x)		(0x400 + (8 * (x)))
 #define RFE_ADDR_FILT_HI_VALID_		BIT(31)
@@ -121,6 +163,8 @@
 #define RFE_CTL_MCAST_HASH_		BIT(3)
 #define RFE_CTL_DA_PERFECT_		BIT(1)
 
+#define MAC_WUCSR2			(0x600)
+
 #define INT_STS				(0x780)
 #define INT_BIT_DMA_RX_(channel)	BIT(24 + (channel))
 #define INT_BIT_ALL_RX_			(0x0F000000)
@@ -534,6 +578,9 @@ struct lan743x_adapter {
 	struct net_device       *netdev;
 	struct mii_bus		*mdiobus;
 	int                     msg_enable;
+#ifdef CONFIG_PM
+	u32			wolopts;
+#endif
 	struct pci_dev		*pdev;
 	struct lan743x_csr      csr;
 	struct lan743x_intr     intr;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 5/9] lan743x: Add support for ethtool eeprom access
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Implement ethtool eeprom access
Also provides access to OTP (One Time Programming)

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_ethtool.c | 209 +++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_main.h    |  33 ++++
 2 files changed, 242 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index bab1344..f9ad237 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -7,6 +7,178 @@
 #include <linux/pci.h>
 #include <linux/phy.h>
 
+/* eeprom */
+#define LAN743X_EEPROM_MAGIC		    (0x74A5)
+#define LAN743X_OTP_MAGIC		    (0x74F3)
+#define EEPROM_INDICATOR_1		    (0xA5)
+#define EEPROM_INDICATOR_2		    (0xAA)
+#define EEPROM_MAC_OFFSET		    (0x01)
+#define MAX_EEPROM_SIZE			    512
+#define OTP_INDICATOR_1			    (0xF3)
+#define OTP_INDICATOR_2			    (0xF7)
+
+static int lan743x_otp_write(struct lan743x_adapter *adapter, u32 offset,
+			     u32 length, u8 *data)
+{
+	unsigned long timeout;
+	u32 buf;
+	int i;
+
+	buf = lan743x_csr_read(adapter, OTP_PWR_DN);
+
+	if (buf & OTP_PWR_DN_PWRDN_N_) {
+		/* clear it and wait to be cleared */
+		lan743x_csr_write(adapter, OTP_PWR_DN, 0);
+
+		timeout = jiffies + HZ;
+		do {
+			udelay(1);
+			buf = lan743x_csr_read(adapter, OTP_PWR_DN);
+			if (time_after(jiffies, timeout)) {
+				netif_warn(adapter, drv, adapter->netdev,
+					   "timeout on OTP_PWR_DN completion\n");
+				return -EIO;
+			}
+		} while (buf & OTP_PWR_DN_PWRDN_N_);
+	}
+
+	/* set to BYTE program mode */
+	lan743x_csr_write(adapter, OTP_PRGM_MODE, OTP_PRGM_MODE_BYTE_);
+
+	for (i = 0; i < length; i++) {
+		lan743x_csr_write(adapter, OTP_ADDR1,
+				  ((offset + i) >> 8) &
+				  OTP_ADDR1_15_11_MASK_);
+		lan743x_csr_write(adapter, OTP_ADDR2,
+				  ((offset + i) &
+				  OTP_ADDR2_10_3_MASK_));
+		lan743x_csr_write(adapter, OTP_PRGM_DATA, data[i]);
+		lan743x_csr_write(adapter, OTP_TST_CMD, OTP_TST_CMD_PRGVRFY_);
+		lan743x_csr_write(adapter, OTP_CMD_GO, OTP_CMD_GO_GO_);
+
+		timeout = jiffies + HZ;
+		do {
+			udelay(1);
+			buf = lan743x_csr_read(adapter, OTP_STATUS);
+			if (time_after(jiffies, timeout)) {
+				netif_warn(adapter, drv, adapter->netdev,
+					   "Timeout on OTP_STATUS completion\n");
+				return -EIO;
+			}
+		} while (buf & OTP_STATUS_BUSY_);
+	}
+
+	return 0;
+}
+
+static int lan743x_eeprom_wait(struct lan743x_adapter *adapter)
+{
+	unsigned long start_time = jiffies;
+	u32 val;
+
+	do {
+		val = lan743x_csr_read(adapter, E2P_CMD);
+
+		if (!(val & E2P_CMD_EPC_BUSY_) ||
+		    (val & E2P_CMD_EPC_TIMEOUT_))
+			break;
+		usleep_range(40, 100);
+	} while (!time_after(jiffies, start_time + HZ));
+
+	if (val & (E2P_CMD_EPC_TIMEOUT_ | E2P_CMD_EPC_BUSY_)) {
+		netif_warn(adapter, drv, adapter->netdev,
+			   "EEPROM read operation timeout\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int lan743x_eeprom_confirm_not_busy(struct lan743x_adapter *adapter)
+{
+	unsigned long start_time = jiffies;
+	u32 val;
+
+	do {
+		val = lan743x_csr_read(adapter, E2P_CMD);
+
+		if (!(val & E2P_CMD_EPC_BUSY_))
+			return 0;
+
+		usleep_range(40, 100);
+	} while (!time_after(jiffies, start_time + HZ));
+
+	netif_warn(adapter, drv, adapter->netdev, "EEPROM is busy\n");
+	return -EIO;
+}
+
+static int lan743x_eeprom_read(struct lan743x_adapter *adapter,
+			       u32 offset, u32 length, u8 *data)
+{
+	int retval;
+	u32 val;
+	int i;
+
+	retval = lan743x_eeprom_confirm_not_busy(adapter);
+	if (retval)
+		return retval;
+
+	for (i = 0; i < length; i++) {
+		val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_;
+		val |= (offset & E2P_CMD_EPC_ADDR_MASK_);
+		lan743x_csr_write(adapter, E2P_CMD, val);
+
+		retval = lan743x_eeprom_wait(adapter);
+		if (retval < 0)
+			return retval;
+
+		val = lan743x_csr_read(adapter, E2P_DATA);
+		data[i] = val & 0xFF;
+		offset++;
+	}
+
+	return 0;
+}
+
+static int lan743x_eeprom_write(struct lan743x_adapter *adapter,
+				u32 offset, u32 length, u8 *data)
+{
+	int retval;
+	u32 val;
+	int i;
+
+	retval = lan743x_eeprom_confirm_not_busy(adapter);
+	if (retval)
+		return retval;
+
+	/* Issue write/erase enable command */
+	val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_;
+	lan743x_csr_write(adapter, E2P_CMD, val);
+
+	retval = lan743x_eeprom_wait(adapter);
+	if (retval < 0)
+		return retval;
+
+	for (i = 0; i < length; i++) {
+		/* Fill data register */
+		val = data[i];
+		lan743x_csr_write(adapter, E2P_DATA, val);
+
+		/* Send "write" command */
+		val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_;
+		val |= (offset & E2P_CMD_EPC_ADDR_MASK_);
+		lan743x_csr_write(adapter, E2P_CMD, val);
+
+		retval = lan743x_eeprom_wait(adapter);
+		if (retval < 0)
+			return retval;
+
+		offset++;
+	}
+
+	return 0;
+}
+
 static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
 					struct ethtool_drvinfo *info)
 {
@@ -32,6 +204,40 @@ static void lan743x_ethtool_set_msglevel(struct net_device *netdev,
 	adapter->msg_enable = msglevel;
 }
 
+static int lan743x_ethtool_get_eeprom_len(struct net_device *netdev)
+{
+	return MAX_EEPROM_SIZE;
+}
+
+static int lan743x_ethtool_get_eeprom(struct net_device *netdev,
+				      struct ethtool_eeprom *ee, u8 *data)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	return lan743x_eeprom_read(adapter, ee->offset, ee->len, data);
+}
+
+static int lan743x_ethtool_set_eeprom(struct net_device *netdev,
+				      struct ethtool_eeprom *ee, u8 *data)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	int ret = -EINVAL;
+
+	if (ee->magic == LAN743X_EEPROM_MAGIC)
+		ret = lan743x_eeprom_write(adapter, ee->offset, ee->len,
+					   data);
+	/* Beware!  OTP is One Time Programming ONLY!
+	 * So do some strict condition check before messing up
+	 */
+	else if ((ee->magic == LAN743X_OTP_MAGIC) &&
+		 (ee->offset == 0) &&
+		 (ee->len == MAX_EEPROM_SIZE) &&
+		 (data[0] == OTP_INDICATOR_1))
+		ret = lan743x_otp_write(adapter, ee->offset, ee->len, data);
+
+	return ret;
+}
+
 static const char lan743x_set0_hw_cnt_strings[][ETH_GSTRING_LEN] = {
 	"RX FCS Errors",
 	"RX Alignment Errors",
@@ -215,6 +421,9 @@ const struct ethtool_ops lan743x_ethtool_ops = {
 	.set_msglevel = lan743x_ethtool_set_msglevel,
 	.get_link = ethtool_op_get_link,
 
+	.get_eeprom_len = lan743x_ethtool_get_eeprom_len,
+	.get_eeprom = lan743x_ethtool_get_eeprom,
+	.set_eeprom = lan743x_ethtool_set_eeprom,
 	.get_strings = lan743x_ethtool_get_strings,
 	.get_ethtool_stats = lan743x_ethtool_get_ethtool_stats,
 	.get_sset_count = lan743x_ethtool_get_sset_count,
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index de4f2cc..c026b8d 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -42,6 +42,16 @@
 
 #define DP_DATA_0			(0x030)
 
+#define E2P_CMD				(0x040)
+#define E2P_CMD_EPC_BUSY_		BIT(31)
+#define E2P_CMD_EPC_CMD_WRITE_		(0x30000000)
+#define E2P_CMD_EPC_CMD_EWEN_		(0x20000000)
+#define E2P_CMD_EPC_CMD_READ_		(0x00000000)
+#define E2P_CMD_EPC_TIMEOUT_		BIT(10)
+#define E2P_CMD_EPC_ADDR_MASK_		(0x000001FF)
+
+#define E2P_DATA			(0x044)
+
 #define FCT_RX_CTL			(0xAC)
 #define FCT_RX_CTL_EN_(channel)		BIT(28 + (channel))
 #define FCT_RX_CTL_DIS_(channel)	BIT(24 + (channel))
@@ -288,6 +298,29 @@
 #define TX_CFG_C_TX_DMA_INT_STS_AUTO_CLR_	BIT(3)
 #define TX_CFG_C_TX_INT_STS_R2C_MODE_MASK_	(0x00000007)
 
+#define OTP_PWR_DN				(0x1000)
+#define OTP_PWR_DN_PWRDN_N_			BIT(0)
+
+#define OTP_ADDR1				(0x1004)
+#define OTP_ADDR1_15_11_MASK_			(0x1F)
+
+#define OTP_ADDR2				(0x1008)
+#define OTP_ADDR2_10_3_MASK_			(0xFF)
+
+#define OTP_PRGM_DATA				(0x1010)
+
+#define OTP_PRGM_MODE				(0x1014)
+#define OTP_PRGM_MODE_BYTE_			BIT(0)
+
+#define OTP_TST_CMD				(0x1024)
+#define OTP_TST_CMD_PRGVRFY_			BIT(3)
+
+#define OTP_CMD_GO				(0x1028)
+#define OTP_CMD_GO_GO_				BIT(0)
+
+#define OTP_STATUS				(0x1030)
+#define OTP_STATUS_BUSY_			BIT(0)
+
 /* MAC statistics registers */
 #define STAT_RX_FCS_ERRORS			(0x1200)
 #define STAT_RX_ALIGNMENT_ERRORS		(0x1204)
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 4/9] lan743x: Add support for ethtool message level
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Implement ethtool message level

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_ethtool.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 9ed9711..bab1344 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -17,6 +17,21 @@ static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
 		pci_name(adapter->pdev), sizeof(info->bus_info));
 }
 
+static u32 lan743x_ethtool_get_msglevel(struct net_device *netdev)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	return adapter->msg_enable;
+}
+
+static void lan743x_ethtool_set_msglevel(struct net_device *netdev,
+					 u32 msglevel)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	adapter->msg_enable = msglevel;
+}
+
 static const char lan743x_set0_hw_cnt_strings[][ETH_GSTRING_LEN] = {
 	"RX FCS Errors",
 	"RX Alignment Errors",
@@ -196,6 +211,8 @@ static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
 
 const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_drvinfo = lan743x_ethtool_get_drvinfo,
+	.get_msglevel = lan743x_ethtool_get_msglevel,
+	.set_msglevel = lan743x_ethtool_set_msglevel,
 	.get_link = ethtool_op_get_link,
 
 	.get_strings = lan743x_ethtool_get_strings,
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 3/9] lan743x: Add support for ethtool statistics
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Implement ethtool statistics

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_ethtool.c | 180 +++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_main.c    |   6 +-
 drivers/net/ethernet/microchip/lan743x_main.h    |  31 ++++
 3 files changed, 214 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 5c4582c..9ed9711 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -17,10 +17,190 @@ static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
 		pci_name(adapter->pdev), sizeof(info->bus_info));
 }
 
+static const char lan743x_set0_hw_cnt_strings[][ETH_GSTRING_LEN] = {
+	"RX FCS Errors",
+	"RX Alignment Errors",
+	"Rx Fragment Errors",
+	"RX Jabber Errors",
+	"RX Undersize Frame Errors",
+	"RX Oversize Frame Errors",
+	"RX Dropped Frames",
+	"RX Unicast Byte Count",
+	"RX Broadcast Byte Count",
+	"RX Multicast Byte Count",
+	"RX Unicast Frames",
+	"RX Broadcast Frames",
+	"RX Multicast Frames",
+	"RX Pause Frames",
+	"RX 64 Byte Frames",
+	"RX 65 - 127 Byte Frames",
+	"RX 128 - 255 Byte Frames",
+	"RX 256 - 511 Bytes Frames",
+	"RX 512 - 1023 Byte Frames",
+	"RX 1024 - 1518 Byte Frames",
+	"RX Greater 1518 Byte Frames",
+};
+
+static const char lan743x_set1_sw_cnt_strings[][ETH_GSTRING_LEN] = {
+	"RX Queue 0 Frames",
+	"RX Queue 1 Frames",
+	"RX Queue 2 Frames",
+	"RX Queue 3 Frames",
+};
+
+static const char lan743x_set2_hw_cnt_strings[][ETH_GSTRING_LEN] = {
+	"RX Total Frames",
+	"EEE RX LPI Transitions",
+	"EEE RX LPI Time",
+	"RX Counter Rollover Status",
+	"TX FCS Errors",
+	"TX Excess Deferral Errors",
+	"TX Carrier Errors",
+	"TX Bad Byte Count",
+	"TX Single Collisions",
+	"TX Multiple Collisions",
+	"TX Excessive Collision",
+	"TX Late Collisions",
+	"TX Unicast Byte Count",
+	"TX Broadcast Byte Count",
+	"TX Multicast Byte Count",
+	"TX Unicast Frames",
+	"TX Broadcast Frames",
+	"TX Multicast Frames",
+	"TX Pause Frames",
+	"TX 64 Byte Frames",
+	"TX 65 - 127 Byte Frames",
+	"TX 128 - 255 Byte Frames",
+	"TX 256 - 511 Bytes Frames",
+	"TX 512 - 1023 Byte Frames",
+	"TX 1024 - 1518 Byte Frames",
+	"TX Greater 1518 Byte Frames",
+	"TX Total Frames",
+	"EEE TX LPI Transitions",
+	"EEE TX LPI Time",
+	"TX Counter Rollover Status",
+};
+
+static const u32 lan743x_set0_hw_cnt_addr[] = {
+	STAT_RX_FCS_ERRORS,
+	STAT_RX_ALIGNMENT_ERRORS,
+	STAT_RX_FRAGMENT_ERRORS,
+	STAT_RX_JABBER_ERRORS,
+	STAT_RX_UNDERSIZE_FRAME_ERRORS,
+	STAT_RX_OVERSIZE_FRAME_ERRORS,
+	STAT_RX_DROPPED_FRAMES,
+	STAT_RX_UNICAST_BYTE_COUNT,
+	STAT_RX_BROADCAST_BYTE_COUNT,
+	STAT_RX_MULTICAST_BYTE_COUNT,
+	STAT_RX_UNICAST_FRAMES,
+	STAT_RX_BROADCAST_FRAMES,
+	STAT_RX_MULTICAST_FRAMES,
+	STAT_RX_PAUSE_FRAMES,
+	STAT_RX_64_BYTE_FRAMES,
+	STAT_RX_65_127_BYTE_FRAMES,
+	STAT_RX_128_255_BYTE_FRAMES,
+	STAT_RX_256_511_BYTES_FRAMES,
+	STAT_RX_512_1023_BYTE_FRAMES,
+	STAT_RX_1024_1518_BYTE_FRAMES,
+	STAT_RX_GREATER_1518_BYTE_FRAMES,
+};
+
+static const u32 lan743x_set2_hw_cnt_addr[] = {
+	STAT_RX_TOTAL_FRAMES,
+	STAT_EEE_RX_LPI_TRANSITIONS,
+	STAT_EEE_RX_LPI_TIME,
+	STAT_RX_COUNTER_ROLLOVER_STATUS,
+	STAT_TX_FCS_ERRORS,
+	STAT_TX_EXCESS_DEFERRAL_ERRORS,
+	STAT_TX_CARRIER_ERRORS,
+	STAT_TX_BAD_BYTE_COUNT,
+	STAT_TX_SINGLE_COLLISIONS,
+	STAT_TX_MULTIPLE_COLLISIONS,
+	STAT_TX_EXCESSIVE_COLLISION,
+	STAT_TX_LATE_COLLISIONS,
+	STAT_TX_UNICAST_BYTE_COUNT,
+	STAT_TX_BROADCAST_BYTE_COUNT,
+	STAT_TX_MULTICAST_BYTE_COUNT,
+	STAT_TX_UNICAST_FRAMES,
+	STAT_TX_BROADCAST_FRAMES,
+	STAT_TX_MULTICAST_FRAMES,
+	STAT_TX_PAUSE_FRAMES,
+	STAT_TX_64_BYTE_FRAMES,
+	STAT_TX_65_127_BYTE_FRAMES,
+	STAT_TX_128_255_BYTE_FRAMES,
+	STAT_TX_256_511_BYTES_FRAMES,
+	STAT_TX_512_1023_BYTE_FRAMES,
+	STAT_TX_1024_1518_BYTE_FRAMES,
+	STAT_TX_GREATER_1518_BYTE_FRAMES,
+	STAT_TX_TOTAL_FRAMES,
+	STAT_EEE_TX_LPI_TRANSITIONS,
+	STAT_EEE_TX_LPI_TIME,
+	STAT_TX_COUNTER_ROLLOVER_STATUS
+};
+
+static void lan743x_ethtool_get_strings(struct net_device *netdev,
+					u32 stringset, u8 *data)
+{
+	switch (stringset) {
+	case ETH_SS_STATS:
+		memcpy(data, lan743x_set0_hw_cnt_strings,
+		       sizeof(lan743x_set0_hw_cnt_strings));
+		memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings)],
+		       lan743x_set1_sw_cnt_strings,
+		       sizeof(lan743x_set1_sw_cnt_strings));
+		memcpy(&data[sizeof(lan743x_set0_hw_cnt_strings) +
+		       sizeof(lan743x_set1_sw_cnt_strings)],
+		       lan743x_set2_hw_cnt_strings,
+		       sizeof(lan743x_set2_hw_cnt_strings));
+		break;
+	}
+}
+
+static void lan743x_ethtool_get_ethtool_stats(struct net_device *netdev,
+					      struct ethtool_stats *stats,
+					      u64 *data)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+	int data_index = 0;
+	u32 buf;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(lan743x_set0_hw_cnt_addr); i++) {
+		buf = lan743x_csr_read(adapter, lan743x_set0_hw_cnt_addr[i]);
+		data[data_index++] = (u64)buf;
+	}
+	for (i = 0; i < ARRAY_SIZE(adapter->rx); i++)
+		data[data_index++] = (u64)(adapter->rx[i].frame_count);
+	for (i = 0; i < ARRAY_SIZE(lan743x_set2_hw_cnt_addr); i++) {
+		buf = lan743x_csr_read(adapter, lan743x_set2_hw_cnt_addr[i]);
+		data[data_index++] = (u64)buf;
+	}
+}
+
+static int lan743x_ethtool_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+	{
+		int ret;
+
+		ret = ARRAY_SIZE(lan743x_set0_hw_cnt_strings);
+		ret += ARRAY_SIZE(lan743x_set1_sw_cnt_strings);
+		ret += ARRAY_SIZE(lan743x_set2_hw_cnt_strings);
+		return ret;
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_drvinfo = lan743x_ethtool_get_drvinfo,
 	.get_link = ethtool_op_get_link,
 
+	.get_strings = lan743x_ethtool_get_strings,
+	.get_ethtool_stats = lan743x_ethtool_get_ethtool_stats,
+	.get_sset_count = lan743x_ethtool_get_sset_count,
 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
 };
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index ade3b04..1e2f8c6 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -54,13 +54,13 @@ static int lan743x_pci_init(struct lan743x_adapter *adapter,
 	return ret;
 }
 
-static u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset)
+u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset)
 {
 	return ioread32(&adapter->csr.csr_address[offset]);
 }
 
-static void lan743x_csr_write(struct lan743x_adapter *adapter, int offset,
-			      u32 data)
+void lan743x_csr_write(struct lan743x_adapter *adapter, int offset,
+		       u32 data)
 {
 	iowrite32(data, &adapter->csr.csr_address[offset]);
 }
diff --git a/drivers/net/ethernet/microchip/lan743x_main.h b/drivers/net/ethernet/microchip/lan743x_main.h
index 73b463a..de4f2cc 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.h
+++ b/drivers/net/ethernet/microchip/lan743x_main.h
@@ -291,6 +291,7 @@
 /* MAC statistics registers */
 #define STAT_RX_FCS_ERRORS			(0x1200)
 #define STAT_RX_ALIGNMENT_ERRORS		(0x1204)
+#define STAT_RX_FRAGMENT_ERRORS			(0x1208)
 #define STAT_RX_JABBER_ERRORS			(0x120C)
 #define STAT_RX_UNDERSIZE_FRAME_ERRORS		(0x1210)
 #define STAT_RX_OVERSIZE_FRAME_ERRORS		(0x1214)
@@ -298,12 +299,26 @@
 #define STAT_RX_UNICAST_BYTE_COUNT		(0x121C)
 #define STAT_RX_BROADCAST_BYTE_COUNT		(0x1220)
 #define STAT_RX_MULTICAST_BYTE_COUNT		(0x1224)
+#define STAT_RX_UNICAST_FRAMES			(0x1228)
+#define STAT_RX_BROADCAST_FRAMES		(0x122C)
 #define STAT_RX_MULTICAST_FRAMES		(0x1230)
+#define STAT_RX_PAUSE_FRAMES			(0x1234)
+#define STAT_RX_64_BYTE_FRAMES			(0x1238)
+#define STAT_RX_65_127_BYTE_FRAMES		(0x123C)
+#define STAT_RX_128_255_BYTE_FRAMES		(0x1240)
+#define STAT_RX_256_511_BYTES_FRAMES		(0x1244)
+#define STAT_RX_512_1023_BYTE_FRAMES		(0x1248)
+#define STAT_RX_1024_1518_BYTE_FRAMES		(0x124C)
+#define STAT_RX_GREATER_1518_BYTE_FRAMES	(0x1250)
 #define STAT_RX_TOTAL_FRAMES			(0x1254)
+#define STAT_EEE_RX_LPI_TRANSITIONS		(0x1258)
+#define STAT_EEE_RX_LPI_TIME			(0x125C)
+#define STAT_RX_COUNTER_ROLLOVER_STATUS		(0x127C)
 
 #define STAT_TX_FCS_ERRORS			(0x1280)
 #define STAT_TX_EXCESS_DEFERRAL_ERRORS		(0x1284)
 #define STAT_TX_CARRIER_ERRORS			(0x1288)
+#define STAT_TX_BAD_BYTE_COUNT			(0x128C)
 #define STAT_TX_SINGLE_COLLISIONS		(0x1290)
 #define STAT_TX_MULTIPLE_COLLISIONS		(0x1294)
 #define STAT_TX_EXCESSIVE_COLLISION		(0x1298)
@@ -311,8 +326,21 @@
 #define STAT_TX_UNICAST_BYTE_COUNT		(0x12A0)
 #define STAT_TX_BROADCAST_BYTE_COUNT		(0x12A4)
 #define STAT_TX_MULTICAST_BYTE_COUNT		(0x12A8)
+#define STAT_TX_UNICAST_FRAMES			(0x12AC)
+#define STAT_TX_BROADCAST_FRAMES		(0x12B0)
 #define STAT_TX_MULTICAST_FRAMES		(0x12B4)
+#define STAT_TX_PAUSE_FRAMES			(0x12B8)
+#define STAT_TX_64_BYTE_FRAMES			(0x12BC)
+#define STAT_TX_65_127_BYTE_FRAMES		(0x12C0)
+#define STAT_TX_128_255_BYTE_FRAMES		(0x12C4)
+#define STAT_TX_256_511_BYTES_FRAMES		(0x12C8)
+#define STAT_TX_512_1023_BYTE_FRAMES		(0x12CC)
+#define STAT_TX_1024_1518_BYTE_FRAMES		(0x12D0)
+#define STAT_TX_GREATER_1518_BYTE_FRAMES	(0x12D4)
 #define STAT_TX_TOTAL_FRAMES			(0x12D8)
+#define STAT_EEE_TX_LPI_TRANSITIONS		(0x12DC)
+#define STAT_EEE_TX_LPI_TIME			(0x12E0)
+#define STAT_TX_COUNTER_ROLLOVER_STATUS		(0x12FC)
 
 /* End of Register definitions */
 
@@ -594,4 +622,7 @@ struct lan743x_rx_buffer_info {
 #define RX_PROCESS_RESULT_PACKET_RECEIVED   (1)
 #define RX_PROCESS_RESULT_PACKET_DROPPED    (2)
 
+u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset);
+void lan743x_csr_write(struct lan743x_adapter *adapter, int offset, u32 data);
+
 #endif /* _LAN743X_H */
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 2/9] lan743x: Add support for ethtool link settings
From: Bryan Whitehead @ 2018-07-12 19:04 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Use default link setting functions

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/lan743x_ethtool.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
index 0e20758..5c4582c 100644
--- a/drivers/net/ethernet/microchip/lan743x_ethtool.c
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -5,6 +5,7 @@
 #include "lan743x_main.h"
 #include "lan743x_ethtool.h"
 #include <linux/pci.h>
+#include <linux/phy.h>
 
 static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
 					struct ethtool_drvinfo *info)
@@ -18,4 +19,8 @@ static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
 
 const struct ethtool_ops lan743x_ethtool_ops = {
 	.get_drvinfo = lan743x_ethtool_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+
+	.get_link_ksettings = phy_ethtool_get_link_ksettings,
+	.set_link_ksettings = phy_ethtool_set_link_ksettings,
 };
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo
From: Bryan Whitehead @ 2018-07-12 19:04 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
In-Reply-To: <1531422306-6547-1-git-send-email-Bryan.Whitehead@microchip.com>

Implement ethtool get_drvinfo

Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
---
 drivers/net/ethernet/microchip/Makefile          |  2 +-
 drivers/net/ethernet/microchip/lan743x_ethtool.c | 21 +++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_ethtool.h | 11 +++++++++++
 drivers/net/ethernet/microchip/lan743x_main.c    |  2 ++
 4 files changed, 35 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ethtool.c
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ethtool.h

diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile
index 2e982cc..43f47cb 100644
--- a/drivers/net/ethernet/microchip/Makefile
+++ b/drivers/net/ethernet/microchip/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_ENC28J60) += enc28j60.o
 obj-$(CONFIG_ENCX24J600) += encx24j600.o encx24j600-regmap.o
 obj-$(CONFIG_LAN743X) += lan743x.o
 
-lan743x-objs := lan743x_main.o
+lan743x-objs := lan743x_main.o lan743x_ethtool.o
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c
new file mode 100644
index 0000000..0e20758
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2018 Microchip Technology Inc. */
+
+#include <linux/netdevice.h>
+#include "lan743x_main.h"
+#include "lan743x_ethtool.h"
+#include <linux/pci.h>
+
+static void lan743x_ethtool_get_drvinfo(struct net_device *netdev,
+					struct ethtool_drvinfo *info)
+{
+	struct lan743x_adapter *adapter = netdev_priv(netdev);
+
+	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+	strlcpy(info->bus_info,
+		pci_name(adapter->pdev), sizeof(info->bus_info));
+}
+
+const struct ethtool_ops lan743x_ethtool_ops = {
+	.get_drvinfo = lan743x_ethtool_get_drvinfo,
+};
diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.h b/drivers/net/ethernet/microchip/lan743x_ethtool.h
new file mode 100644
index 0000000..d0d11a7
--- /dev/null
+++ b/drivers/net/ethernet/microchip/lan743x_ethtool.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2018 Microchip Technology Inc. */
+
+#ifndef _LAN743X_ETHTOOL_H
+#define _LAN743X_ETHTOOL_H
+
+#include "linux/ethtool.h"
+
+extern const struct ethtool_ops lan743x_ethtool_ops;
+
+#endif /* _LAN743X_ETHTOOL_H */
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index e1747a4..ade3b04 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -12,6 +12,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/iopoll.h>
 #include "lan743x_main.h"
+#include "lan743x_ethtool.h"
 
 static void lan743x_pci_cleanup(struct lan743x_adapter *adapter)
 {
@@ -2689,6 +2690,7 @@ static int lan743x_pcidev_probe(struct pci_dev *pdev,
 		goto cleanup_hardware;
 
 	adapter->netdev->netdev_ops = &lan743x_netdev_ops;
+	adapter->netdev->ethtool_ops = &lan743x_ethtool_ops;
 	adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
 	adapter->netdev->hw_features = adapter->netdev->features;
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver
From: Bryan Whitehead @ 2018-07-12 19:04 UTC (permalink / raw)
  To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran

This patch series adds extra features to the lan743x driver.

Updates for V2:
Patch 3/9 - Used ARRAY_SIZE macro in lan743x_ethtool_get_ethtool_stats.
Patch 5/9 - Used MAX_EEPROM_SIZE in lan743x_ethtool_set_eeprom.
Patch 6/9 - Removed unnecessary read of PMT_CTL.
	    Used CRC algorithm from lib.
	    Removed PHY interrupt settings from lan743x_pm_suspend
	    Change "#if CONFIG_PM" to "#ifdef CONFIG_PM"

Bryan Whitehead (9):
  lan743x: Add support for ethtool get_drvinfo
  lan743x: Add support for ethtool link settings
  lan743x: Add support for ethtool statistics
  lan743x: Add support for ethtool message level
  lan743x: Add support for ethtool eeprom access
  lan743x: Add power management support
  lan743x: Add EEE support
  lan743x: Add RSS support
  lan743x: Add PTP support

 drivers/net/ethernet/microchip/Makefile          |    2 +-
 drivers/net/ethernet/microchip/lan743x_ethtool.c |  729 +++++++++++++
 drivers/net/ethernet/microchip/lan743x_ethtool.h |   11 +
 drivers/net/ethernet/microchip/lan743x_main.c    |  293 +++++-
 drivers/net/ethernet/microchip/lan743x_main.h    |  229 ++++-
 drivers/net/ethernet/microchip/lan743x_ptp.c     | 1194 ++++++++++++++++++++++
 drivers/net/ethernet/microchip/lan743x_ptp.h     |   78 ++
 7 files changed, 2528 insertions(+), 8 deletions(-)
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ethtool.c
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ethtool.h
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ptp.c
 create mode 100644 drivers/net/ethernet/microchip/lan743x_ptp.h

-- 
2.7.4

^ permalink raw reply

* Re: Re: [Qemu-devel] [PATCH v3 0/3] Use of unique identifier for pairing virtio and passthrough devices...
From: Michael S. Tsirkin @ 2018-07-12 19:18 UTC (permalink / raw)
  To: Cornelia Huck
  Cc: Siwei Liu, si-wei liu, Roman Kagan, Venu Busireddy,
	Marcel Apfelbaum, virtio-dev, qemu-devel, Samudrala, Sridhar,
	Alexander Duyck, Netdev
In-Reply-To: <20180711115344.633eba9e.cohuck@redhat.com>

On Wed, Jul 11, 2018 at 11:53:44AM +0200, Cornelia Huck wrote:
> On Tue, 10 Jul 2018 17:07:37 -0700
> Siwei Liu <loseweigh@gmail.com> wrote:
> 
> > On Mon, Jul 9, 2018 at 6:54 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
> > > On Mon, Jul 09, 2018 at 06:11:53PM -0700, si-wei liu wrote:  
> > >> The plan is to enable group ID based matching in the first place rather than
> > >> match by MAC, the latter of which is fragile and problematic.  
> > >
> > > It isn't all that fragile - hyperv used same for a while, so if someone
> > > posts working patches with QEMU support but before this grouping stuff,
> > > I'll happily apply them.  
> > 
> > I wouldn't box the solution to very limited scenario just because of
> > matching by MAC, the benefit of having generic group ID in the first
> > place is that we save the effort of maintaining legacy MAC based
> > pairing that just adds complexity anyway. Currently the VF's MAC
> > address cannot be changed by either PF or by the guest user is a
> > severe limitation due to this. The other use case is that PT device
> > than VF would generally have different MAC than the standby virtio. We
> > shouldn't limit itself to VF specific scenario from the very
> > beginning.
> 
> So, this brings me to a different concern: the semantics of
> VIRTIO_NET_F_STANDBY.
> 
> * The currently sole user seems to be the virtio-net Linux driver.
> * The commit messages, code comments and Documentation/ all talk about
>   matching by MAC.
> * I could not find any proposed update to the virtio spec. (If there
>   had been an older proposal with a different feature name, it is not
>   discoverable.)
> 
> VIRTIO_NET_F_STANDBY is a host <-> guest interface. As there's no
> official spec, you can only go by the Linux implementation, and by that
> its semantics seem to be 'match by MAC', not 'match by other criteria'.
> 
> How is this supposed to work in the long run?

We definitely need a spec patch for VIRTIO_NET_F_STANDBY documenting existing
semantics.  Sridhar, do you plan to take a look?

-- 
MST

^ permalink raw reply

* Re: [PATCH 00/14] ARM BPF jit compiler improvements
From: Daniel Borkmann @ 2018-07-12 19:02 UTC (permalink / raw)
  To: Russell King - ARM Linux, netdev, linux-arm-kernel
In-Reply-To: <20180711093033.GP17271@n2100.armlinux.org.uk>

On 07/11/2018 11:30 AM, Russell King - ARM Linux wrote:
> Hi,
> 
> This series improves the ARM BPF JIT compiler by:
> - enumerating the stack layout rather than using constants that happen
>   to be multiples of four
> - rejig the BPF "register" accesses to use negative numbers instead of
>   positive, which could be confused with register numbers in the bpf2a32
>   array.
> - since we maintain the ARM FP register as a pointer to the top of our
>   scratch space (or, with frame pointers enabled, a valid ARM frame
>   pointer register), we can access our scratch space using FP, which is
>   constant across all BPF programs, including tail-called programs.
> - use immediate forms of ARM instructions where possible, rather than
>   first loading the immediate into an ARM register.
> - use load-with-shift instruction rather than seperate shift instruction
>   followed by load
> - avoid reloading index and array in the tail-call code
> - use double-word load/store instructions where available
> 
> Version 2:
> - Fix ARMv5 test pointed out by Olof
> - Fix build error found by 0-day (adding an additional patch)
> 
>  arch/arm/net/bpf_jit_32.c | 982 ++++++++++++++++++++++++----------------------
>  arch/arm/net/bpf_jit_32.h |  42 +-
>  2 files changed, 543 insertions(+), 481 deletions(-)

Applied to bpf-next, thanks a lot Russell!

^ permalink raw reply

* Re: [PATCH net-next 2/2] net: phy: add phy_speed_down and phy_speed_up
From: Heiner Kallweit @ 2018-07-12 19:00 UTC (permalink / raw)
  To: Florian Fainelli, Andrew Lunn; +Cc: David Miller, netdev@vger.kernel.org
In-Reply-To: <a9a668e3-772b-61bf-85c2-801dc46f8ecf@gmail.com>

On 11.07.2018 23:59, Heiner Kallweit wrote:
> On 11.07.2018 23:33, Florian Fainelli wrote:
>>
>>
>> On 07/11/2018 02:08 PM, Heiner Kallweit wrote:
>>> On 11.07.2018 22:55, Andrew Lunn wrote:
>>>>> +/**
>>>>> + * phy_speed_down - set speed to lowest speed supported by both link partners
>>>>> + * @phydev: the phy_device struct
>>>>> + * @sync: perform action synchronously
>>>>> + *
>>>>> + * Description: Typically used to save energy when waiting for a WoL packet
>>>>> + */
>>>>> +int phy_speed_down(struct phy_device *phydev, bool sync)
>>>>
>>>> This sync parameter needs some more thought. I'm not sure it is safe.
>>>>
>>>> How does a PHY trigger a WoL wake up? I guess some use the interrupt
>>>> pin. How does a PHY indicate auto-neg has completed? It triggers an
>>>> interrupt. So it seems like there is a danger here we suspend, and
>>>> then wake up 2 seconds later when auto-neg has completed.
>>>>
>>>> I'm not sure we can safely suspend until auto-neg has completed.
>>>>
>>>>> +/**
>>>>> + * phy_speed_up - (re)set advertised speeds to all supported speeds
>>>>> + * @phydev: the phy_device struct
>>>>> + * @sync: perform action synchronously
>>>>> + *
>>>>> + * Description: Used to revert the effect of phy_speed_down
>>>>> + */
>>>>> +int phy_speed_up(struct phy_device *phydev, bool sync)
>>>>
>>>> And here, i'm thinking the opposite. A MAC driver needs to be ready
>>>> for the PHY state to change at any time. So why do we need to wait?
>>>> Just let the normal mechanisms inform the MAC when the link is up.
>>>>
>>> I see your points, thanks for the feedback. In my case WoL triggers
>>> a PCI PME and the code works as expected, but I agree this may be
>>> different in other setups (external PHY).
>>>
>>> The sync parameter was inspired by following comment from Florian:
>>> "One thing that bothers me a bit is that this should ideally be
>>> offered as both blocking and non-blocking options"
>>> So let's see which comments he may have before preparing a v2.
>>
>> What I had in mind is that you would be able to register a callback that
>> would tell you when auto-negotiation completes, and not register one if
>> you did not want to have that information.
>>
>> As Andrew points out though, with PHY using interrupts, this might be a
>> bit challenging to do because you will get an interrupt about "something
>> has changed" and you would have to run the callback from the PHY state
>> machine to determine this was indeed a result of triggering
>> auto-negotiation. Maybe polling for auto-negotiation like you do here is
>> good enough.
>>
> OK, then I would poll for autoneg finished in phy_speed_down and
> remove the polling option from phy_speed_up. I will do some tests
> with this before submitting a v2.
> 
Like r8169 also tg3 driver doesn't wait for the speed-down-renegotiation
to finish. Therefore, even though I share Andrew's concerns, there seem
to be chips where it's safe to not wait for the renegotiation to finish
(e.g. because device is in PCI D3 already and can't generate an interrupt).
Having said that I'd keep the sync parameter for phy_speed_down so that
the driver can decide.
For phy_speed_up I'll remove the sync parameter as discussed.


>> One nit, you might have to check for those functions that the PHY did
>> have auto-negotiation enabled and was not forced.
>>
> This I'm doing already, or do you mean something different?
> 

^ permalink raw reply

* Re: [PATCH 2/2] [RESEND, net-next] ipv6: xfrm: use 64-bit timestamps
From: Steffen Klassert @ 2018-07-12 19:11 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Herbert Xu, David S. Miller, Alexey Kuznetsov, Hideaki YOSHIFUJI,
	netdev, linux-kernel
In-Reply-To: <20180711101941.4039411-2-arnd@arndb.de>

On Wed, Jul 11, 2018 at 12:19:14PM +0200, Arnd Bergmann wrote:
> get_seconds() is deprecated because it can overflow on 32-bit
> architectures.  For the xfrm_state->lastused member, we treat the data
> as a 64-bit number already, so we just need to use the right accessor
> that works on both 32-bit and 64-bit machines.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Also applied to ipsec-next, thanks!

^ permalink raw reply

* Re: [PATCH 1/2] [RESEND, net-next] xfrm: use time64_t for in-kernel timestamps
From: Steffen Klassert @ 2018-07-12 19:10 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Herbert Xu, David S. Miller, Florian Westphal, netdev,
	linux-kernel
In-Reply-To: <20180711101941.4039411-1-arnd@arndb.de>

On Wed, Jul 11, 2018 at 12:19:13PM +0200, Arnd Bergmann wrote:
> The lifetime managment uses '__u64' timestamps on the user space
> interface, but 'unsigned long' for reading the current time in the kernel
> with get_seconds().
> 
> While this is probably safe beyond y2038, it will still overflow in 2106,
> and the get_seconds() call is deprecated because fo that.
> 
> This changes the xfrm time handling to use time64_t consistently, along
> with reading the time using the safer ktime_get_real_seconds(). It still
> suffers from problems that can happen from a concurrent settimeofday()
> call or (to a lesser degree) a leap second update, but since the time
> stamps are part of the user API, there is nothing we can do to prevent
> that.
> 
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

Applied to the ipsec-next tree, thanks a lot!

^ permalink raw reply

* Re: [BUG] bonded interfaces drop bpdu (stp) frames
From: Jay Vosburgh @ 2018-07-12 18:03 UTC (permalink / raw)
  To: Michal Soltys, Chonggang Li
  Cc: =?UTF-8?B?TWFoZXNoIEJhbmRld2FyICjgpK7gpLngpYfgpLYg4KSs4KSC4KSh4KWH4KS14KS+?= =?UTF-8?B?4KSwKQ==?=,
	linux-netdev
In-Reply-To: <e9c7ad15-df2f-b2c1-0784-29d7a453a27e@ziu.info>

Michal Soltys <soltys@ziu.info> wrote:

>On 07/12/2018 04:51 PM, Jay Vosburgh wrote:
>> Mahesh Bandewar (महेश बंडेवार) wrote:
>>
>>> On Wed, Jul 11, 2018 at 3:23 PM, Michal Soltys <soltys@ziu.info> wrote:
>>>>
>>>> Hi,
>>>>
>>>> As weird as that sounds, this is what I observed today after bumping
>>>> kernel version. I have a setup where 2 bonds are attached to linux
>>>> bridge and physically are connected to two switches doing MSTP (and
>>>> linux bridge is just passing them).
>>>>
>>>> Initially I suspected some changes related to bridge code - but quick
>>>> peek at the code showed nothing suspicious - and the part of it that
>>>> explicitly passes stp frames if stp is not enabled has seen little
>>>> changes (e.g. per-port group_fwd_mask added recently). Furthermore - if
>>>> regular non-bonded interfaces are attached everything works fine.
>>>>
>>>> Just to be sure I detached the bond (802.3ad mode) and checked it with
>>>> simple tcpdump (ether proto \\stp) - and indeed no hello packets were
>>>> there (with them being present just fine on active enslaved interface,
>>>> or on the bond device in earlier kernels).
>>>>
>>>> If time permits I'll bisect tommorow to pinpoint the commit, but from
>>>> quick todays test - 4.9.x is working fine, while 4.16.16 (tested on
>>>> debian) and 4.17.3 (tested on archlinux) are failing.
>>>>
>>>> Unless this is already a known issue (or you have any suggestions what
>>>> could be responsible).
>>>>
>>> I believe these are link-local-multicast messages and sometime back a
>>> change went into to not pass those frames to the bonding master. This
>>> could be the side effect of that.
>>
>> 	Mahesh, I suspect you're thinking of:
>>
>> commit b89f04c61efe3b7756434d693b9203cc0cce002e
>> Author: Chonggang Li <chonggangli@google.com>
>> Date:   Sun Apr 16 12:02:18 2017 -0700
>>
>>      bonding: deliver link-local packets with skb->dev set to link that packets arrived on
>>
>> 	Michal, are you able to revert this patch and test?
>>
>> 	-J
>>
>> ---
>> 	-Jay Vosburgh, jay.vosburgh@canonical.com
>>
>
>
>Just tested - yes, reverting that patch solves the issues.

	Chonggang,

	Reading the changelog in your commit referenced above, I'm not
entirely sure what actual problem it is fixing.  Could you elaborate?

	As the patch appears to cause a regression, it needs to be
either fixed or reverted.

	Mahesh, you signed-off on it as well, perhaps you also have some
context?

	-J

---
	-Jay Vosburgh, jay.vosburgh@canonical.com

^ permalink raw reply

* Re: [BUG] mlx5 have problems with ipv4-ipv6 tunnels in linux 4.4
From: Or Gerlitz @ 2018-07-12 18:03 UTC (permalink / raw)
  To: Konstantin Khlebnikov, Saeed Mahameed
  Cc: Saeed Mahameed, netdev, Or Gerlitz, Tariq Toukan
In-Reply-To: <e5258c3f-aeca-a8ab-33c8-6e1411a16a87@yandex-team.ru>

On Tue, Jul 10, 2018 at 12:19 PM, Konstantin Khlebnikov
<khlebnikov@yandex-team.ru> wrote:
> On 10.07.2018 01:31, Saeed Mahameed wrote:
>>
>> On Tue, Jul 3, 2018 at 10:45 PM, Konstantin Khlebnikov
>> <khlebnikov@yandex-team.ru> wrote:
>>>
>>> I'm seeing problems with tunnelled traffic with Mellanox Technologies
>>> MT27710 Family [ConnectX-4 Lx] using vanilla driver from linux 4.4.y
>>>
>>> Packets with payload bigger than 116 bytes are not exmited.
>>> Smaller packets and normal ipv6 works fine.
>>>
>>
>> Hi Konstantin,
>>
>> Is this true for all ipv6 traffic or just ipv4-ipv6 tunnels ?
>>
>> what is the skb_network_offset(skb) for such packet ?
>>
>>> In linux 4.9, 4.14 and out-of-tree driver everything seems fine for now.
>>> It's hard to guess or bisect commit: there are a lot of changes and
>>> something wrong with driver or swiotlb in 4.7..4.8.
>>> 4.6 is affected too - so this should be something between 4.6 and 4.9
>>>
>>> Probably this case was fixed indirectly by adding some kind of offload
>>> and
>>> non-offloaded path is still broken.
>>> Please give me a hint: which commit could it be.
>>>
>>
>> I suspect it works in a newer kernel since we introduced on 4.7/4.8:
>
>
> Yes, this works. Thank you.
>
> Problem was with VLAN rather than tunnel.
>
> This hunk from first patch is enough:
> -#define MLX5E_MIN_INLINE ETH_HLEN
> +#define MLX5E_MIN_INLINE (ETH_HLEN + VLAN_HLEN)


so... what should we do to fix 4.4-stable? just push there the 1st path?

Saeed, 4.4 is LTS, lets fix it there..

Or.


> In my case full data path looks like
>
> ( tcp -> ipip6 -> veth ) -> netns-to-host -> ( veth -> vlan at mlx5 )
>
> Tunnelled traffic also goes to vlan, while most of other traffic goes
> through non-tagged interface and worked fine.
>
> max_inline is 226 so (226 - vlan - ethernet - ipv6 - ipv4 - tcp)
> leaves exactly 116 bytes for payload.
>
>
>>
>> commit e3a19b53cbb0e6738b7a547f262179065b72e3fa
>> Author: Matthew Finlay <matt@mellanox.com>
>> Date:   Thu Jun 30 17:34:47 2016 +0300
>>
>>      net/mlx5e: Copy all L2 headers into inline segment
>>
>>      ConnectX4-Lx uses an inline wqe mode that currently defaults to
>>      requiring the entire L2 header be included in the wqe.
>>      This patch fixes mlx5e_get_inline_hdr_size() to account for
>>      all L2 headers (VLAN, QinQ, etc) using skb_network_offset(skb).
>>
>>      Fixes: e586b3b0baee ("net/mlx5: Ethernet Datapath files")
>>      Signed-off-by: Matthew Finlay <matt@mellanox.com>
>>      Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
>>      Signed-off-by: David S. Miller <davem@davemloft.net>
>>
>>
>>
>> commit ae76715d153e33c249b6850361e4d8d775388b5a
>> Author: Hadar Hen Zion <hadarh@mellanox.com>
>> Date:   Sun Jul 24 16:12:39 2016 +0300
>>
>>      net/mlx5e: Check the minimum inline header mode before xmit
>>
>> and then some fixes on top of it, such as:
>>
>> commit f600c6088018d1dbc5777d18daa83660f7ea4a64
>> Author: Eran Ben Elisha <eranbe@mellanox.com>
>> Date:   Thu Jan 25 11:18:09 2018 +0200
>>
>>      net/mlx5e: Verify inline header size do not exceed SKB linear size
>>
>>
>> anyhow, can you try the above patches one by one  on 4.4.y and see if it
>> helps ?
>>
>>
>> Thanks,
>> Saeed
>>
>

^ permalink raw reply

* [PATCH net-next] selftests: tls: add selftests for TLS sockets
From: Dave Watson @ 2018-07-12 17:59 UTC (permalink / raw)
  To: Boris Pismenny, davem@davemloft.net, netdev@vger.kernel.org,
	aviadye@mellanox.com, Daniel Borkmann, Vakul Garg

Add selftests for tls socket.  Tests various iov and message options,
poll blocking and nonblocking behavior, partial message sends / receives,
 and control message data.  Tests should pass regardless of if TLS
is enabled in the kernel or not, and print a warning message if not.

Signed-off-by: Dave Watson <davejwatson@fb.com>
---
 tools/testing/selftests/net/Makefile |   2 +-
 tools/testing/selftests/net/tls.c    | 692 +++++++++++++++++++++++++++
 2 files changed, 693 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/net/tls.c

diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 663e11e85727..9cca68e440a0 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -13,7 +13,7 @@ TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy
 TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd
 TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx
 TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
-TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict
+TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls
 
 include ../lib.mk
 
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
new file mode 100644
index 000000000000..b3ebf2646e52
--- /dev/null
+++ b/tools/testing/selftests/net/tls.c
@@ -0,0 +1,692 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <linux/tls.h>
+#include <linux/tcp.h>
+#include <linux/socket.h>
+
+#include <sys/types.h>
+#include <sys/sendfile.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include "../kselftest_harness.h"
+
+#define TLS_PAYLOAD_MAX_LEN 16384
+#define SOL_TLS 282
+
+FIXTURE(tls)
+{
+	int fd, cfd;
+	bool notls;
+};
+
+FIXTURE_SETUP(tls)
+{
+	struct tls12_crypto_info_aes_gcm_128 tls12;
+	struct sockaddr_in addr;
+	socklen_t len;
+	int sfd, ret;
+
+	self->notls = false;
+	len = sizeof(addr);
+
+	memset(&tls12, 0, sizeof(tls12));
+	tls12.info.version = TLS_1_2_VERSION;
+	tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128;
+
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	addr.sin_port = 0;
+
+	self->fd = socket(AF_INET, SOCK_STREAM, 0);
+	sfd = socket(AF_INET, SOCK_STREAM, 0);
+
+	ret = bind(sfd, &addr, sizeof(addr));
+	ASSERT_EQ(ret, 0);
+	ret = listen(sfd, 10);
+	ASSERT_EQ(ret, 0);
+
+	ret = getsockname(sfd, &addr, &len);
+	ASSERT_EQ(ret, 0);
+
+	ret = connect(self->fd, &addr, sizeof(addr));
+	ASSERT_EQ(ret, 0);
+
+	ret = setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+	if (ret != 0) {
+		self->notls = true;
+		printf("Failure setting TCP_ULP, testing without tls\n");
+	}
+
+	if (!self->notls) {
+		ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12,
+				 sizeof(tls12));
+		ASSERT_EQ(ret, 0);
+	}
+
+	self->cfd = accept(sfd, &addr, &len);
+	ASSERT_GE(self->cfd, 0);
+
+	if (!self->notls) {
+		ret = setsockopt(self->cfd, IPPROTO_TCP, TCP_ULP, "tls",
+				 sizeof("tls"));
+		ASSERT_EQ(ret, 0);
+
+		ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12,
+				 sizeof(tls12));
+		ASSERT_EQ(ret, 0);
+	}
+
+	close(sfd);
+}
+
+FIXTURE_TEARDOWN(tls)
+{
+	close(self->fd);
+	close(self->cfd);
+}
+
+TEST_F(tls, sendfile)
+{
+	int filefd = open("/proc/self/exe", O_RDONLY);
+	struct stat st;
+
+	EXPECT_GE(filefd, 0);
+	fstat(filefd, &st);
+	EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
+}
+
+TEST_F(tls, send_then_sendfile)
+{
+	int filefd = open("/proc/self/exe", O_RDONLY);
+	char const *test_str = "test_send";
+	int to_send = strlen(test_str) + 1;
+	char recv_buf[10];
+	struct stat st;
+	char *buf;
+
+	EXPECT_GE(filefd, 0);
+	fstat(filefd, &st);
+	buf = (char *)malloc(st.st_size);
+
+	EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send);
+	EXPECT_EQ(recv(self->cfd, recv_buf, to_send, 0), to_send);
+	EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0);
+
+	EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
+	EXPECT_EQ(recv(self->cfd, buf, st.st_size, 0), st.st_size);
+}
+
+TEST_F(tls, recv_max)
+{
+	unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
+	char recv_mem[TLS_PAYLOAD_MAX_LEN];
+	char buf[TLS_PAYLOAD_MAX_LEN];
+
+	EXPECT_GE(send(self->fd, buf, send_len, 0), 0);
+	EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
+	EXPECT_EQ(memcmp(buf, recv_mem, send_len), 0);
+}
+
+TEST_F(tls, recv_small)
+{
+	char const *test_str = "test_read";
+	int send_len = 10;
+	char buf[10];
+
+	send_len = strlen(test_str) + 1;
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+	EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+TEST_F(tls, msg_more)
+{
+	char const *test_str = "test_read";
+	int send_len = 10;
+	char buf[10 * 2];
+
+	EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);
+	EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1);
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_DONTWAIT),
+		  send_len * 2);
+	EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+TEST_F(tls, sendmsg_single)
+{
+	struct msghdr msg;
+
+	char const *test_str = "test_sendmsg";
+	size_t send_len = 13;
+	struct iovec vec;
+	char buf[13];
+
+	vec.iov_base = (char *)test_str;
+	vec.iov_len = send_len;
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_iov = &vec;
+	msg.msg_iovlen = 1;
+	EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+	EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+TEST_F(tls, sendmsg_large)
+{
+	void *mem = malloc(16384);
+	size_t send_len = 16384;
+	size_t sends = 128;
+	struct msghdr msg;
+	size_t recvs = 0;
+	size_t sent = 0;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	while (sent++ < sends) {
+		struct iovec vec = { (void *)mem, send_len };
+
+		msg.msg_iov = &vec;
+		msg.msg_iovlen = 1;
+		EXPECT_EQ(sendmsg(self->cfd, &msg, 0), send_len);
+	}
+
+	while (recvs++ < sends)
+		EXPECT_NE(recv(self->fd, mem, send_len, 0), -1);
+
+	free(mem);
+}
+
+TEST_F(tls, sendmsg_multiple)
+{
+	char const *test_str = "test_sendmsg_multiple";
+	struct iovec vec[5];
+	char *test_strs[5];
+	struct msghdr msg;
+	int total_len = 0;
+	int len_cmp = 0;
+	int iov_len = 5;
+	char *buf;
+	int i;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	for (i = 0; i < iov_len; i++) {
+		test_strs[i] = (char *)malloc(strlen(test_str) + 1);
+		snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
+		vec[i].iov_base = (void *)test_strs[i];
+		vec[i].iov_len = strlen(test_strs[i]) + 1;
+		total_len += vec[i].iov_len;
+	}
+	msg.msg_iov = vec;
+	msg.msg_iovlen = iov_len;
+
+	EXPECT_EQ(sendmsg(self->cfd, &msg, 0), total_len);
+	buf = malloc(total_len);
+	EXPECT_NE(recv(self->fd, buf, total_len, 0), -1);
+	for (i = 0; i < iov_len; i++) {
+		EXPECT_EQ(memcmp(test_strs[i], buf + len_cmp,
+				 strlen(test_strs[i])),
+			  0);
+		len_cmp += strlen(buf + len_cmp) + 1;
+	}
+	for (i = 0; i < iov_len; i++)
+		free(test_strs[i]);
+	free(buf);
+}
+
+TEST_F(tls, sendmsg_multiple_stress)
+{
+	char const *test_str = "abcdefghijklmno";
+	struct iovec vec[1024];
+	char *test_strs[1024];
+	int iov_len = 1024;
+	int total_len = 0;
+	char buf[1 << 14];
+	struct msghdr msg;
+	int len_cmp = 0;
+	int i;
+
+	memset(&msg, 0, sizeof(struct msghdr));
+	for (i = 0; i < iov_len; i++) {
+		test_strs[i] = (char *)malloc(strlen(test_str) + 1);
+		snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
+		vec[i].iov_base = (void *)test_strs[i];
+		vec[i].iov_len = strlen(test_strs[i]) + 1;
+		total_len += vec[i].iov_len;
+	}
+	msg.msg_iov = vec;
+	msg.msg_iovlen = iov_len;
+
+	EXPECT_EQ(sendmsg(self->fd, &msg, 0), total_len);
+	EXPECT_NE(recv(self->cfd, buf, total_len, 0), -1);
+
+	for (i = 0; i < iov_len; i++)
+		len_cmp += strlen(buf + len_cmp) + 1;
+
+	for (i = 0; i < iov_len; i++)
+		free(test_strs[i]);
+}
+
+TEST_F(tls, splice_from_pipe)
+{
+	int send_len = TLS_PAYLOAD_MAX_LEN;
+	char mem_send[TLS_PAYLOAD_MAX_LEN];
+	char mem_recv[TLS_PAYLOAD_MAX_LEN];
+	int p[2];
+
+	ASSERT_GE(pipe(p), 0);
+	EXPECT_GE(write(p[1], mem_send, send_len), 0);
+	EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0);
+	EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
+	EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+}
+
+TEST_F(tls, splice_from_pipe2)
+{
+	int send_len = 16000;
+	char mem_send[16000];
+	char mem_recv[16000];
+	int p2[2];
+	int p[2];
+
+	ASSERT_GE(pipe(p), 0);
+	ASSERT_GE(pipe(p2), 0);
+	EXPECT_GE(write(p[1], mem_send, 8000), 0);
+	EXPECT_GE(splice(p[0], NULL, self->fd, NULL, 8000, 0), 0);
+	EXPECT_GE(write(p2[1], mem_send + 8000, 8000), 0);
+	EXPECT_GE(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 0);
+	EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
+	EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+}
+
+TEST_F(tls, send_and_splice)
+{
+	int send_len = TLS_PAYLOAD_MAX_LEN;
+	char mem_send[TLS_PAYLOAD_MAX_LEN];
+	char mem_recv[TLS_PAYLOAD_MAX_LEN];
+	char const *test_str = "test_read";
+	int send_len2 = 10;
+	char buf[10];
+	int p[2];
+
+	ASSERT_GE(pipe(p), 0);
+	EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2);
+	EXPECT_NE(recv(self->cfd, buf, send_len2, 0), -1);
+	EXPECT_EQ(memcmp(test_str, buf, send_len2), 0);
+
+	EXPECT_GE(write(p[1], mem_send, send_len), send_len);
+	EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len);
+
+	EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
+	EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+}
+
+TEST_F(tls, splice_to_pipe)
+{
+	int send_len = TLS_PAYLOAD_MAX_LEN;
+	char mem_send[TLS_PAYLOAD_MAX_LEN];
+	char mem_recv[TLS_PAYLOAD_MAX_LEN];
+	int p[2];
+
+	ASSERT_GE(pipe(p), 0);
+	EXPECT_GE(send(self->fd, mem_send, send_len, 0), 0);
+	EXPECT_GE(splice(self->cfd, NULL, p[1], NULL, send_len, 0), 0);
+	EXPECT_GE(read(p[0], mem_recv, send_len), 0);
+	EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
+}
+
+TEST_F(tls, recvmsg_single)
+{
+	char const *test_str = "test_recvmsg_single";
+	int send_len = strlen(test_str) + 1;
+	char buf[20];
+	struct msghdr hdr;
+	struct iovec vec;
+
+	memset(&hdr, 0, sizeof(hdr));
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	vec.iov_base = (char *)buf;
+	vec.iov_len = send_len;
+	hdr.msg_iovlen = 1;
+	hdr.msg_iov = &vec;
+	EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
+	EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
+}
+
+TEST_F(tls, recvmsg_single_max)
+{
+	int send_len = TLS_PAYLOAD_MAX_LEN;
+	char send_mem[TLS_PAYLOAD_MAX_LEN];
+	char recv_mem[TLS_PAYLOAD_MAX_LEN];
+	struct iovec vec;
+	struct msghdr hdr;
+
+	EXPECT_EQ(send(self->fd, send_mem, send_len, 0), send_len);
+	vec.iov_base = (char *)recv_mem;
+	vec.iov_len = TLS_PAYLOAD_MAX_LEN;
+
+	hdr.msg_iovlen = 1;
+	hdr.msg_iov = &vec;
+	EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
+	EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
+}
+
+TEST_F(tls, recvmsg_multiple)
+{
+	unsigned int msg_iovlen = 1024;
+	unsigned int len_compared = 0;
+	struct iovec vec[1024];
+	char *iov_base[1024];
+	unsigned int iov_len = 16;
+	int send_len = 1 << 14;
+	char buf[1 << 14];
+	struct msghdr hdr;
+	int i;
+
+	EXPECT_EQ(send(self->fd, buf, send_len, 0), send_len);
+	for (i = 0; i < msg_iovlen; i++) {
+		iov_base[i] = (char *)malloc(iov_len);
+		vec[i].iov_base = iov_base[i];
+		vec[i].iov_len = iov_len;
+	}
+
+	hdr.msg_iovlen = msg_iovlen;
+	hdr.msg_iov = vec;
+	EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
+	for (i = 0; i < msg_iovlen; i++)
+		len_compared += iov_len;
+
+	for (i = 0; i < msg_iovlen; i++)
+		free(iov_base[i]);
+}
+
+TEST_F(tls, single_send_multiple_recv)
+{
+	unsigned int total_len = TLS_PAYLOAD_MAX_LEN * 2;
+	unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
+	char send_mem[TLS_PAYLOAD_MAX_LEN * 2];
+	char recv_mem[TLS_PAYLOAD_MAX_LEN * 2];
+
+	EXPECT_GE(send(self->fd, send_mem, total_len, 0), 0);
+	memset(recv_mem, 0, total_len);
+
+	EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
+	EXPECT_NE(recv(self->cfd, recv_mem + send_len, send_len, 0), -1);
+	EXPECT_EQ(memcmp(send_mem, recv_mem, total_len), 0);
+}
+
+TEST_F(tls, multiple_send_single_recv)
+{
+	unsigned int total_len = 2 * 10;
+	unsigned int send_len = 10;
+	char recv_mem[2 * 10];
+	char send_mem[10];
+
+	EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
+	EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
+	memset(recv_mem, 0, total_len);
+	EXPECT_EQ(recv(self->cfd, recv_mem, total_len, 0), total_len);
+
+	EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
+	EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0);
+}
+
+TEST_F(tls, recv_partial)
+{
+	char const *test_str = "test_read_partial";
+	char const *test_str_first = "test_read";
+	char const *test_str_second = "_partial";
+	int send_len = strlen(test_str) + 1;
+	char recv_mem[18];
+
+	memset(recv_mem, 0, sizeof(recv_mem));
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_first), 0), -1);
+	EXPECT_EQ(memcmp(test_str_first, recv_mem, strlen(test_str_first)), 0);
+	memset(recv_mem, 0, sizeof(recv_mem));
+	EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_second), 0), -1);
+	EXPECT_EQ(memcmp(test_str_second, recv_mem, strlen(test_str_second)),
+		  0);
+}
+
+TEST_F(tls, recv_nonblock)
+{
+	char buf[4096];
+	bool err;
+
+	EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
+	err = (errno == EAGAIN || errno == EWOULDBLOCK);
+	EXPECT_EQ(err, true);
+}
+
+TEST_F(tls, recv_peek)
+{
+	char const *test_str = "test_read_peek";
+	int send_len = strlen(test_str) + 1;
+	char buf[15];
+
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
+	EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
+	memset(buf, 0, sizeof(buf));
+	EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+	EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
+}
+
+TEST_F(tls, recv_peek_multiple)
+{
+	char const *test_str = "test_read_peek";
+	int send_len = strlen(test_str) + 1;
+	unsigned int num_peeks = 100;
+	char buf[15];
+	int i;
+
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	for (i = 0; i < num_peeks; i++) {
+		EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
+		EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
+		memset(buf, 0, sizeof(buf));
+	}
+	EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
+	EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
+}
+
+TEST_F(tls, pollin)
+{
+	char const *test_str = "test_poll";
+	struct pollfd fd = { 0, 0, 0 };
+	char buf[10];
+	int send_len = 10;
+
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	fd.fd = self->cfd;
+	fd.events = POLLIN;
+
+	EXPECT_EQ(poll(&fd, 1, 20), 1);
+	EXPECT_EQ(fd.revents & POLLIN, 1);
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
+	/* Test timing out */
+	EXPECT_EQ(poll(&fd, 1, 20), 0);
+}
+
+TEST_F(tls, poll_wait)
+{
+	char const *test_str = "test_poll_wait";
+	int send_len = strlen(test_str) + 1;
+	struct pollfd fd = { 0, 0, 0 };
+	char recv_mem[15];
+
+	fd.fd = self->cfd;
+	fd.events = POLLIN;
+	EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
+	/* Set timeout to inf. secs */
+	EXPECT_EQ(poll(&fd, 1, -1), 1);
+	EXPECT_EQ(fd.revents & POLLIN, 1);
+	EXPECT_EQ(recv(self->cfd, recv_mem, send_len, 0), send_len);
+}
+
+TEST_F(tls, blocking)
+{
+	size_t data = 100000;
+	int res = fork();
+
+	EXPECT_NE(res, -1);
+
+	if (res) {
+		/* parent */
+		size_t left = data;
+		char buf[16384];
+		int status;
+		int pid2;
+
+		while (left) {
+			int res = send(self->fd, buf,
+				       left > 16384 ? 16384 : left, 0);
+
+			EXPECT_GE(res, 0);
+			left -= res;
+		}
+
+		pid2 = wait(&status);
+		EXPECT_EQ(status, 0);
+		EXPECT_EQ(res, pid2);
+	} else {
+		/* child */
+		size_t left = data;
+		char buf[16384];
+
+		while (left) {
+			int res = recv(self->cfd, buf,
+				       left > 16384 ? 16384 : left, 0);
+
+			EXPECT_GE(res, 0);
+			left -= res;
+		}
+	}
+}
+
+TEST_F(tls, nonblocking)
+{
+	size_t data = 100000;
+	int sendbuf = 100;
+	int flags;
+	int res;
+
+	flags = fcntl(self->fd, F_GETFL, 0);
+	fcntl(self->fd, F_SETFL, flags | O_NONBLOCK);
+	fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK);
+
+	/* Ensure nonblocking behavior by imposing a small send
+	 * buffer.
+	 */
+	EXPECT_EQ(setsockopt(self->fd, SOL_SOCKET, SO_SNDBUF,
+			     &sendbuf, sizeof(sendbuf)), 0);
+
+	res = fork();
+	EXPECT_NE(res, -1);
+
+	if (res) {
+		/* parent */
+		bool eagain = false;
+		size_t left = data;
+		char buf[16384];
+		int status;
+		int pid2;
+
+		while (left) {
+			int res = send(self->fd, buf,
+				       left > 16384 ? 16384 : left, 0);
+
+			if (res == -1 && errno == EAGAIN) {
+				eagain = true;
+				usleep(10000);
+				continue;
+			}
+			EXPECT_GE(res, 0);
+			left -= res;
+		}
+
+		EXPECT_TRUE(eagain);
+		pid2 = wait(&status);
+
+		EXPECT_EQ(status, 0);
+		EXPECT_EQ(res, pid2);
+	} else {
+		/* child */
+		bool eagain = false;
+		size_t left = data;
+		char buf[16384];
+
+		while (left) {
+			int res = recv(self->cfd, buf,
+				       left > 16384 ? 16384 : left, 0);
+
+			if (res == -1 && errno == EAGAIN) {
+				eagain = true;
+				usleep(10000);
+				continue;
+			}
+			EXPECT_GE(res, 0);
+			left -= res;
+		}
+		EXPECT_TRUE(eagain);
+	}
+}
+
+TEST_F(tls, control_msg)
+{
+	if (self->notls)
+		return;
+
+	char cbuf[CMSG_SPACE(sizeof(char))];
+	char const *test_str = "test_read";
+	int cmsg_len = sizeof(char);
+	char record_type = 100;
+	struct cmsghdr *cmsg;
+	struct msghdr msg;
+	int send_len = 10;
+	struct iovec vec;
+	char buf[10];
+
+	vec.iov_base = (char *)test_str;
+	vec.iov_len = 10;
+	memset(&msg, 0, sizeof(struct msghdr));
+	msg.msg_iov = &vec;
+	msg.msg_iovlen = 1;
+	msg.msg_control = cbuf;
+	msg.msg_controllen = sizeof(cbuf);
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_level = SOL_TLS;
+	/* test sending non-record types. */
+	cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
+	cmsg->cmsg_len = CMSG_LEN(cmsg_len);
+	*CMSG_DATA(cmsg) = record_type;
+	msg.msg_controllen = cmsg->cmsg_len;
+
+	EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
+	/* Should fail because we didn't provide a control message */
+	EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
+
+	vec.iov_base = buf;
+	EXPECT_EQ(recvmsg(self->cfd, &msg, 0), send_len);
+	cmsg = CMSG_FIRSTHDR(&msg);
+	EXPECT_NE(cmsg, NULL);
+	EXPECT_EQ(cmsg->cmsg_level, SOL_TLS);
+	EXPECT_EQ(cmsg->cmsg_type, TLS_GET_RECORD_TYPE);
+	record_type = *((unsigned char *)CMSG_DATA(cmsg));
+	EXPECT_EQ(record_type, 100);
+	EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
+}
+
+TEST_HARNESS_MAIN
-- 
2.17.1

^ permalink raw reply related

* Re: [net 0/4][pull request] Intel Wired LAN Driver Updates 2018-07-12
From: David Miller @ 2018-07-12 17:27 UTC (permalink / raw)
  To: jeffrey.t.kirsher; +Cc: netdev, nhorman, sassmann, jogreene
In-Reply-To: <20180712152756.26015-1-jeffrey.t.kirsher@intel.com>

From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Date: Thu, 12 Jul 2018 08:27:52 -0700

> This series contains updates to ixgbe and e100/e1000 kernel documentation.
> 
> Alex fixes ixgbe to ensure that we are more explicit about the ordering
> of updates to the receive address register (RAR) table.
> 
> Dan Carpenter fixes an issue where we were reading one element beyond
> the end of the array.
> 
> Mauro Carvalho Chehab fixes formatting issues in the e100.rst and
> e1000.rst that were causing errors during 'make htmldocs'.
> 
> The following are changes since commit 20c4515a1af770f4fb0dc6b044ffc9a6031e5767:
>   qed: fix spelling mistake "successffuly" -> "successfully"
> and are available in the git repository at:
>   git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-queue 10GbE

Pulled, thanks Jeff.

^ permalink raw reply

* [PATCH/v2] bonding: Fix a typo in bonding.txt
From: Masanari Iida @ 2018-07-12 17:21 UTC (permalink / raw)
  To: linux-kernel, corbet, netdev, j.vosburgh, vfalico, andy; +Cc: Masanari Iida
In-Reply-To: <20180712160517.7382-1-standby24x7@gmail.com>

This patch fixes a spelling typo in bonding.txt

Signed-off-by: Masanari Iida <standby24x7@gmail.com>
---
 Documentation/networking/bonding.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index c13214d073a4..d3e5dd26db12 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -1490,7 +1490,7 @@ To remove an ARP target:
 
 To configure the interval between learning packet transmits:
 # echo 12 > /sys/class/net/bond0/bonding/lp_interval
-	NOTE: the lp_inteval is the number of seconds between instances where
+	NOTE: the lp_interval is the number of seconds between instances where
 the bonding driver sends learning packets to each slaves peer switch.  The
 default interval is 1 second.
 
-- 
2.18.0.96.ged843436dd49

^ permalink raw reply related

* Re: [PATCH bpf-next 0/3] bpf: install eBPF helper man page along with bpftool doc
From: Daniel Borkmann @ 2018-07-12 17:00 UTC (permalink / raw)
  To: Quentin Monnet, ast; +Cc: netdev, oss-drivers
In-Reply-To: <20180712115224.17364-1-quentin.monnet@netronome.com>

On 07/12/2018 01:52 PM, Quentin Monnet wrote:
> The three patches in this series are related to the documentation for eBPF
> helpers. The first patch brings minor formatting edits to the documentation
> in include/uapi/linux/bpf.h, and the second one updates the related header
> file under tools/.
> 
> The third patch adds a Makefile under tools/bpf for generating the
> documentation (man pages) about eBPF helpers. The targets defined in this
> file can also be called from the bpftool directory (please refer to
> relevant commit logs for details).
> 
> Quentin Monnet (3):
>   bpf: fix documentation for eBPF helpers
>   tools: bpf: synchronise BPF UAPI header with tools
>   tools: bpf: build and install man page for eBPF helpers from bpftool/

Looks good, applied to bpf-next, thanks Quentin!

^ permalink raw reply

* Re: [PATCH v3 net-next 00/19] TLS offload rx, netdev & mlx5
From: Dave Watson @ 2018-07-12 16:54 UTC (permalink / raw)
  To: Boris Pismenny; +Cc: davem, netdev, aviadye, saeedm
In-Reply-To: <1531338873-18466-1-git-send-email-borisp@mellanox.com>

On 07/11/18 10:54 PM, Boris Pismenny wrote:
> Hi,
> 
> The following series provides TLS RX inline crypto offload.

All the tls patches look good to me except #10

"tls: Fix zerocopy_from_iter iov handling"

which seems to break the non-device zerocopy flow. 

The integration is very clean, thanks!

> 
> v2->v3:
>     - Fix typo
>     - Adjust cover letter
>     - Fix bug in zero copy flows
>     - Use network byte order for the record number in resync
>     - Adjust the sequence provided in resync
> 
> v1->v2:
>     - Fix bisectability problems due to variable name changes
>     - Fix potential uninitialized return value
> 

^ permalink raw reply

* Re: [PATCH net-next] net: gro: properly remove skb from list
From: Tyler Hicks @ 2018-07-12 16:54 UTC (permalink / raw)
  To: Prashant Bhole; +Cc: David S . Miller, Jesper Dangaard Brouer, netdev
In-Reply-To: <20180712072459.8800-1-bhole_prashant_q7@lab.ntt.co.jp>

[-- Attachment #1: Type: text/plain, Size: 6352 bytes --]

On 2018-07-12 16:24:59, Prashant Bhole wrote:
> Following crash occurs in validate_xmit_skb_list() when same skb is
> iterated multiple times in the loop and consume_skb() is called.
> 
> The root cause is calling list_del_init(&skb->list) and not clearing
> skb->next in d4546c2509b1. list_del_init(&skb->list) sets skb->next
> to point to skb itself. skb->next needs to be cleared because other
> parts of network stack uses another kind of SKB lists.
> validate_xmit_skb_list() uses such list.
> 
> A similar type of bugfix was reported by Jesper Dangaard Brouer.
> https://patchwork.ozlabs.org/patch/942541/
> 
> This patch clears skb->next and changes list_del_init() to list_del()
> so that list->prev will maintain the list poison.
> 
> [  148.185511] ==================================================================
> [  148.187865] BUG: KASAN: use-after-free in validate_xmit_skb_list+0x4b/0xa0
> [  148.190158] Read of size 8 at addr ffff8801e52eefc0 by task swapper/1/0
> [  148.192940]
> [  148.193642] CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.18.0-rc3+ #25
> [  148.195423] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20180531_142017-buildhw-08.phx2.fedoraproject.org-1.fc28 04/01/2014
> [  148.199129] Call Trace:
> [  148.200565]  <IRQ>
> [  148.201911]  dump_stack+0xc6/0x14c
> [  148.203572]  ? dump_stack_print_info.cold.1+0x2f/0x2f
> [  148.205083]  ? kmsg_dump_rewind_nolock+0x59/0x59
> [  148.206307]  ? validate_xmit_skb+0x2c6/0x560
> [  148.207432]  ? debug_show_held_locks+0x30/0x30
> [  148.208571]  ? validate_xmit_skb_list+0x4b/0xa0
> [  148.211144]  print_address_description+0x6c/0x23c
> [  148.212601]  ? validate_xmit_skb_list+0x4b/0xa0
> [  148.213782]  kasan_report.cold.6+0x241/0x2fd
> [  148.214958]  validate_xmit_skb_list+0x4b/0xa0
> [  148.216494]  sch_direct_xmit+0x1b0/0x680
> [  148.217601]  ? dev_watchdog+0x4e0/0x4e0
> [  148.218675]  ? do_raw_spin_trylock+0x10/0x120
> [  148.219818]  ? do_raw_spin_lock+0xe0/0xe0
> [  148.221032]  __dev_queue_xmit+0x1167/0x1810
> [  148.222155]  ? sched_clock+0x5/0x10
> [...]
> 
> [  148.474257] Allocated by task 0:
> [  148.475363]  kasan_kmalloc+0xbf/0xe0
> [  148.476503]  kmem_cache_alloc+0xb4/0x1b0
> [  148.477654]  __build_skb+0x91/0x250
> [  148.478677]  build_skb+0x67/0x180
> [  148.479657]  e1000_clean_rx_irq+0x542/0x8a0
> [  148.480757]  e1000_clean+0x652/0xd10
> [  148.481772]  net_rx_action+0x4ea/0xc20
> [  148.482808]  __do_softirq+0x1f9/0x574
> [  148.483831]
> [  148.484575] Freed by task 0:
> [  148.485504]  __kasan_slab_free+0x12e/0x180
> [  148.486589]  kmem_cache_free+0xb4/0x240
> [  148.487634]  kfree_skbmem+0xed/0x150
> [  148.488648]  consume_skb+0x146/0x250
> [  148.489665]  validate_xmit_skb+0x2b7/0x560
> [  148.490754]  validate_xmit_skb_list+0x70/0xa0
> [  148.491897]  sch_direct_xmit+0x1b0/0x680
> [  148.493949]  __dev_queue_xmit+0x1167/0x1810
> [  148.495103]  br_dev_queue_push_xmit+0xce/0x250
> [  148.496196]  br_forward_finish+0x276/0x280
> [  148.497234]  __br_forward+0x44f/0x520
> [  148.498260]  br_forward+0x19f/0x1b0
> [  148.499264]  br_handle_frame_finish+0x65e/0x980
> [  148.500398]  NF_HOOK.constprop.10+0x290/0x2a0
> [  148.501522]  br_handle_frame+0x417/0x640
> [  148.502582]  __netif_receive_skb_core+0xaac/0x18f0
> [  148.503753]  __netif_receive_skb_one_core+0x98/0x120
> [  148.504958]  netif_receive_skb_internal+0xe3/0x330
> [  148.506154]  napi_gro_complete+0x190/0x2a0
> [  148.507243]  dev_gro_receive+0x9f7/0x1100
> [  148.508316]  napi_gro_receive+0xcb/0x260
> [  148.509387]  e1000_clean_rx_irq+0x2fc/0x8a0
> [  148.510501]  e1000_clean+0x652/0xd10
> [  148.511523]  net_rx_action+0x4ea/0xc20
> [  148.512566]  __do_softirq+0x1f9/0x574
> [  148.513598]
> [  148.514346] The buggy address belongs to the object at ffff8801e52eefc0
> [  148.514346]  which belongs to the cache skbuff_head_cache of size 232
> [  148.517047] The buggy address is located 0 bytes inside of
> [  148.517047]  232-byte region [ffff8801e52eefc0, ffff8801e52ef0a8)
> [  148.519549] The buggy address belongs to the page:
> [  148.520726] page:ffffea000794bb00 count:1 mapcount:0 mapping:ffff880106f4dfc0 index:0xffff8801e52ee840 compound_mapcount: 0
> [  148.524325] flags: 0x17ffffc0008100(slab|head)
> [  148.525481] raw: 0017ffffc0008100 ffff880106b938d0 ffff880106b938d0 ffff880106f4dfc0
> [  148.527503] raw: ffff8801e52ee840 0000000000190011 00000001ffffffff 0000000000000000
> [  148.529547] page dumped because: kasan: bad access detected
> 
> Fixes: d4546c2509b1 ("net: Convert GRO SKB handling to list_head.")
> Signed-off-by: Prashant Bhole <bhole_prashant_q7@lab.ntt.co.jp>
> Reported-by: Tyler Hicks <tyhicks@canonical.com>

Thanks for the fix! I have verified that it fixes the crash that I was
seeing.

  Tested-by: Tyler Hicks <tyhicks@canonical.com>

Your analysis of the problem makes sense. I feel like a helper function
to properly remove an skb from list_head and NULL the next pointer, in
the GRO code, before passing it on to something else that uses the
hand-rolled linked list implementation could help with maintainability.
That's just a suggestion  - this patch looks good to me:

  Reviewed-by: Tyler Hicks <tyhicks@canonical.com>

Tyler

> ---
>  net/core/dev.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/net/core/dev.c b/net/core/dev.c
> index d13cddcac41f..08c41941f912 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -5169,7 +5169,8 @@ static void __napi_gro_flush_chain(struct napi_struct *napi, u32 index,
>  	list_for_each_entry_safe_reverse(skb, p, head, list) {
>  		if (flush_old && NAPI_GRO_CB(skb)->age == jiffies)
>  			return;
> -		list_del_init(&skb->list);
> +		list_del(&skb->list);
> +		skb->next = NULL;
>  		napi_gro_complete(skb);
>  		napi->gro_count--;
>  		napi->gro_hash[index].count--;
> @@ -5350,7 +5351,8 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
>  	ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED;
>  
>  	if (pp) {
> -		list_del_init(&pp->list);
> +		list_del(&pp->list);
> +		pp->next = NULL;
>  		napi_gro_complete(pp);
>  		napi->gro_count--;
>  		napi->gro_hash[hash].count--;
> -- 
> 2.17.1
> 
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* Re: [PATCH v3 net-next 10/19] tls: Fix zerocopy_from_iter iov handling
From: Dave Watson @ 2018-07-12 16:46 UTC (permalink / raw)
  To: Boris Pismenny; +Cc: davem, netdev, aviadye, saeedm
In-Reply-To: <1531338873-18466-11-git-send-email-borisp@mellanox.com>

On 07/11/18 10:54 PM, Boris Pismenny wrote:
> zerocopy_from_iter iterates over the message, but it doesn't revert the
> updates made by the iov iteration. This patch fixes it. Now, the iov can
> be used after calling zerocopy_from_iter.

This breaks tests (which I will send up as selftests shortly).  I
believe we are depending on zerocopy_from_iter to advance the iter,
and if zerocopy_from_iter returns a failure, then we revert it.  So
you can revert it here if you want, but you'd have to advance it if we
actually used it instead.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox