* [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver
@ 2018-07-12 19:04 Bryan Whitehead
2018-07-12 19:04 ` [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo Bryan Whitehead
` (8 more replies)
0 siblings, 9 replies; 23+ messages in thread
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
@ 2018-07-12 19:04 ` Bryan Whitehead
2018-07-12 22:28 ` Andrew Lunn
2018-07-12 19:04 ` [PATCH v2 net-next 2/9] lan743x: Add support for ethtool link settings Bryan Whitehead
` (7 subsequent siblings)
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:04 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 2/9] lan743x: Add support for ethtool link settings
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
2018-07-12 19:04 ` [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo Bryan Whitehead
@ 2018-07-12 19:04 ` Bryan Whitehead
2018-07-12 22:29 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 3/9] lan743x: Add support for ethtool statistics Bryan Whitehead
` (6 subsequent siblings)
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:04 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 3/9] lan743x: Add support for ethtool statistics
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
2018-07-12 19:04 ` [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo Bryan Whitehead
2018-07-12 19:04 ` [PATCH v2 net-next 2/9] lan743x: Add support for ethtool link settings Bryan Whitehead
@ 2018-07-12 19:05 ` Bryan Whitehead
2018-07-12 22:31 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 4/9] lan743x: Add support for ethtool message level Bryan Whitehead
` (5 subsequent siblings)
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 4/9] lan743x: Add support for ethtool message level
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
` (2 preceding siblings ...)
2018-07-12 19:05 ` [PATCH v2 net-next 3/9] lan743x: Add support for ethtool statistics Bryan Whitehead
@ 2018-07-12 19:05 ` Bryan Whitehead
2018-07-12 22:31 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 5/9] lan743x: Add support for ethtool eeprom access Bryan Whitehead
` (4 subsequent siblings)
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 5/9] lan743x: Add support for ethtool eeprom access
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
` (3 preceding siblings ...)
2018-07-12 19:05 ` [PATCH v2 net-next 4/9] lan743x: Add support for ethtool message level Bryan Whitehead
@ 2018-07-12 19:05 ` Bryan Whitehead
2018-07-12 22:35 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 6/9] lan743x: Add power management support Bryan Whitehead
` (3 subsequent siblings)
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 6/9] lan743x: Add power management support
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
` (4 preceding siblings ...)
2018-07-12 19:05 ` [PATCH v2 net-next 5/9] lan743x: Add support for ethtool eeprom access Bryan Whitehead
@ 2018-07-12 19:05 ` Bryan Whitehead
2018-07-12 22:42 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 7/9] lan743x: Add EEE support Bryan Whitehead
` (2 subsequent siblings)
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 7/9] lan743x: Add EEE support
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
` (5 preceding siblings ...)
2018-07-12 19:05 ` [PATCH v2 net-next 6/9] lan743x: Add power management support Bryan Whitehead
@ 2018-07-12 19:05 ` Bryan Whitehead
2018-07-12 22:49 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 8/9] lan743x: Add RSS support Bryan Whitehead
2018-07-12 19:05 ` [PATCH v2 net-next 9/9] lan743x: Add PTP support Bryan Whitehead
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 8/9] lan743x: Add RSS support
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
` (6 preceding siblings ...)
2018-07-12 19:05 ` [PATCH v2 net-next 7/9] lan743x: Add EEE support Bryan Whitehead
@ 2018-07-12 19:05 ` Bryan Whitehead
2018-07-12 19:05 ` [PATCH v2 net-next 9/9] lan743x: Add PTP support Bryan Whitehead
8 siblings, 0 replies; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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 [flat|nested] 23+ messages in thread
* [PATCH v2 net-next 9/9] lan743x: Add PTP support
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
` (7 preceding siblings ...)
2018-07-12 19:05 ` [PATCH v2 net-next 8/9] lan743x: Add RSS support Bryan Whitehead
@ 2018-07-12 19:05 ` Bryan Whitehead
2018-07-13 3:31 ` Richard Cochran
8 siblings, 1 reply; 23+ messages in thread
From: Bryan Whitehead @ 2018-07-12 19:05 UTC (permalink / raw)
To: davem; +Cc: netdev, UNGLinuxDriver, richardcochran
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, ¤t_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 [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo
2018-07-12 19:04 ` [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo Bryan Whitehead
@ 2018-07-12 22:28 ` Andrew Lunn
0 siblings, 0 replies; 23+ messages in thread
From: Andrew Lunn @ 2018-07-12 22:28 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
On Thu, Jul 12, 2018 at 03:04:58PM -0400, Bryan Whitehead wrote:
> Implement ethtool get_drvinfo
>
> Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 2/9] lan743x: Add support for ethtool link settings
2018-07-12 19:04 ` [PATCH v2 net-next 2/9] lan743x: Add support for ethtool link settings Bryan Whitehead
@ 2018-07-12 22:29 ` Andrew Lunn
0 siblings, 0 replies; 23+ messages in thread
From: Andrew Lunn @ 2018-07-12 22:29 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
On Thu, Jul 12, 2018 at 03:04:59PM -0400, Bryan Whitehead wrote:
> Use default link setting functions
>
> Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 3/9] lan743x: Add support for ethtool statistics
2018-07-12 19:05 ` [PATCH v2 net-next 3/9] lan743x: Add support for ethtool statistics Bryan Whitehead
@ 2018-07-12 22:31 ` Andrew Lunn
0 siblings, 0 replies; 23+ messages in thread
From: Andrew Lunn @ 2018-07-12 22:31 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
On Thu, Jul 12, 2018 at 03:05:00PM -0400, Bryan Whitehead wrote:
> Implement ethtool statistics
>
> Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 4/9] lan743x: Add support for ethtool message level
2018-07-12 19:05 ` [PATCH v2 net-next 4/9] lan743x: Add support for ethtool message level Bryan Whitehead
@ 2018-07-12 22:31 ` Andrew Lunn
0 siblings, 0 replies; 23+ messages in thread
From: Andrew Lunn @ 2018-07-12 22:31 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
On Thu, Jul 12, 2018 at 03:05:01PM -0400, Bryan Whitehead wrote:
> Implement ethtool message level
>
> Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 5/9] lan743x: Add support for ethtool eeprom access
2018-07-12 19:05 ` [PATCH v2 net-next 5/9] lan743x: Add support for ethtool eeprom access Bryan Whitehead
@ 2018-07-12 22:35 ` Andrew Lunn
0 siblings, 0 replies; 23+ messages in thread
From: Andrew Lunn @ 2018-07-12 22:35 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
On Thu, Jul 12, 2018 at 03:05:02PM -0400, Bryan Whitehead wrote:
> Implement ethtool eeprom access
> Also provides access to OTP (One Time Programming)
>
> Signed-off-by: Bryan Whitehead <Bryan.Whitehead@microchip.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 6/9] lan743x: Add power management support
2018-07-12 19:05 ` [PATCH v2 net-next 6/9] lan743x: Add power management support Bryan Whitehead
@ 2018-07-12 22:42 ` Andrew Lunn
2018-07-18 20:05 ` Bryan.Whitehead
0 siblings, 1 reply; 23+ messages in thread
From: Andrew Lunn @ 2018-07-12 22:42 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
> +#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);
Hi Bryan
This seems asymmetric. set_wol you call into the phylib to enable wol
in the PHY. But get_wol does not call into phylib. So the phy has no
chance to set what it supports.
Andrew
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 7/9] lan743x: Add EEE support
2018-07-12 19:05 ` [PATCH v2 net-next 7/9] lan743x: Add EEE support Bryan Whitehead
@ 2018-07-12 22:49 ` Andrew Lunn
2018-07-13 16:35 ` Bryan.Whitehead
0 siblings, 1 reply; 23+ messages in thread
From: Andrew Lunn @ 2018-07-12 22:49 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
> +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");
> + }
> +
Hi Bryan
You should call phy_ethtool_set_eee() in both cases, so that it gets
disabled in the PHY as well. It needs to stop advertising it.
Andrew
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 9/9] lan743x: Add PTP support
2018-07-12 19:05 ` [PATCH v2 net-next 9/9] lan743x: Add PTP support Bryan Whitehead
@ 2018-07-13 3:31 ` Richard Cochran
2018-07-18 20:04 ` Bryan.Whitehead
0 siblings, 1 reply; 23+ messages in thread
From: Richard Cochran @ 2018-07-13 3:31 UTC (permalink / raw)
To: Bryan Whitehead; +Cc: davem, netdev, UNGLinuxDriver
On Thu, Jul 12, 2018 at 03:05:06PM -0400, Bryan Whitehead wrote:
> +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
No need for this ifdeferry - ptp_clock_index() already returns -1 in
that case.
> + 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;
> +}
> +
> @@ -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)) {
Bad line break.
> 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);
This is poor coding style. Please find a better way.
> + }
> +
> +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)) {
Why not use && instead of three nested tests?
> + 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_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 */
The constant ifdef CONFIG_PTP_1588_CLOCK is poor style and
unnecessary. Just group this code together under one ifdef, or better
yet put it into its own file.
> +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)
Please implement adjfine().
* @adjfine: Adjusts the frequency of the hardware clock.
* parameter scaled_ppm: Desired frequency offset from
* nominal frequency in parts per million, but with a
* 16 bit binary fractional field.
*
* @adjfreq: Adjusts the frequency of the hardware clock.
* This method is deprecated. New drivers should implement
* the @adjfine method instead.
* parameter delta: Desired frequency offset from nominal frequency
* in parts per billion
> +{
> + struct lan743x_ptp *ptp = container_of(ptpci, struct lan743x_ptp,
> + ptp_clock_info);
> + struct lan743x_adapter *adapter = container_of(ptp,
> + struct lan743x_adapter,
> + ptp);
Coding style:
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);
You need to use the div_u64() macro here.
> +
> + 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);
This definitely should be at the debug level, or just delete it altogether.
> + 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);
Coding style.
> + 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);
Again, debug or delete.
> +
> + 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);
Style.
> +
> + if (ts) {
> + u32 seconds = 0;
> + u32 nano_seconds = 0;
Please declare stack variables at the top of the function.
> +
> + 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);
Debug/delete
> + } else {
> + netif_warn(adapter, drv, adapter->netdev, "ts == NULL\n");
> + return -EINVAL;
No need to test for 'ts'. The caller must supply a valid pointer.
> + }
> + 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) {
Actually seconds will exceed four bytes sooner than you think. If
your HW has a restriction, then simply keep the seconds offset in SW
in the driver, adding it in where needed (like when reading the clock
or providing time stamps).
> + 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;
So this function is really *not* implementing the PTP_CLK_REQ_PPS
feature but rather the PTP_CLK_REQ_PEROUT with a period of once per
second.
PTP_CLK_REQ_PPS means placing a PPS event into the kernel's "hardpps"
subsystem by calling ptp_clock_event().
I'm sorry this isn't really documented. I should fix that.
If you HW can output arbitrary signals, then you should implement
PTP_CLK_REQ_PEROUT. In any case, you shouldn't advertise the
ptp_clock_info.pps capability.
> + 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, ¤t_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);
Please no new tasklets. Instead use a work queue. If you need lower
latency, consider using ptp_schedule_worker().
> + 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");
Don't print like this from an ISR. Or is this an error, since you
don't enable this bit?
> + /* 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;
Put same types on one line:
int c, i;
> +
> + 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;
Locals to top of function please.
> + 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_) {
As a sanity check, you should break this loop using a counter.
> + 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);
Use the TAI clock instead.
> + 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);
Use the macro.
> + nano_seconds += (time_step_ns % 1000000000LL);
Actually, use div_u64_rem() to avoid the % operator.
> + if (nano_seconds >= 1000000000) {
How can this test be true?
> + 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;
Ugh. Now you have these defined twice. Move them to the top, please.
> + 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);
Use division macro for 64 bit.
> + 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 */
Avoid tail comments please.
> + }
> + spin_unlock_bh(&ptp->tx_ts_lock);
> + return result;
> +}
Thanks,
Richard
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v2 net-next 7/9] lan743x: Add EEE support
2018-07-12 22:49 ` Andrew Lunn
@ 2018-07-13 16:35 ` Bryan.Whitehead
0 siblings, 0 replies; 23+ messages in thread
From: Bryan.Whitehead @ 2018-07-13 16:35 UTC (permalink / raw)
To: andrew; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
> > +static int lan743x_ethtool_set_eee(struct net_device *netdev,
> > + struct ethtool_eee *eee)
> > +{
<snip>
>
> Hi Bryan
>
> You should call phy_ethtool_set_eee() in both cases, so that it gets disabled
> in the PHY as well. It needs to stop advertising it.
>
> Andrew
OK, thanks Andrew, will do.
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v2 net-next 9/9] lan743x: Add PTP support
2018-07-13 3:31 ` Richard Cochran
@ 2018-07-18 20:04 ` Bryan.Whitehead
2018-07-18 20:55 ` Richard Cochran
0 siblings, 1 reply; 23+ messages in thread
From: Bryan.Whitehead @ 2018-07-18 20:04 UTC (permalink / raw)
To: richardcochran; +Cc: davem, netdev, UNGLinuxDriver
Hi Richard,
Thank you for your detailed feedback. I'm working on it now, but I feel it will take a little extra time to complete. Therefor I'm planning to remove PTP support from this patch series, and resubmit it in a new patch later.
I also have a few questions below.
> -----Original Message-----
> From: Richard Cochran [mailto:richardcochran@gmail.com]
> Sent: Thursday, July 12, 2018 11:32 PM
> To: Bryan Whitehead - C21958 <Bryan.Whitehead@microchip.com>
> Cc: davem@davemloft.net; netdev@vger.kernel.org; UNGLinuxDriver
> <UNGLinuxDriver@microchip.com>
> Subject: Re: [PATCH v2 net-next 9/9] lan743x: Add PTP support
>
...
> > + 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);
>
> This is poor coding style. Please find a better way.
Can you clarify what is poor and what would be better?
For example, should I change "X != 0" to "X ? true : false".
> > +#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;
>
> So this function is really *not* implementing the PTP_CLK_REQ_PPS feature
> but rather the PTP_CLK_REQ_PEROUT with a period of once per second.
>
> PTP_CLK_REQ_PPS means placing a PPS event into the kernel's "hardpps"
> subsystem by calling ptp_clock_event().
>
> I'm sorry this isn't really documented. I should fix that.
>
> If you HW can output arbitrary signals, then you should implement
> PTP_CLK_REQ_PEROUT. In any case, you shouldn't advertise the
> ptp_clock_info.pps capability.
So you mean PPS is not intended to generate a physical signal?
It is only intended to call ptp_clock_event?
I can configure the hardware to generate an interrupt each second and then call
ptp_clock_event. Would that satisfy the pps requirements?
Regarding PTP_CLK_REQ_PEROUT. Is that intended for physical signals?
Thanks,
Bryan
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v2 net-next 6/9] lan743x: Add power management support
2018-07-12 22:42 ` Andrew Lunn
@ 2018-07-18 20:05 ` Bryan.Whitehead
0 siblings, 0 replies; 23+ messages in thread
From: Bryan.Whitehead @ 2018-07-18 20:05 UTC (permalink / raw)
To: andrew; +Cc: davem, netdev, UNGLinuxDriver, richardcochran
Hi Andrew,
Thanks for your reviews, and corrections.
I will submit a new patch series soon.
Bryan
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH v2 net-next 9/9] lan743x: Add PTP support
2018-07-18 20:04 ` Bryan.Whitehead
@ 2018-07-18 20:55 ` Richard Cochran
2018-07-18 21:05 ` Bryan.Whitehead
0 siblings, 1 reply; 23+ messages in thread
From: Richard Cochran @ 2018-07-18 20:55 UTC (permalink / raw)
To: Bryan.Whitehead; +Cc: davem, netdev, UNGLinuxDriver
On Wed, Jul 18, 2018 at 08:04:08PM +0000, Bryan.Whitehead@microchip.com wrote:
> Thank you for your detailed feedback. I'm working on it now, but I feel it will take a little extra time to complete. Therefor I'm planning to remove PTP support from this patch series, and resubmit it in a new patch later.
Ok.
> > > + 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);
> >
> > This is poor coding style. Please find a better way.
>
> Can you clarify what is poor and what would be better?
> For example, should I change "X != 0" to "X ? true : false".
Look at this:
lan743x_ptp_tx_timestamp_skb(tx->adapter,
buffer_info->skb,
(buffer_info->flags &
TX_BUFFER_INFO_FLAG_IGNORE_SYNC)
!= 0);
Can't you reduce
(buffer_info->flags & TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0
into a local variable:
lan743x_ptp_tx_timestamp_skb(tx->adapter, buffer_info->skb, xyz);
?
> So you mean PPS is not intended to generate a physical signal?
Yes.
> It is only intended to call ptp_clock_event?
Yes.
> I can configure the hardware to generate an interrupt each second and then call
> ptp_clock_event. Would that satisfy the pps requirements?
Yes.
> Regarding PTP_CLK_REQ_PEROUT. Is that intended for physical signals?
Yes.
Thanks,
Richard
^ permalink raw reply [flat|nested] 23+ messages in thread
* RE: [PATCH v2 net-next 9/9] lan743x: Add PTP support
2018-07-18 20:55 ` Richard Cochran
@ 2018-07-18 21:05 ` Bryan.Whitehead
0 siblings, 0 replies; 23+ messages in thread
From: Bryan.Whitehead @ 2018-07-18 21:05 UTC (permalink / raw)
To: richardcochran; +Cc: davem, netdev, UNGLinuxDriver
> > Can you clarify what is poor and what would be better?
> > For example, should I change "X != 0" to "X ? true : false".
>
> Look at this:
> lan743x_ptp_tx_timestamp_skb(tx->adapter,
> buffer_info->skb,
> (buffer_info->flags &
>
> TX_BUFFER_INFO_FLAG_IGNORE_SYNC)
> != 0);
>
> Can't you reduce
>
> (buffer_info->flags & TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0
>
> into a local variable:
>
> lan743x_ptp_tx_timestamp_skb(tx->adapter, buffer_info-
> >skb, xyz); ?
>
> > So you mean PPS is not intended to generate a physical signal?
>
> Yes.
>
> > It is only intended to call ptp_clock_event?
>
> Yes.
>
> > I can configure the hardware to generate an interrupt each second and
> > then call ptp_clock_event. Would that satisfy the pps requirements?
>
> Yes.
>
> > Regarding PTP_CLK_REQ_PEROUT. Is that intended for physical signals?
>
> Yes.
>
> Thanks,
> Richard
Richard,
Thank you for your quick answers.
Bryan
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2018-07-18 21:44 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-12 19:04 [PATCH v2 net-next 0/9] lan743x: Add features to lan743x driver Bryan Whitehead
2018-07-12 19:04 ` [PATCH v2 net-next 1/9] lan743x: Add support for ethtool get_drvinfo Bryan Whitehead
2018-07-12 22:28 ` Andrew Lunn
2018-07-12 19:04 ` [PATCH v2 net-next 2/9] lan743x: Add support for ethtool link settings Bryan Whitehead
2018-07-12 22:29 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 3/9] lan743x: Add support for ethtool statistics Bryan Whitehead
2018-07-12 22:31 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 4/9] lan743x: Add support for ethtool message level Bryan Whitehead
2018-07-12 22:31 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 5/9] lan743x: Add support for ethtool eeprom access Bryan Whitehead
2018-07-12 22:35 ` Andrew Lunn
2018-07-12 19:05 ` [PATCH v2 net-next 6/9] lan743x: Add power management support Bryan Whitehead
2018-07-12 22:42 ` Andrew Lunn
2018-07-18 20:05 ` Bryan.Whitehead
2018-07-12 19:05 ` [PATCH v2 net-next 7/9] lan743x: Add EEE support Bryan Whitehead
2018-07-12 22:49 ` Andrew Lunn
2018-07-13 16:35 ` Bryan.Whitehead
2018-07-12 19:05 ` [PATCH v2 net-next 8/9] lan743x: Add RSS support Bryan Whitehead
2018-07-12 19:05 ` [PATCH v2 net-next 9/9] lan743x: Add PTP support Bryan Whitehead
2018-07-13 3:31 ` Richard Cochran
2018-07-18 20:04 ` Bryan.Whitehead
2018-07-18 20:55 ` Richard Cochran
2018-07-18 21:05 ` Bryan.Whitehead
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.