netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions.
@ 2012-12-03  3:42 Michael Chan
  2012-12-03  3:42 ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Michael Chan
  2012-12-03 18:23 ` [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions Richard Cochran
  0 siblings, 2 replies; 10+ messages in thread
From: Michael Chan @ 2012-12-03  3:42 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

From: Matt Carlson <mcarlson@broadcom.com>

This patch adds code to register/unregister the ptp clock and write
the reference clock. If a chip reset is performed, the hwclock is
reinitialized with the adjusted kernel time

Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/Kconfig |    1 +
 drivers/net/ethernet/broadcom/tg3.c   |   84 +++++++++++++++++++++++++++++++--
 drivers/net/ethernet/broadcom/tg3.h   |   60 ++++++++++++++++++++++-
 3 files changed, 137 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 4bd416b..f552673 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -102,6 +102,7 @@ config TIGON3
 	depends on PCI
 	select PHYLIB
 	select HWMON
+	select PTP_1588_CLOCK
 	---help---
 	  This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
 
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 5cc976d..38047a9 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -54,6 +54,9 @@
 #include <asm/byteorder.h>
 #include <linux/uaccess.h>
 
+#include <uapi/linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
+
 #ifdef CONFIG_SPARC
 #include <asm/idprom.h>
 #include <asm/prom.h>
@@ -5516,6 +5519,57 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
 	return err;
 }
 
+static void tg3_refclk_write(struct tg3 *tp, u64 newval)
+{
+	tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP);
+	tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff);
+	tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32);
+	tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME);
+}
+
+static const struct ptp_clock_info tg3_ptp_caps = {
+	.owner		= THIS_MODULE,
+	.name		= "",
+	.max_adj	= 0,
+	.n_alarm	= 0,
+	.n_ext_ts	= 0,
+	.n_per_out	= 0,
+	.pps		= 0,
+};
+
+static void tg3_ptp_init(struct tg3 *tp)
+{
+	if (!tg3_flag(tp, PTP_CAPABLE))
+		return;
+
+	/* Initialize the hardware clock to the system time. */
+	tg3_refclk_write(tp, ktime_to_ns(ktime_get_real()));
+	tp->ptp_adjust = 0;
+
+	tp->ptp_info = tg3_ptp_caps;
+	strncpy(tp->ptp_info.name, tp->dev->name, IFNAMSIZ);
+}
+
+static void tg3_ptp_resume(struct tg3 *tp)
+{
+	if (!tg3_flag(tp, PTP_CAPABLE))
+		return;
+
+	tg3_refclk_write(tp, ktime_to_ns(ktime_get_real()) + tp->ptp_adjust);
+	tp->ptp_adjust = 0;
+}
+
+static void tg3_ptp_fini(struct tg3 *tp)
+{
+	if (!tg3_flag(tp, PTP_CAPABLE) ||
+	    !tp->ptp_clock)
+		return;
+
+	ptp_clock_unregister(tp->ptp_clock);
+	tp->ptp_clock = NULL;
+	tp->ptp_adjust = 0;
+}
+
 static inline int tg3_irq_sync(struct tg3 *tp)
 {
 	return tp->irq_sync;
@@ -6527,6 +6581,8 @@ static inline void tg3_netif_stop(struct tg3 *tp)
 
 static inline void tg3_netif_start(struct tg3 *tp)
 {
+	tg3_ptp_resume(tp);
+
 	/* NOTE: unconditional netif_tx_wake_all_queues is only
 	 * appropriate so long as all callers are assured to
 	 * have free tx slots (such as after tg3_init_hw)
@@ -10364,7 +10420,8 @@ static void tg3_ints_fini(struct tg3 *tp)
 	tg3_flag_clear(tp, ENABLE_TSS);
 }
 
-static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq)
+static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
+		     bool init)
 {
 	struct net_device *dev = tp->dev;
 	int i, err;
@@ -10443,6 +10500,12 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq)
 	tg3_flag_set(tp, INIT_COMPLETE);
 	tg3_enable_ints(tp);
 
+	if (init)
+		tg3_ptp_init(tp);
+	else
+		tg3_ptp_resume(tp);
+
+
 	tg3_full_unlock(tp);
 
 	netif_tx_start_all_queues(dev);
@@ -10540,11 +10603,19 @@ static int tg3_open(struct net_device *dev)
 
 	tg3_full_unlock(tp);
 
-	err = tg3_start(tp, true, true);
+	err = tg3_start(tp, true, true, true);
 	if (err) {
 		tg3_frob_aux_power(tp, false);
 		pci_set_power_state(tp->pdev, PCI_D3hot);
 	}
+
+	if (tg3_flag(tp, PTP_CAPABLE)) {
+		tp->ptp_clock = ptp_clock_register(&tp->ptp_info,
+						   &tp->pdev->dev);
+		if (IS_ERR(tp->ptp_clock))
+			tp->ptp_clock = NULL;
+	}
+
 	return err;
 }
 
@@ -10552,6 +10623,8 @@ static int tg3_close(struct net_device *dev)
 {
 	struct tg3 *tp = netdev_priv(dev);
 
+	tg3_ptp_fini(tp);
+
 	tg3_stop(tp);
 
 	/* Clear stats across close / open calls */
@@ -11454,7 +11527,7 @@ static int tg3_set_channels(struct net_device *dev,
 
 	tg3_carrier_off(tp);
 
-	tg3_start(tp, true, false);
+	tg3_start(tp, true, false, false);
 
 	return 0;
 }
@@ -12507,7 +12580,6 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
 		}
 
 		tg3_full_lock(tp, irq_sync);
-
 		tg3_halt(tp, RESET_KIND_SUSPEND, 1);
 		err = tg3_nvram_lock(tp);
 		tg3_halt_cpu(tp, RX_CPU_BASE);
@@ -16598,8 +16670,8 @@ static void tg3_io_resume(struct pci_dev *pdev)
 	tg3_full_lock(tp, 0);
 	tg3_flag_set(tp, INIT_COMPLETE);
 	err = tg3_restart_hw(tp, 1);
-	tg3_full_unlock(tp);
 	if (err) {
+		tg3_full_unlock(tp);
 		netdev_err(netdev, "Cannot restart hardware after reset.\n");
 		goto done;
 	}
@@ -16610,6 +16682,8 @@ static void tg3_io_resume(struct pci_dev *pdev)
 
 	tg3_netif_start(tp);
 
+	tg3_full_unlock(tp);
+
 	tg3_phy_start(tp);
 
 done:
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 4534804..d330e81 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -772,7 +772,10 @@
 #define  SG_DIG_MAC_ACK_STATUS		 0x00000004
 #define  SG_DIG_AUTONEG_COMPLETE	 0x00000002
 #define  SG_DIG_AUTONEG_ERROR		 0x00000001
-/* 0x5b8 --> 0x600 unused */
+#define TG3_TX_TSTAMP_LSB		0x000005c0
+#define TG3_TX_TSTAMP_MSB		0x000005c4
+#define  TG3_TSTAMP_MASK		 0x7fffffffffffffff
+/* 0x5c8 --> 0x600 unused */
 #define MAC_TX_MAC_STATE_BASE		0x00000600 /* 16 bytes */
 #define MAC_RX_MAC_STATE_BASE		0x00000610 /* 20 bytes */
 /* 0x624 --> 0x670 unused */
@@ -789,7 +792,36 @@
 #define MAC_RSS_HASH_KEY_7		0x0000068c
 #define MAC_RSS_HASH_KEY_8		0x00000690
 #define MAC_RSS_HASH_KEY_9		0x00000694
-/* 0x698 --> 0x800 unused */
+/* 0x698 --> 0x6b0 unused */
+
+#define TG3_RX_TSTAMP_LSB		0x000006b0
+#define TG3_RX_TSTAMP_MSB		0x000006b4
+/* 0x6b8 --> 0x6c8 unused */
+
+#define TG3_RX_PTP_CTL			0x000006c8
+#define TG3_RX_PTP_CTL_SYNC_EVNT	0x00000001
+#define TG3_RX_PTP_CTL_DELAY_REQ	0x00000002
+#define TG3_RX_PTP_CTL_PDLAY_REQ	0x00000004
+#define TG3_RX_PTP_CTL_PDLAY_RES	0x00000008
+#define TG3_RX_PTP_CTL_ALL_V1_EVENTS	(TG3_RX_PTP_CTL_SYNC_EVNT | \
+					 TG3_RX_PTP_CTL_DELAY_REQ)
+#define TG3_RX_PTP_CTL_ALL_V2_EVENTS	(TG3_RX_PTP_CTL_SYNC_EVNT | \
+					 TG3_RX_PTP_CTL_DELAY_REQ | \
+					 TG3_RX_PTP_CTL_PDLAY_REQ | \
+					 TG3_RX_PTP_CTL_PDLAY_RES)
+#define TG3_RX_PTP_CTL_FOLLOW_UP	0x00000100
+#define TG3_RX_PTP_CTL_DELAY_RES	0x00000200
+#define TG3_RX_PTP_CTL_PDRES_FLW_UP	0x00000400
+#define TG3_RX_PTP_CTL_ANNOUNCE		0x00000800
+#define TG3_RX_PTP_CTL_SIGNALING	0x00001000
+#define TG3_RX_PTP_CTL_MANAGEMENT	0x00002000
+#define TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN	0x00800000
+#define TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN	0x01000000
+#define TG3_RX_PTP_CTL_RX_PTP_V2_EN	(TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | \
+					 TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN)
+#define TG3_RX_PTP_CTL_RX_PTP_V1_EN	0x02000000
+#define TG3_RX_PTP_CTL_HWTS_INTERLOCK	0x04000000
+/* 0x6cc --> 0x800 unused */
 
 #define MAC_TX_STATS_OCTETS		0x00000800
 #define MAC_TX_STATS_RESV1		0x00000804
@@ -1669,6 +1701,7 @@
 #define  GRC_MODE_HOST_STACKUP		0x00010000
 #define  GRC_MODE_HOST_SENDBDS		0x00020000
 #define  GRC_MODE_HTX2B_ENABLE		0x00040000
+#define  GRC_MODE_TIME_SYNC_ENABLE	0x00080000
 #define  GRC_MODE_NO_TX_PHDR_CSUM	0x00100000
 #define  GRC_MODE_NVRAM_WR_ENABLE	0x00200000
 #define  GRC_MODE_PCIE_TL_SEL		0x00000000
@@ -1771,7 +1804,17 @@
 #define GRC_VCPU_EXT_CTRL_DISABLE_WOL	 0x20000000
 #define GRC_FASTBOOT_PC			0x00006894	/* 5752, 5755, 5787 */
 
-/* 0x6c00 --> 0x7000 unused */
+#define TG3_EAV_REF_CLCK_LSB		0x00006900
+#define TG3_EAV_REF_CLCK_MSB		0x00006904
+#define TG3_EAV_REF_CLCK_CTL		0x00006908
+#define  TG3_EAV_REF_CLCK_CTL_STOP	 0x00000002
+#define  TG3_EAV_REF_CLCK_CTL_RESUME	 0x00000004
+#define TG3_EAV_REF_CLK_CORRECT_CTL	0x00006928
+#define  TG3_EAV_REF_CLK_CORRECT_EN	 (1 << 31)
+#define  TG3_EAV_REF_CLK_CORRECT_NEG	 (1 << 30)
+
+#define TG3_EAV_REF_CLK_CORRECT_MASK	0xffffff
+/* 0x690c --> 0x7000 unused */
 
 /* NVRAM Control registers */
 #define NVRAM_CMD			0x00007000
@@ -2439,6 +2482,7 @@ struct tg3_tx_buffer_desc {
 #define TXD_FLAG_IP_FRAG		0x0008
 #define TXD_FLAG_JMB_PKT		0x0008
 #define TXD_FLAG_IP_FRAG_END		0x0010
+#define TXD_FLAG_HWTSTAMP		0x0020
 #define TXD_FLAG_VLAN			0x0040
 #define TXD_FLAG_COAL_NOW		0x0080
 #define TXD_FLAG_CPU_PRE_DMA		0x0100
@@ -2480,6 +2524,9 @@ struct tg3_rx_buffer_desc {
 #define RXD_FLAG_IP_CSUM		0x1000
 #define RXD_FLAG_TCPUDP_CSUM		0x2000
 #define RXD_FLAG_IS_TCP			0x4000
+#define RXD_FLAG_PTPSTAT_MASK		0x0210
+#define RXD_FLAG_PTPSTAT_PTPV1		0x0010
+#define RXD_FLAG_PTPSTAT_PTPV2		0x0200
 
 	u32				ip_tcp_csum;
 #define RXD_IPCSUM_MASK		0xffff0000
@@ -2970,9 +3017,11 @@ enum TG3_FLAGS {
 	TG3_FLAG_USE_JUMBO_BDFLAG,
 	TG3_FLAG_L1PLLPD_EN,
 	TG3_FLAG_APE_HAS_NCSI,
+	TG3_FLAG_TX_TSTAMP_EN,
 	TG3_FLAG_4K_FIFO_LIMIT,
 	TG3_FLAG_5719_RDMA_BUG,
 	TG3_FLAG_RESET_TASK_PENDING,
+	TG3_FLAG_PTP_CAPABLE,
 	TG3_FLAG_5705_PLUS,
 	TG3_FLAG_IS_5788,
 	TG3_FLAG_5750_PLUS,
@@ -3041,6 +3090,10 @@ struct tg3 {
 	u32				coal_now;
 	u32				msg_enable;
 
+	struct ptp_clock_info		ptp_info;
+	struct ptp_clock		*ptp_clock;
+	s64				ptp_adjust;
+
 	/* begin "tx thread" cacheline section */
 	void				(*write32_tx_mbox) (struct tg3 *, u32,
 							    u32);
@@ -3108,6 +3161,7 @@ struct tg3 {
 	u32				dma_rwctrl;
 	u32				coalesce_mode;
 	u32				pwrmgmt_thresh;
+	u32				rxptpctl;
 
 	/* PCI block */
 	u32				pci_chip_rev_id;
-- 
1.7.1

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

* [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions
  2012-12-03  3:42 [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions Michael Chan
@ 2012-12-03  3:42 ` Michael Chan
  2012-12-03  3:42   ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Michael Chan
  2012-12-03 18:51   ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Richard Cochran
  2012-12-03 18:23 ` [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions Richard Cochran
  1 sibling, 2 replies; 10+ messages in thread
From: Michael Chan @ 2012-12-03  3:42 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

From: Matt Carlson <mcarlson@broadcom.com>

This patch updates the ptp_caps structure with implementation functions.
All the basic clock operations as described in
Documentation/ptp/ptp.txt are supported.

Frequency adjustment is performed using hardware with a 24 bit
accumulator and a programmable correction value. On each clk, the
correction value gets added to the accumulator and when it overflows,
the time counter is incremented/decremented and the accumulator reset.

So conversion from ppb to correction value is
	ppb * (1 << 24) / 1000000000

Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c |  125 ++++++++++++++++++++++++++++++++++-
 1 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 38047a9..a54d194 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -5519,6 +5519,14 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
 	return err;
 }
 
+
+static u64 tg3_refclk_read(struct tg3 *tp)
+{
+	u64 stamp = tr32(TG3_EAV_REF_CLCK_LSB);
+
+	return stamp | (u64) tr32(TG3_EAV_REF_CLCK_MSB) << 32;
+}
+
 static void tg3_refclk_write(struct tg3 *tp, u64 newval)
 {
 	tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP);
@@ -5527,14 +5535,127 @@ static void tg3_refclk_write(struct tg3 *tp, u64 newval)
 	tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME);
 }
 
+static inline void tg3_full_lock(struct tg3 *tp, int irq_sync);
+static inline void tg3_full_unlock(struct tg3 *tp);
+static int tg3_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+{
+	struct tg3 *tp = netdev_priv(dev);
+
+	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;
+
+	if (tp->ptp_clock)
+		info->phc_index = ptp_clock_index(tp->ptp_clock);
+	else
+		info->phc_index = -1;
+
+	info->tx_types = (1 << HWTSTAMP_TX_OFF) |
+			 (1 << HWTSTAMP_TX_ON);
+
+	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+			   (1 << HWTSTAMP_FILTER_ALL);
+	return 0;
+}
+
+static int tg3_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
+	bool neg_adj = false;
+	u32 correction = 0;
+
+	if (ppb < 0) {
+		neg_adj = true;
+		ppb = -ppb;
+	}
+
+	/* Frequency adjustment is performed using hardware with a 24 bit
+	 * accumulator and a programmable correction value. On each clk, the
+	 * correction value gets added to the accumulator and when it
+	 * overflows, the time counter is incremented/decremented.
+	 *
+	 * So conversion from ppb to correction value is
+	 *		ppb * (1 << 24) / 1000000000
+	 */
+	correction = div_u64((u64)ppb * (1 << 24), 1000000000ULL) &
+		     TG3_EAV_REF_CLK_CORRECT_MASK;
+
+	tg3_full_lock(tp, 0);
+
+	if (correction)
+		tw32(TG3_EAV_REF_CLK_CORRECT_CTL,
+		     TG3_EAV_REF_CLK_CORRECT_EN |
+		     (neg_adj ? TG3_EAV_REF_CLK_CORRECT_NEG : 0) | correction);
+	else
+		tw32(TG3_EAV_REF_CLK_CORRECT_CTL, 0);
+
+	tg3_full_unlock(tp);
+
+	return 0;
+}
+
+static int tg3_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
+	tp->ptp_adjust += delta;
+	return 0;
+}
+
+static int tg3_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+	u64 ns;
+	u32 remainder;
+	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
+
+	tg3_full_lock(tp, 0);
+	ns = tg3_refclk_read(tp);
+	tg3_full_unlock(tp);
+	ns += tp->ptp_adjust;
+
+	ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+	ts->tv_nsec = remainder;
+
+	return 0;
+}
+
+static int tg3_ptp_settime(struct ptp_clock_info *ptp,
+			   const struct timespec *ts)
+{
+	u64 ns;
+	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
+
+	ns = timespec_to_ns(ts);
+
+	tg3_full_lock(tp, 0);
+	tg3_refclk_write(tp, ns);
+	tg3_full_unlock(tp);
+	tp->ptp_adjust = 0;
+
+	return 0;
+}
+
+static int tg3_ptp_enable(struct ptp_clock_info *ptp,
+			  struct ptp_clock_request *rq, int on)
+{
+	return -EOPNOTSUPP;
+}
+
 static const struct ptp_clock_info tg3_ptp_caps = {
 	.owner		= THIS_MODULE,
 	.name		= "",
-	.max_adj	= 0,
+	.max_adj	= 250000000,
 	.n_alarm	= 0,
 	.n_ext_ts	= 0,
 	.n_per_out	= 0,
 	.pps		= 0,
+	.adjfreq	= tg3_ptp_adjfreq,
+	.adjtime	= tg3_ptp_adjtime,
+	.gettime	= tg3_ptp_gettime,
+	.settime	= tg3_ptp_settime,
+	.enable		= tg3_ptp_enable,
 };
 
 static void tg3_ptp_init(struct tg3 *tp)
@@ -12785,7 +12906,7 @@ static const struct ethtool_ops tg3_ethtool_ops = {
 	.set_rxfh_indir		= tg3_set_rxfh_indir,
 	.get_channels		= tg3_get_channels,
 	.set_channels		= tg3_set_channels,
-	.get_ts_info		= ethtool_op_get_ts_info,
+	.get_ts_info		= tg3_get_ts_info,
 };
 
 static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
-- 
1.7.1

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

* [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl
  2012-12-03  3:42 ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Michael Chan
@ 2012-12-03  3:42   ` Michael Chan
  2012-12-03  3:42     ` [PATCH 4/4 net-next] tg3: PTP - Enable the timestamping feature in hardware and fill skb tx/rx timestamps Michael Chan
  2012-12-03 19:41     ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Richard Cochran
  2012-12-03 18:51   ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Richard Cochran
  1 sibling, 2 replies; 10+ messages in thread
From: Michael Chan @ 2012-12-03  3:42 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

From: Matt Carlson <mcarlson@broadcom.com>

This patch implements the SIOCSHWTSTAMP ioctl as described in
Documentation/networking/timestamping.txt

Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c |   99 +++++++++++++++++++++++++++++++++++
 1 files changed, 99 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index a54d194..f6e956c 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -12755,6 +12755,102 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
 
 }
 
+static int tg3_hwtstamp_ioctl(struct net_device *dev,
+			      struct ifreq *ifr, int cmd)
+{
+	struct tg3 *tp = netdev_priv(dev);
+	struct hwtstamp_config stmpconf;
+
+	if (!tg3_flag(tp, PTP_CAPABLE))
+		return -EINVAL;
+
+	if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf)))
+		return -EFAULT;
+
+	if (stmpconf.flags)
+		return -EINVAL;
+
+	switch (stmpconf.tx_type) {
+	case HWTSTAMP_TX_ON:
+		tg3_flag_set(tp, TX_TSTAMP_EN);
+		break;
+	case HWTSTAMP_TX_OFF:
+		tg3_flag_clear(tp, TX_TSTAMP_EN);
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	switch (stmpconf.rx_filter) {
+	case HWTSTAMP_FILTER_NONE:
+		tp->rxptpctl = 0;
+		break;
+	case HWTSTAMP_FILTER_ALL:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V1_EN |
+			       TG3_RX_PTP_CTL_ALL_V1_EVENTS |
+			       TG3_RX_PTP_CTL_RX_PTP_V2_EN |
+			       TG3_RX_PTP_CTL_ALL_V2_EVENTS;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V1_EN |
+			       TG3_RX_PTP_CTL_ALL_V1_EVENTS;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V1_EN |
+			       TG3_RX_PTP_CTL_SYNC_EVNT;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V1_EN |
+			       TG3_RX_PTP_CTL_DELAY_REQ;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_EN |
+			       TG3_RX_PTP_CTL_ALL_V2_EVENTS;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN |
+			       TG3_RX_PTP_CTL_ALL_V2_EVENTS;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN |
+			       TG3_RX_PTP_CTL_ALL_V2_EVENTS;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_EN |
+			       TG3_RX_PTP_CTL_SYNC_EVNT;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN |
+			       TG3_RX_PTP_CTL_SYNC_EVNT;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN |
+			       TG3_RX_PTP_CTL_SYNC_EVNT;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_EN |
+			       TG3_RX_PTP_CTL_DELAY_REQ;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN |
+			       TG3_RX_PTP_CTL_DELAY_REQ;
+		break;
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+		tp->rxptpctl = TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN |
+			       TG3_RX_PTP_CTL_DELAY_REQ;
+		break;
+	default:
+		return -ERANGE;
+	}
+
+	if (netif_running(dev) && tp->rxptpctl)
+		tw32(TG3_RX_PTP_CTL,
+		     tp->rxptpctl | TG3_RX_PTP_CTL_HWTS_INTERLOCK);
+
+	return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
+		-EFAULT : 0;
+}
+
 static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
 	struct mii_ioctl_data *data = if_mii(ifr);
@@ -12805,6 +12901,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 		return err;
 
+	case SIOCSHWTSTAMP:
+		return tg3_hwtstamp_ioctl(dev, ifr, cmd);
+
 	default:
 		/* do nothing */
 		break;
-- 
1.7.1

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

* [PATCH 4/4 net-next] tg3: PTP - Enable the timestamping feature in hardware and fill skb tx/rx timestamps
  2012-12-03  3:42   ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Michael Chan
@ 2012-12-03  3:42     ` Michael Chan
  2012-12-03 19:41     ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Richard Cochran
  1 sibling, 0 replies; 10+ messages in thread
From: Michael Chan @ 2012-12-03  3:42 UTC (permalink / raw)
  To: davem; +Cc: netdev, nsujir

From: Matt Carlson <mcarlson@broadcom.com>

This patch implements the hardware timestamping as described in
Documentation/networking/timestamping.txt

Update version to 3.128.

Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
 drivers/net/ethernet/broadcom/tg3.c |   57 +++++++++++++++++++++++++++++++---
 1 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index f6e956c..b2ad1c4 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -93,10 +93,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
 
 #define DRV_MODULE_NAME		"tg3"
 #define TG3_MAJ_NUM			3
-#define TG3_MIN_NUM			127
+#define TG3_MIN_NUM			128
 #define DRV_MODULE_VERSION	\
 	__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE	"November 14, 2012"
+#define DRV_MODULE_RELDATE	"December 02, 2012"
 
 #define RESET_KIND_SHUTDOWN	0
 #define RESET_KIND_INIT		1
@@ -5658,6 +5658,14 @@ static const struct ptp_clock_info tg3_ptp_caps = {
 	.enable		= tg3_ptp_enable,
 };
 
+static void tg3_hwclock_to_timestamp(struct tg3 *tp, u64 hwclock,
+				     struct skb_shared_hwtstamps *timestamp)
+{
+	memset(timestamp, 0, sizeof(struct skb_shared_hwtstamps));
+	timestamp->hwtstamp  = ns_to_ktime((hwclock & TG3_TSTAMP_MASK) +
+					   tp->ptp_adjust);
+}
+
 static void tg3_ptp_init(struct tg3 *tp)
 {
 	if (!tg3_flag(tp, PTP_CAPABLE))
@@ -5871,6 +5879,16 @@ static void tg3_tx(struct tg3_napi *tnapi)
 			return;
 		}
 
+		if (tnapi->tx_ring[sw_idx].len_flags & TXD_FLAG_HWTSTAMP) {
+			struct skb_shared_hwtstamps timestamp;
+			u64 hwclock = tr32(TG3_TX_TSTAMP_LSB);
+			hwclock |= (u64)tr32(TG3_TX_TSTAMP_MSB) << 32;
+
+			tg3_hwclock_to_timestamp(tp, hwclock, &timestamp);
+
+			skb_tstamp_tx(skb, &timestamp);
+		}
+
 		pci_unmap_single(tp->pdev,
 				 dma_unmap_addr(ri, mapping),
 				 skb_headlen(skb),
@@ -6138,6 +6156,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 		dma_addr_t dma_addr;
 		u32 opaque_key, desc_idx, *post_ptr;
 		u8 *data;
+		u64 tstamp = 0;
 
 		desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
 		opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
@@ -6172,6 +6191,14 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 		len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) -
 		      ETH_FCS_LEN;
 
+		if ((desc->type_flags & RXD_FLAG_PTPSTAT_MASK) ==
+		     RXD_FLAG_PTPSTAT_PTPV1 ||
+		    (desc->type_flags & RXD_FLAG_PTPSTAT_MASK) ==
+		     RXD_FLAG_PTPSTAT_PTPV2) {
+			tstamp = tr32(TG3_RX_TSTAMP_LSB);
+			tstamp |= (u64)tr32(TG3_RX_TSTAMP_MSB) << 32;
+		}
+
 		if (len > TG3_RX_COPY_THRESH(tp)) {
 			int skb_size;
 			unsigned int frag_size;
@@ -6215,6 +6242,10 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 		}
 
 		skb_put(skb, len);
+		if (tstamp)
+			tg3_hwclock_to_timestamp(tp, tstamp,
+						 skb_hwtstamps(skb));
+
 		if ((tp->dev->features & NETIF_F_RXCSUM) &&
 		    (desc->type_flags & RXD_FLAG_TCPUDP_CSUM) &&
 		    (((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
@@ -7271,6 +7302,12 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		vlan = vlan_tx_tag_get(skb);
 	}
 
+	if ((unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) &&
+	    tg3_flag(tp, TX_TSTAMP_EN)) {
+		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+		base_flags |= TXD_FLAG_HWTSTAMP;
+	}
+
 	len = skb_headlen(skb);
 
 	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
@@ -9139,9 +9176,15 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 	 */
 	tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
 
-	tw32(GRC_MODE,
-	     tp->grc_mode |
-	     (GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
+	val = GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP;
+	if (tp->rxptpctl)
+		tw32(TG3_RX_PTP_CTL,
+		     tp->rxptpctl | TG3_RX_PTP_CTL_HWTS_INTERLOCK);
+
+	if (tg3_flag(tp, PTP_CAPABLE))
+		val |= GRC_MODE_TIME_SYNC_ENABLE;
+
+	tw32(GRC_MODE, tp->grc_mode | val);
 
 	/* Setup the timer prescalar register.  Clock is always 66Mhz. */
 	val = tr32(GRC_MISC_CFG);
@@ -16565,6 +16608,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
 	pci_set_drvdata(pdev, dev);
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+		tg3_flag_set(tp, PTP_CAPABLE);
+
 	if (tg3_flag(tp, 5717_PLUS)) {
 		/* Resume a low-power mode */
 		tg3_frob_aux_power(tp, false);
-- 
1.7.1

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

* Re: [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions.
  2012-12-03  3:42 [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions Michael Chan
  2012-12-03  3:42 ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Michael Chan
@ 2012-12-03 18:23 ` Richard Cochran
  2012-12-03 21:49   ` Nithin Nayak Sujir
  1 sibling, 1 reply; 10+ messages in thread
From: Richard Cochran @ 2012-12-03 18:23 UTC (permalink / raw)
  To: Michael Chan; +Cc: davem, netdev, nsujir

Please put me on CC for any PTP related patches.
I have a few comments, below.

On Sun, Dec 02, 2012 at 07:42:48PM -0800, Michael Chan wrote:
> From: Matt Carlson <mcarlson@broadcom.com>
> 
> This patch adds code to register/unregister the ptp clock and write
> the reference clock. If a chip reset is performed, the hwclock is
> reinitialized with the adjusted kernel time
> 
> Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> ---
>  drivers/net/ethernet/broadcom/Kconfig |    1 +
>  drivers/net/ethernet/broadcom/tg3.c   |   84 +++++++++++++++++++++++++++++++--
>  drivers/net/ethernet/broadcom/tg3.h   |   60 ++++++++++++++++++++++-
>  3 files changed, 137 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
> index 4bd416b..f552673 100644
> --- a/drivers/net/ethernet/broadcom/Kconfig
> +++ b/drivers/net/ethernet/broadcom/Kconfig
> @@ -102,6 +102,7 @@ config TIGON3
>  	depends on PCI
>  	select PHYLIB
>  	select HWMON
> +	select PTP_1588_CLOCK
>  	---help---
>  	  This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
>  
> diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
> index 5cc976d..38047a9 100644
> --- a/drivers/net/ethernet/broadcom/tg3.c
> +++ b/drivers/net/ethernet/broadcom/tg3.c
> @@ -54,6 +54,9 @@
>  #include <asm/byteorder.h>
>  #include <linux/uaccess.h>
>  
> +#include <uapi/linux/net_tstamp.h>
> +#include <linux/ptp_clock_kernel.h>
> +
>  #ifdef CONFIG_SPARC
>  #include <asm/idprom.h>
>  #include <asm/prom.h>
> @@ -5516,6 +5519,57 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
>  	return err;
>  }
>  
> +static void tg3_refclk_write(struct tg3 *tp, u64 newval)
> +{
> +	tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP);
> +	tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff);
> +	tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32);
> +	tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME);
> +}
> +
> +static const struct ptp_clock_info tg3_ptp_caps = {
> +	.owner		= THIS_MODULE,
> +	.name		= "",

Please use a static name here, something related to the driver, like
"tigon3 clock" perhaps. There used to be drivers doing other things
with this, but now the kernel doc from ptp_clock_kernel.h says:

  @name:      A short "friendly name" to identify the clock and to
              help distinguish PHY based devices from MAC based ones.
              The string is not meant to be a unique id.

> +	.max_adj	= 0,
> +	.n_alarm	= 0,
> +	.n_ext_ts	= 0,
> +	.n_per_out	= 0,
> +	.pps		= 0,

You have left the methods as a bunch of NULL pointers. This will not
fly, since someone might land on this commit during a bisect. In
general, every patch in a series should result in a working kernel.

> +};
> +
> +static void tg3_ptp_init(struct tg3 *tp)
> +{
> +	if (!tg3_flag(tp, PTP_CAPABLE))
> +		return;
> +
> +	/* Initialize the hardware clock to the system time. */
> +	tg3_refclk_write(tp, ktime_to_ns(ktime_get_real()));
> +	tp->ptp_adjust = 0;
> +
> +	tp->ptp_info = tg3_ptp_caps;
> +	strncpy(tp->ptp_info.name, tp->dev->name, IFNAMSIZ);
> +}
> +
> +static void tg3_ptp_resume(struct tg3 *tp)
> +{
> +	if (!tg3_flag(tp, PTP_CAPABLE))
> +		return;
> +
> +	tg3_refclk_write(tp, ktime_to_ns(ktime_get_real()) + tp->ptp_adjust);
> +	tp->ptp_adjust = 0;
> +}
> +
> +static void tg3_ptp_fini(struct tg3 *tp)
> +{
> +	if (!tg3_flag(tp, PTP_CAPABLE) ||
> +	    !tp->ptp_clock)

Overzealous line break.

> +		return;
> +
> +	ptp_clock_unregister(tp->ptp_clock);
> +	tp->ptp_clock = NULL;
> +	tp->ptp_adjust = 0;
> +}
> +
>  static inline int tg3_irq_sync(struct tg3 *tp)
>  {
>  	return tp->irq_sync;
> @@ -6527,6 +6581,8 @@ static inline void tg3_netif_stop(struct tg3 *tp)
>  
>  static inline void tg3_netif_start(struct tg3 *tp)
>  {
> +	tg3_ptp_resume(tp);
> +
>  	/* NOTE: unconditional netif_tx_wake_all_queues is only
>  	 * appropriate so long as all callers are assured to
>  	 * have free tx slots (such as after tg3_init_hw)
> @@ -10364,7 +10420,8 @@ static void tg3_ints_fini(struct tg3 *tp)
>  	tg3_flag_clear(tp, ENABLE_TSS);
>  }
>  
> -static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq)
> +static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
> +		     bool init)
>  {
>  	struct net_device *dev = tp->dev;
>  	int i, err;
> @@ -10443,6 +10500,12 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq)
>  	tg3_flag_set(tp, INIT_COMPLETE);
>  	tg3_enable_ints(tp);
>  
> +	if (init)
> +		tg3_ptp_init(tp);
> +	else
> +		tg3_ptp_resume(tp);
> +
> +
>  	tg3_full_unlock(tp);
>  
>  	netif_tx_start_all_queues(dev);
> @@ -10540,11 +10603,19 @@ static int tg3_open(struct net_device *dev)
>  
>  	tg3_full_unlock(tp);
>  
> -	err = tg3_start(tp, true, true);
> +	err = tg3_start(tp, true, true, true);
>  	if (err) {
>  		tg3_frob_aux_power(tp, false);
>  		pci_set_power_state(tp->pdev, PCI_D3hot);
>  	}
> +
> +	if (tg3_flag(tp, PTP_CAPABLE)) {
> +		tp->ptp_clock = ptp_clock_register(&tp->ptp_info,
> +						   &tp->pdev->dev);
> +		if (IS_ERR(tp->ptp_clock))
> +			tp->ptp_clock = NULL;
> +	}
> +
>  	return err;
>  }
>  
> @@ -10552,6 +10623,8 @@ static int tg3_close(struct net_device *dev)
>  {
>  	struct tg3 *tp = netdev_priv(dev);
>  
> +	tg3_ptp_fini(tp);
> +
>  	tg3_stop(tp);
>  
>  	/* Clear stats across close / open calls */
> @@ -11454,7 +11527,7 @@ static int tg3_set_channels(struct net_device *dev,
>  
>  	tg3_carrier_off(tp);
>  
> -	tg3_start(tp, true, false);
> +	tg3_start(tp, true, false, false);
>  
>  	return 0;
>  }
> @@ -12507,7 +12580,6 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
>  		}
>  
>  		tg3_full_lock(tp, irq_sync);
> -
>  		tg3_halt(tp, RESET_KIND_SUSPEND, 1);
>  		err = tg3_nvram_lock(tp);
>  		tg3_halt_cpu(tp, RX_CPU_BASE);
> @@ -16598,8 +16670,8 @@ static void tg3_io_resume(struct pci_dev *pdev)
>  	tg3_full_lock(tp, 0);
>  	tg3_flag_set(tp, INIT_COMPLETE);
>  	err = tg3_restart_hw(tp, 1);
> -	tg3_full_unlock(tp);
>  	if (err) {
> +		tg3_full_unlock(tp);

This is hunk or the next one somehow related to the PTP code?
If not, they it should go into their own patch.

>  		netdev_err(netdev, "Cannot restart hardware after reset.\n");
>  		goto done;
>  	}
> @@ -16610,6 +16682,8 @@ static void tg3_io_resume(struct pci_dev *pdev)
>  
>  	tg3_netif_start(tp);
>  
> +	tg3_full_unlock(tp);
> +
>  	tg3_phy_start(tp);
>  
>  done:

Thanks,
Richard

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

* Re: [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions
  2012-12-03  3:42 ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Michael Chan
  2012-12-03  3:42   ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Michael Chan
@ 2012-12-03 18:51   ` Richard Cochran
  2012-12-03 21:52     ` Nithin Nayak Sujir
  1 sibling, 1 reply; 10+ messages in thread
From: Richard Cochran @ 2012-12-03 18:51 UTC (permalink / raw)
  To: Michael Chan; +Cc: davem, netdev, nsujir

On Sun, Dec 02, 2012 at 07:42:49PM -0800, Michael Chan wrote:
> From: Matt Carlson <mcarlson@broadcom.com>
> 
> This patch updates the ptp_caps structure with implementation functions.
> All the basic clock operations as described in
> Documentation/ptp/ptp.txt are supported.
> 
> Frequency adjustment is performed using hardware with a 24 bit
> accumulator and a programmable correction value. On each clk, the
> correction value gets added to the accumulator and when it overflows,
> the time counter is incremented/decremented and the accumulator reset.
> 
> So conversion from ppb to correction value is
> 	ppb * (1 << 24) / 1000000000

Are you sure about this? I don't know your hardware, but the others
ones with an addend and an accumulator work differently. Usually there
is a default addend based on the frequency ratio between the input
clock and the divided nominal clock. Then the ppb is applied to the
default addend.

For example, see how tmr_add is calculated in 

   Documentation/devicetree/bindings/net/fsl-tsec-phy.txt

> 
> Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> ---
>  drivers/net/ethernet/broadcom/tg3.c |  125 ++++++++++++++++++++++++++++++++++-
>  1 files changed, 123 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
> index 38047a9..a54d194 100644
> --- a/drivers/net/ethernet/broadcom/tg3.c
> +++ b/drivers/net/ethernet/broadcom/tg3.c
> @@ -5519,6 +5519,14 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
>  	return err;
>  }
>  
> +
> +static u64 tg3_refclk_read(struct tg3 *tp)
> +{
> +	u64 stamp = tr32(TG3_EAV_REF_CLCK_LSB);
> +
> +	return stamp | (u64) tr32(TG3_EAV_REF_CLCK_MSB) << 32;
> +}
> +
>  static void tg3_refclk_write(struct tg3 *tp, u64 newval)
>  {
>  	tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP);
> @@ -5527,14 +5535,127 @@ static void tg3_refclk_write(struct tg3 *tp, u64 newval)
>  	tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME);
>  }
>  
> +static inline void tg3_full_lock(struct tg3 *tp, int irq_sync);
> +static inline void tg3_full_unlock(struct tg3 *tp);
> +static int tg3_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
> +{
> +	struct tg3 *tp = netdev_priv(dev);
> +
> +	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;
> +
> +	if (tp->ptp_clock)
> +		info->phc_index = ptp_clock_index(tp->ptp_clock);
> +	else
> +		info->phc_index = -1;
> +
> +	info->tx_types = (1 << HWTSTAMP_TX_OFF) |
> +			 (1 << HWTSTAMP_TX_ON);
> +
> +	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
> +			   (1 << HWTSTAMP_FILTER_ALL);
> +	return 0;
> +}
> +
> +static int tg3_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
> +{
> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
> +	bool neg_adj = false;
> +	u32 correction = 0;
> +
> +	if (ppb < 0) {
> +		neg_adj = true;
> +		ppb = -ppb;
> +	}
> +
> +	/* Frequency adjustment is performed using hardware with a 24 bit
> +	 * accumulator and a programmable correction value. On each clk, the
> +	 * correction value gets added to the accumulator and when it
> +	 * overflows, the time counter is incremented/decremented.
> +	 *
> +	 * So conversion from ppb to correction value is
> +	 *		ppb * (1 << 24) / 1000000000
> +	 */
> +	correction = div_u64((u64)ppb * (1 << 24), 1000000000ULL) &
> +		     TG3_EAV_REF_CLK_CORRECT_MASK;
> +
> +	tg3_full_lock(tp, 0);
> +
> +	if (correction)
> +		tw32(TG3_EAV_REF_CLK_CORRECT_CTL,
> +		     TG3_EAV_REF_CLK_CORRECT_EN |
> +		     (neg_adj ? TG3_EAV_REF_CLK_CORRECT_NEG : 0) | correction);
> +	else
> +		tw32(TG3_EAV_REF_CLK_CORRECT_CTL, 0);
> +
> +	tg3_full_unlock(tp);
> +
> +	return 0;
> +}
> +
> +static int tg3_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
> +{
> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
> +	tp->ptp_adjust += delta;

This 'ptp_adjust' should be placed under the lock. This races with the
reader method.

> +	return 0;
> +}
> +
> +static int tg3_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
> +{
> +	u64 ns;
> +	u32 remainder;
> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
> +
> +	tg3_full_lock(tp, 0);
> +	ns = tg3_refclk_read(tp);
> +	tg3_full_unlock(tp);
> +	ns += tp->ptp_adjust;
> +
> +	ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
> +	ts->tv_nsec = remainder;
> +
> +	return 0;
> +}
> +
> +static int tg3_ptp_settime(struct ptp_clock_info *ptp,
> +			   const struct timespec *ts)
> +{
> +	u64 ns;
> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
> +
> +	ns = timespec_to_ns(ts);
> +
> +	tg3_full_lock(tp, 0);
> +	tg3_refclk_write(tp, ns);
> +	tg3_full_unlock(tp);
> +	tp->ptp_adjust = 0;
> +
> +	return 0;
> +}
> +
> +static int tg3_ptp_enable(struct ptp_clock_info *ptp,
> +			  struct ptp_clock_request *rq, int on)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
>  static const struct ptp_clock_info tg3_ptp_caps = {
>  	.owner		= THIS_MODULE,
>  	.name		= "",
> -	.max_adj	= 0,
> +	.max_adj	= 250000000,
>  	.n_alarm	= 0,
>  	.n_ext_ts	= 0,
>  	.n_per_out	= 0,
>  	.pps		= 0,
> +	.adjfreq	= tg3_ptp_adjfreq,
> +	.adjtime	= tg3_ptp_adjtime,
> +	.gettime	= tg3_ptp_gettime,
> +	.settime	= tg3_ptp_settime,
> +	.enable		= tg3_ptp_enable,

These are missing from patch #1.

>  };
>  
>  static void tg3_ptp_init(struct tg3 *tp)

Thanks,
Richard

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

* Re: [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl
  2012-12-03  3:42   ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Michael Chan
  2012-12-03  3:42     ` [PATCH 4/4 net-next] tg3: PTP - Enable the timestamping feature in hardware and fill skb tx/rx timestamps Michael Chan
@ 2012-12-03 19:41     ` Richard Cochran
  1 sibling, 0 replies; 10+ messages in thread
From: Richard Cochran @ 2012-12-03 19:41 UTC (permalink / raw)
  To: Michael Chan; +Cc: davem, netdev, nsujir

On Sun, Dec 02, 2012 at 07:42:50PM -0800, Michael Chan wrote:
> From: Matt Carlson <mcarlson@broadcom.com>
> 
> This patch implements the SIOCSHWTSTAMP ioctl as described in
> Documentation/networking/timestamping.txt
> 
> Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> ---
>  drivers/net/ethernet/broadcom/tg3.c |   99 +++++++++++++++++++++++++++++++++++
>  1 files changed, 99 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
> index a54d194..f6e956c 100644
> --- a/drivers/net/ethernet/broadcom/tg3.c
> +++ b/drivers/net/ethernet/broadcom/tg3.c
> @@ -12755,6 +12755,102 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
>  
>  }
>  
> +static int tg3_hwtstamp_ioctl(struct net_device *dev,
> +			      struct ifreq *ifr, int cmd)
> +{
> +	struct tg3 *tp = netdev_priv(dev);
> +	struct hwtstamp_config stmpconf;
> +
> +	if (!tg3_flag(tp, PTP_CAPABLE))
> +		return -EINVAL;
> +
> +	if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf)))
> +		return -EFAULT;
> +
> +	if (stmpconf.flags)
> +		return -EINVAL;
> +
> +	switch (stmpconf.tx_type) {
> +	case HWTSTAMP_TX_ON:
> +		tg3_flag_set(tp, TX_TSTAMP_EN);
> +		break;
> +	case HWTSTAMP_TX_OFF:
> +		tg3_flag_clear(tp, TX_TSTAMP_EN);
> +		break;
> +	default:
> +		return -ERANGE;
> +	}
> +
> +	switch (stmpconf.rx_filter) {
> +	case HWTSTAMP_FILTER_NONE:
> +		tp->rxptpctl = 0;
> +		break;
> +	case HWTSTAMP_FILTER_ALL:

This filter code means that all packets are stamped, not just all PTP
packets. I guess that you should return ERANGE here.

Thanks,
Richard

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

* Re: [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions.
  2012-12-03 18:23 ` [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions Richard Cochran
@ 2012-12-03 21:49   ` Nithin Nayak Sujir
  0 siblings, 0 replies; 10+ messages in thread
From: Nithin Nayak Sujir @ 2012-12-03 21:49 UTC (permalink / raw)
  To: Richard Cochran; +Cc: Michael Chan, davem, netdev

Hi Richard,
Thanks for your comments.

On 12/03/2012 10:23 AM, Richard Cochran wrote:
> Please put me on CC for any PTP related patches.
> I have a few comments, below.
>
> On Sun, Dec 02, 2012 at 07:42:48PM -0800, Michael Chan wrote:
>> From: Matt Carlson <mcarlson@broadcom.com>
>>
>> This patch adds code to register/unregister the ptp clock and write
>> the reference clock. If a chip reset is performed, the hwclock is
>> reinitialized with the adjusted kernel time
>>
>> Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
>> Signed-off-by: Michael Chan <mchan@broadcom.com>
>> ---
>>   drivers/net/ethernet/broadcom/Kconfig |    1 +
>>   drivers/net/ethernet/broadcom/tg3.c   |   84 +++++++++++++++++++++++++++++++--
>>   drivers/net/ethernet/broadcom/tg3.h   |   60 ++++++++++++++++++++++-
>>   3 files changed, 137 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
>> index 4bd416b..f552673 100644
>> --- a/drivers/net/ethernet/broadcom/Kconfig
>> +++ b/drivers/net/ethernet/broadcom/Kconfig
>> @@ -102,6 +102,7 @@ config TIGON3
>>   	depends on PCI
>>   	select PHYLIB
>>   	select HWMON
>> +	select PTP_1588_CLOCK
>>   	---help---
>>   	  This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
>>   
>> diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
>> index 5cc976d..38047a9 100644
>> --- a/drivers/net/ethernet/broadcom/tg3.c
>> +++ b/drivers/net/ethernet/broadcom/tg3.c
>> @@ -54,6 +54,9 @@
>>   #include <asm/byteorder.h>
>>   #include <linux/uaccess.h>
>>   
>> +#include <uapi/linux/net_tstamp.h>
>> +#include <linux/ptp_clock_kernel.h>
>> +
>>   #ifdef CONFIG_SPARC
>>   #include <asm/idprom.h>
>>   #include <asm/prom.h>
>> @@ -5516,6 +5519,57 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
>>   	return err;
>>   }
>>   
>> +static void tg3_refclk_write(struct tg3 *tp, u64 newval)
>> +{
>> +	tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP);
>> +	tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff);
>> +	tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32);
>> +	tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME);
>> +}
>> +
>> +static const struct ptp_clock_info tg3_ptp_caps = {
>> +	.owner		= THIS_MODULE,
>> +	.name		= "",
> Please use a static name here, something related to the driver, like
> "tigon3 clock" perhaps. There used to be drivers doing other things
> with this, but now the kernel doc from ptp_clock_kernel.h says:
>
>    @name:      A short "friendly name" to identify the clock and to
>                help distinguish PHY based devices from MAC based ones.
>                The string is not meant to be a unique id.
>
>> +	.max_adj	= 0,
>> +	.n_alarm	= 0,
>> +	.n_ext_ts	= 0,
>> +	.n_per_out	= 0,
>> +	.pps		= 0,
> You have left the methods as a bunch of NULL pointers. This will not
> fly, since someone might land on this commit during a bisect. In
> general, every patch in a series should result in a working kernel.
>
>> +};
>> +
>> +static void tg3_ptp_init(struct tg3 *tp)
>> +{
>> +	if (!tg3_flag(tp, PTP_CAPABLE))
>> +		return;
>> +
>> +	/* Initialize the hardware clock to the system time. */
>> +	tg3_refclk_write(tp, ktime_to_ns(ktime_get_real()));
>> +	tp->ptp_adjust = 0;
>> +
>> +	tp->ptp_info = tg3_ptp_caps;
>> +	strncpy(tp->ptp_info.name, tp->dev->name, IFNAMSIZ);
>> +}
>> +
>> +static void tg3_ptp_resume(struct tg3 *tp)
>> +{
>> +	if (!tg3_flag(tp, PTP_CAPABLE))
>> +		return;
>> +
>> +	tg3_refclk_write(tp, ktime_to_ns(ktime_get_real()) + tp->ptp_adjust);
>> +	tp->ptp_adjust = 0;
>> +}
>> +
>> +static void tg3_ptp_fini(struct tg3 *tp)
>> +{
>> +	if (!tg3_flag(tp, PTP_CAPABLE) ||
>> +	    !tp->ptp_clock)
> Overzealous line break.
>
>> +		return;
>> +
>> +	ptp_clock_unregister(tp->ptp_clock);
>> +	tp->ptp_clock = NULL;
>> +	tp->ptp_adjust = 0;
>> +}
>> +
>>   static inline int tg3_irq_sync(struct tg3 *tp)
>>   {
>>   	return tp->irq_sync;
>> @@ -6527,6 +6581,8 @@ static inline void tg3_netif_stop(struct tg3 *tp)
>>   
>>   static inline void tg3_netif_start(struct tg3 *tp)
>>   {
>> +	tg3_ptp_resume(tp);
>> +
>>   	/* NOTE: unconditional netif_tx_wake_all_queues is only
>>   	 * appropriate so long as all callers are assured to
>>   	 * have free tx slots (such as after tg3_init_hw)
>> @@ -10364,7 +10420,8 @@ static void tg3_ints_fini(struct tg3 *tp)
>>   	tg3_flag_clear(tp, ENABLE_TSS);
>>   }
>>   
>> -static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq)
>> +static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
>> +		     bool init)
>>   {
>>   	struct net_device *dev = tp->dev;
>>   	int i, err;
>> @@ -10443,6 +10500,12 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq)
>>   	tg3_flag_set(tp, INIT_COMPLETE);
>>   	tg3_enable_ints(tp);
>>   
>> +	if (init)
>> +		tg3_ptp_init(tp);
>> +	else
>> +		tg3_ptp_resume(tp);
>> +
>> +
>>   	tg3_full_unlock(tp);
>>   
>>   	netif_tx_start_all_queues(dev);
>> @@ -10540,11 +10603,19 @@ static int tg3_open(struct net_device *dev)
>>   
>>   	tg3_full_unlock(tp);
>>   
>> -	err = tg3_start(tp, true, true);
>> +	err = tg3_start(tp, true, true, true);
>>   	if (err) {
>>   		tg3_frob_aux_power(tp, false);
>>   		pci_set_power_state(tp->pdev, PCI_D3hot);
>>   	}
>> +
>> +	if (tg3_flag(tp, PTP_CAPABLE)) {
>> +		tp->ptp_clock = ptp_clock_register(&tp->ptp_info,
>> +						   &tp->pdev->dev);
>> +		if (IS_ERR(tp->ptp_clock))
>> +			tp->ptp_clock = NULL;
>> +	}
>> +
>>   	return err;
>>   }
>>   
>> @@ -10552,6 +10623,8 @@ static int tg3_close(struct net_device *dev)
>>   {
>>   	struct tg3 *tp = netdev_priv(dev);
>>   
>> +	tg3_ptp_fini(tp);
>> +
>>   	tg3_stop(tp);
>>   
>>   	/* Clear stats across close / open calls */
>> @@ -11454,7 +11527,7 @@ static int tg3_set_channels(struct net_device *dev,
>>   
>>   	tg3_carrier_off(tp);
>>   
>> -	tg3_start(tp, true, false);
>> +	tg3_start(tp, true, false, false);
>>   
>>   	return 0;
>>   }
>> @@ -12507,7 +12580,6 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
>>   		}
>>   
>>   		tg3_full_lock(tp, irq_sync);
>> -
>>   		tg3_halt(tp, RESET_KIND_SUSPEND, 1);
>>   		err = tg3_nvram_lock(tp);
>>   		tg3_halt_cpu(tp, RX_CPU_BASE);
>> @@ -16598,8 +16670,8 @@ static void tg3_io_resume(struct pci_dev *pdev)
>>   	tg3_full_lock(tp, 0);
>>   	tg3_flag_set(tp, INIT_COMPLETE);
>>   	err = tg3_restart_hw(tp, 1);
>> -	tg3_full_unlock(tp);
>>   	if (err) {
>> +		tg3_full_unlock(tp);
> This is hunk or the next one somehow related to the PTP code?
> If not, they it should go into their own patch.
>

Yes, they are related. tg3_netif_start() now calls tg3_ptp_resume() to 
reinitialize the hwclock after a chip reset. This should be inside a 
full_lock(). This hunk moves the tg3_full_unlock() below tg3_netif_start(). It 
also brings netif_device_attach() and tg3_timer_start() inside the lock() but 
this seems to be ok since other places already do that.

I will fix the other comments in v2.



>>   		netdev_err(netdev, "Cannot restart hardware after reset.\n");
>>   		goto done;
>>   	}
>> @@ -16610,6 +16682,8 @@ static void tg3_io_resume(struct pci_dev *pdev)
>>   
>>   	tg3_netif_start(tp);
>>   
>> +	tg3_full_unlock(tp);
>> +
>>   	tg3_phy_start(tp);
>>   
>>   done:
> Thanks,
> Richard
>

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

* Re: [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions
  2012-12-03 18:51   ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Richard Cochran
@ 2012-12-03 21:52     ` Nithin Nayak Sujir
  2012-12-04  7:53       ` Richard Cochran
  0 siblings, 1 reply; 10+ messages in thread
From: Nithin Nayak Sujir @ 2012-12-03 21:52 UTC (permalink / raw)
  To: Richard Cochran; +Cc: Michael Chan, davem, netdev


On 12/03/2012 10:51 AM, Richard Cochran wrote:
> On Sun, Dec 02, 2012 at 07:42:49PM -0800, Michael Chan wrote:
>> From: Matt Carlson <mcarlson@broadcom.com>
>>
>> This patch updates the ptp_caps structure with implementation functions.
>> All the basic clock operations as described in
>> Documentation/ptp/ptp.txt are supported.
>>
>> Frequency adjustment is performed using hardware with a 24 bit
>> accumulator and a programmable correction value. On each clk, the
>> correction value gets added to the accumulator and when it overflows,
>> the time counter is incremented/decremented and the accumulator reset.
>>
>> So conversion from ppb to correction value is
>> 	ppb * (1 << 24) / 1000000000
> Are you sure about this? I don't know your hardware, but the others
> ones with an addend and an accumulator work differently. Usually there
> is a default addend based on the frequency ratio between the input
> clock and the divided nominal clock. Then the ppb is applied to the
> default addend.
>
> For example, see how tmr_add is calculated in
>
>     Documentation/devicetree/bindings/net/fsl-tsec-phy.txt

Yes, the hardware does seem to be different from what you describe but I think 
the conversion is right. I tested this with ptp4l in a back-to-back 
configuration and observed convergence of the master offset to ~0. Without this 
code, the offset keeps increasing.



>
>> Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
>> Signed-off-by: Michael Chan <mchan@broadcom.com>
>> ---
>>   drivers/net/ethernet/broadcom/tg3.c |  125 ++++++++++++++++++++++++++++++++++-
>>   1 files changed, 123 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
>> index 38047a9..a54d194 100644
>> --- a/drivers/net/ethernet/broadcom/tg3.c
>> +++ b/drivers/net/ethernet/broadcom/tg3.c
>> @@ -5519,6 +5519,14 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
>>   	return err;
>>   }
>>   
>> +
>> +static u64 tg3_refclk_read(struct tg3 *tp)
>> +{
>> +	u64 stamp = tr32(TG3_EAV_REF_CLCK_LSB);
>> +
>> +	return stamp | (u64) tr32(TG3_EAV_REF_CLCK_MSB) << 32;
>> +}
>> +
>>   static void tg3_refclk_write(struct tg3 *tp, u64 newval)
>>   {
>>   	tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP);
>> @@ -5527,14 +5535,127 @@ static void tg3_refclk_write(struct tg3 *tp, u64 newval)
>>   	tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME);
>>   }
>>   
>> +static inline void tg3_full_lock(struct tg3 *tp, int irq_sync);
>> +static inline void tg3_full_unlock(struct tg3 *tp);
>> +static int tg3_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
>> +{
>> +	struct tg3 *tp = netdev_priv(dev);
>> +
>> +	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;
>> +
>> +	if (tp->ptp_clock)
>> +		info->phc_index = ptp_clock_index(tp->ptp_clock);
>> +	else
>> +		info->phc_index = -1;
>> +
>> +	info->tx_types = (1 << HWTSTAMP_TX_OFF) |
>> +			 (1 << HWTSTAMP_TX_ON);
>> +
>> +	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
>> +			   (1 << HWTSTAMP_FILTER_ALL);
>> +	return 0;
>> +}
>> +
>> +static int tg3_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
>> +{
>> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
>> +	bool neg_adj = false;
>> +	u32 correction = 0;
>> +
>> +	if (ppb < 0) {
>> +		neg_adj = true;
>> +		ppb = -ppb;
>> +	}
>> +
>> +	/* Frequency adjustment is performed using hardware with a 24 bit
>> +	 * accumulator and a programmable correction value. On each clk, the
>> +	 * correction value gets added to the accumulator and when it
>> +	 * overflows, the time counter is incremented/decremented.
>> +	 *
>> +	 * So conversion from ppb to correction value is
>> +	 *		ppb * (1 << 24) / 1000000000
>> +	 */
>> +	correction = div_u64((u64)ppb * (1 << 24), 1000000000ULL) &
>> +		     TG3_EAV_REF_CLK_CORRECT_MASK;
>> +
>> +	tg3_full_lock(tp, 0);
>> +
>> +	if (correction)
>> +		tw32(TG3_EAV_REF_CLK_CORRECT_CTL,
>> +		     TG3_EAV_REF_CLK_CORRECT_EN |
>> +		     (neg_adj ? TG3_EAV_REF_CLK_CORRECT_NEG : 0) | correction);
>> +	else
>> +		tw32(TG3_EAV_REF_CLK_CORRECT_CTL, 0);
>> +
>> +	tg3_full_unlock(tp);
>> +
>> +	return 0;
>> +}
>> +
>> +static int tg3_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
>> +{
>> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
>> +	tp->ptp_adjust += delta;
> This 'ptp_adjust' should be placed under the lock. This races with the
> reader method.
>
>> +	return 0;
>> +}
>> +
>> +static int tg3_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
>> +{
>> +	u64 ns;
>> +	u32 remainder;
>> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
>> +
>> +	tg3_full_lock(tp, 0);
>> +	ns = tg3_refclk_read(tp);
>> +	tg3_full_unlock(tp);
>> +	ns += tp->ptp_adjust;
>> +
>> +	ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
>> +	ts->tv_nsec = remainder;
>> +
>> +	return 0;
>> +}
>> +
>> +static int tg3_ptp_settime(struct ptp_clock_info *ptp,
>> +			   const struct timespec *ts)
>> +{
>> +	u64 ns;
>> +	struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
>> +
>> +	ns = timespec_to_ns(ts);
>> +
>> +	tg3_full_lock(tp, 0);
>> +	tg3_refclk_write(tp, ns);
>> +	tg3_full_unlock(tp);
>> +	tp->ptp_adjust = 0;
>> +
>> +	return 0;
>> +}
>> +
>> +static int tg3_ptp_enable(struct ptp_clock_info *ptp,
>> +			  struct ptp_clock_request *rq, int on)
>> +{
>> +	return -EOPNOTSUPP;
>> +}
>> +
>>   static const struct ptp_clock_info tg3_ptp_caps = {
>>   	.owner		= THIS_MODULE,
>>   	.name		= "",
>> -	.max_adj	= 0,
>> +	.max_adj	= 250000000,
>>   	.n_alarm	= 0,
>>   	.n_ext_ts	= 0,
>>   	.n_per_out	= 0,
>>   	.pps		= 0,
>> +	.adjfreq	= tg3_ptp_adjfreq,
>> +	.adjtime	= tg3_ptp_adjtime,
>> +	.gettime	= tg3_ptp_gettime,
>> +	.settime	= tg3_ptp_settime,
>> +	.enable		= tg3_ptp_enable,
> These are missing from patch #1.
>
>>   };
>>   
>>   static void tg3_ptp_init(struct tg3 *tp)
> Thanks,
> Richard
>

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

* Re: [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions
  2012-12-03 21:52     ` Nithin Nayak Sujir
@ 2012-12-04  7:53       ` Richard Cochran
  0 siblings, 0 replies; 10+ messages in thread
From: Richard Cochran @ 2012-12-04  7:53 UTC (permalink / raw)
  To: Nithin Nayak Sujir; +Cc: Michael Chan, davem, netdev

On Mon, Dec 03, 2012 at 01:52:16PM -0800, Nithin Nayak Sujir wrote:
> 
> Yes, the hardware does seem to be different from what you describe
> but I think the conversion is right. I tested this with ptp4l in a
> back-to-back configuration and observed convergence of the master
> offset to ~0. Without this code, the offset keeps increasing.

Okay, thanks, just asking.

It appears that this works just like the IGB. The register value is a
binary fraction of the increment value, and not an addend as I
assumed.

Thanks,
Richard

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

end of thread, other threads:[~2012-12-04  7:53 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-03  3:42 [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions Michael Chan
2012-12-03  3:42 ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Michael Chan
2012-12-03  3:42   ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Michael Chan
2012-12-03  3:42     ` [PATCH 4/4 net-next] tg3: PTP - Enable the timestamping feature in hardware and fill skb tx/rx timestamps Michael Chan
2012-12-03 19:41     ` [PATCH 3/4 net-next] tg3: PTP - Add the hardware timestamp ioctl Richard Cochran
2012-12-03 18:51   ` [PATCH 2/4 net-next] tg3: PTP - Implement the ptp api and ethtool functions Richard Cochran
2012-12-03 21:52     ` Nithin Nayak Sujir
2012-12-04  7:53       ` Richard Cochran
2012-12-03 18:23 ` [PATCH 1/4 net-next] tg3: PTP - Add header definitions, initialization and hw access functions Richard Cochran
2012-12-03 21:49   ` Nithin Nayak Sujir

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).