* [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, ×tamp);
+
+ skb_tstamp_tx(skb, ×tamp);
+ }
+
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).