aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRayagond Kokatanur <rayagond@vayavyalabs.com>2013-03-26 00:43:10 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-26 12:53:37 -0400
commit891434b18ec0a21cfa4788695165b74e8d4c0474 (patch)
tree1b052da23d5f4b86efdf0cf45330bf64958e9b62
parentcf32deec16e4e8d47305bdc638fd108c88e06081 (diff)
stmmac: add IEEE PTPv1 and PTPv2 support.
This patch enhances the stmmac driver to support IEEE 1588-2002 PTP (Precision Time Protocol) version 1 and IEEE 1588-2008 PPT version 2. Precision Time Protocol(PTP),which enables precise synchronization of clocks in measurement and control systems implemented with technologies such as network communication,local computing, & distributed objects. Both PTPv1 and PTPv2 is selected at run-time using the HW capability register. The PTPv1 TimeStamp support can be used on chips that have the normal descriptor structures and PTPv2 TimeStamp support can be used on chips that have the Extended descriptors(DES4-5-6-7). All such sanity checks are done and verified by using HW capability register. V2: in this version the ethtool support has been included in this patch; Koptions have been completely removed (previously added to select PTP and PTPv2). PTPv1 and PTPv2 is now added in a single patch instead of two patches. get_timestamp() and get_systemtime() L/H have been combined into single APIs. Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com> Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Cc: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/chain_mode.c32
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c47
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c37
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/ring_mode.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c32
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c108
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c384
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h74
11 files changed, 732 insertions, 24 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ae995a367c91..1aca0e6881bd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -4,4 +4,4 @@ stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
4stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ 4stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
5 chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ 5 chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
6 dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ 6 dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
7 mmc_core.o $(stmmac-y) 7 mmc_core.o stmmac_hwtstamp.o $(stmmac-y)
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 63b6031e304a..37a3f93b487d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -122,8 +122,40 @@ static void stmmac_init_dma_chain(void *des, dma_addr_t phy_addr,
122 } 122 }
123} 123}
124 124
125static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
126{
127 struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
128
129 if (priv->hwts_rx_en && !priv->extend_desc)
130 /* NOTE: Device will overwrite des3 with timestamp value if
131 * 1588-2002 time stamping is enabled, hence reinitialize it
132 * to keep explicit chaining in the descriptor.
133 */
134 p->des3 = (unsigned int)(priv->dma_rx_phy +
135 (((priv->dirty_rx) + 1) %
136 priv->dma_rx_size) *
137 sizeof(struct dma_desc));
138}
139
140static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
141{
142 struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
143
144 if (priv->hw->desc->get_tx_ls(p) && !priv->extend_desc)
145 /* NOTE: Device will overwrite des3 with timestamp value if
146 * 1588-2002 time stamping is enabled, hence reinitialize it
147 * to keep explicit chaining in the descriptor.
148 */
149 p->des3 = (unsigned int)(priv->dma_tx_phy +
150 (((priv->dirty_tx + 1) %
151 priv->dma_tx_size) *
152 sizeof(struct dma_desc)));
153}
154
125const struct stmmac_chain_mode_ops chain_mode_ops = { 155const struct stmmac_chain_mode_ops chain_mode_ops = {
126 .init = stmmac_init_dma_chain, 156 .init = stmmac_init_dma_chain,
127 .is_jumbo_frm = stmmac_is_jumbo_frm, 157 .is_jumbo_frm = stmmac_is_jumbo_frm,
128 .jumbo_frm = stmmac_jumbo_frm, 158 .jumbo_frm = stmmac_jumbo_frm,
159 .refill_desc3 = stmmac_refill_desc3,
160 .clean_desc3 = stmmac_clean_desc3,
129}; 161};
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 942fdce3ab93..6fa975c55234 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -339,6 +339,14 @@ struct stmmac_desc_ops {
339 struct dma_desc *p); 339 struct dma_desc *p);
340 void (*rx_extended_status) (void *data, struct stmmac_extra_stats *x, 340 void (*rx_extended_status) (void *data, struct stmmac_extra_stats *x,
341 struct dma_extended_desc *p); 341 struct dma_extended_desc *p);
342 /* Set tx timestamp enable bit */
343 void (*enable_tx_timestamp) (struct dma_desc *p);
344 /* get tx timestamp status */
345 int (*get_tx_timestamp_status) (struct dma_desc *p);
346 /* get timestamp value */
347 u64 (*get_timestamp) (void *desc, u32 ats);
348 /* get rx timestamp status */
349 int (*get_rx_timestamp_status) (void *desc, u32 ats);
342}; 350};
343 351
344struct stmmac_dma_ops { 352struct stmmac_dma_ops {
@@ -398,6 +406,13 @@ struct stmmac_ops {
398 void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv); 406 void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv);
399}; 407};
400 408
409struct stmmac_hwtimestamp {
410 void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
411 void (*config_sub_second_increment) (void __iomem *ioaddr);
412 int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
413 int (*config_addend)(void __iomem *ioaddr, u32 addend);
414};
415
401struct mac_link { 416struct mac_link {
402 int port; 417 int port;
403 int duplex; 418 int duplex;
@@ -412,9 +427,9 @@ struct mii_regs {
412struct stmmac_ring_mode_ops { 427struct stmmac_ring_mode_ops {
413 unsigned int (*is_jumbo_frm) (int len, int ehn_desc); 428 unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
414 unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum); 429 unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
415 void (*refill_desc3) (int bfsize, struct dma_desc *p); 430 void (*refill_desc3) (void *priv, struct dma_desc *p);
416 void (*init_desc3) (struct dma_desc *p); 431 void (*init_desc3) (struct dma_desc *p);
417 void (*clean_desc3) (struct dma_desc *p); 432 void (*clean_desc3) (void *priv, struct dma_desc *p);
418 int (*set_16kib_bfsize) (int mtu); 433 int (*set_16kib_bfsize) (int mtu);
419}; 434};
420 435
@@ -423,6 +438,8 @@ struct stmmac_chain_mode_ops {
423 unsigned int extend_desc); 438 unsigned int extend_desc);
424 unsigned int (*is_jumbo_frm) (int len, int ehn_desc); 439 unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
425 unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum); 440 unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
441 void (*refill_desc3) (void *priv, struct dma_desc *p);
442 void (*clean_desc3) (void *priv, struct dma_desc *p);
426}; 443};
427 444
428struct mac_device_info { 445struct mac_device_info {
@@ -431,6 +448,7 @@ struct mac_device_info {
431 const struct stmmac_dma_ops *dma; 448 const struct stmmac_dma_ops *dma;
432 const struct stmmac_ring_mode_ops *ring; 449 const struct stmmac_ring_mode_ops *ring;
433 const struct stmmac_chain_mode_ops *chain; 450 const struct stmmac_chain_mode_ops *chain;
451 const struct stmmac_hwtimestamp *ptp;
434 struct mii_regs mii; /* MII register Addresses */ 452 struct mii_regs mii; /* MII register Addresses */
435 struct mac_link link; 453 struct mac_link link;
436 unsigned int synopsys_uid; 454 unsigned int synopsys_uid;
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index c1b9ab23b3c5..0fbc8fafa706 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -378,6 +378,49 @@ static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
378 return p->des01.erx.frame_length; 378 return p->des01.erx.frame_length;
379} 379}
380 380
381static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
382{
383 p->des01.etx.time_stamp_enable = 1;
384}
385
386static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
387{
388 return p->des01.etx.time_stamp_status;
389}
390
391static u64 enh_desc_get_timestamp(void *desc, u32 ats)
392{
393 u64 ns;
394
395 if (ats) {
396 struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
397 ns = p->des6;
398 /* convert high/sec time stamp value to nanosecond */
399 ns += p->des7 * 1000000000ULL;
400 } else {
401 struct dma_desc *p = (struct dma_desc *)desc;
402 ns = p->des2;
403 ns += p->des3 * 1000000000ULL;
404 }
405
406 return ns;
407}
408
409static int enh_desc_get_rx_timestamp_status(void *desc, u32 ats)
410{
411 if (ats) {
412 struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
413 return p->basic.des01.erx.ipc_csum_error;
414 } else {
415 struct dma_desc *p = (struct dma_desc *)desc;
416 if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
417 /* timestamp is corrupted, hence don't store it */
418 return 0;
419 else
420 return 1;
421 }
422}
423
381const struct stmmac_desc_ops enh_desc_ops = { 424const struct stmmac_desc_ops enh_desc_ops = {
382 .tx_status = enh_desc_get_tx_status, 425 .tx_status = enh_desc_get_tx_status,
383 .rx_status = enh_desc_get_rx_status, 426 .rx_status = enh_desc_get_rx_status,
@@ -395,4 +438,8 @@ const struct stmmac_desc_ops enh_desc_ops = {
395 .set_rx_owner = enh_desc_set_rx_owner, 438 .set_rx_owner = enh_desc_set_rx_owner,
396 .get_rx_frame_len = enh_desc_get_rx_frame_len, 439 .get_rx_frame_len = enh_desc_get_rx_frame_len,
397 .rx_extended_status = enh_desc_get_ext_status, 440 .rx_extended_status = enh_desc_get_ext_status,
441 .enable_tx_timestamp = enh_desc_enable_tx_timestamp,
442 .get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
443 .get_timestamp = enh_desc_get_timestamp,
444 .get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
398}; 445};
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 47d509435ebb..7cbcea348c3d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -219,6 +219,39 @@ static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
219 return p->des01.rx.frame_length; 219 return p->des01.rx.frame_length;
220} 220}
221 221
222static void ndesc_enable_tx_timestamp(struct dma_desc *p)
223{
224 p->des01.tx.time_stamp_enable = 1;
225}
226
227static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
228{
229 return p->des01.tx.time_stamp_status;
230}
231
232static u64 ndesc_get_timestamp(void *desc, u32 ats)
233{
234 struct dma_desc *p = (struct dma_desc *)desc;
235 u64 ns;
236
237 ns = p->des2;
238 /* convert high/sec time stamp value to nanosecond */
239 ns += p->des3 * 1000000000ULL;
240
241 return ns;
242}
243
244static int ndesc_get_rx_timestamp_status(void *desc, u32 ats)
245{
246 struct dma_desc *p = (struct dma_desc *)desc;
247
248 if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
249 /* timestamp is corrupted, hence don't store it */
250 return 0;
251 else
252 return 1;
253}
254
222const struct stmmac_desc_ops ndesc_ops = { 255const struct stmmac_desc_ops ndesc_ops = {
223 .tx_status = ndesc_get_tx_status, 256 .tx_status = ndesc_get_tx_status,
224 .rx_status = ndesc_get_rx_status, 257 .rx_status = ndesc_get_rx_status,
@@ -235,4 +268,8 @@ const struct stmmac_desc_ops ndesc_ops = {
235 .set_tx_owner = ndesc_set_tx_owner, 268 .set_tx_owner = ndesc_set_tx_owner,
236 .set_rx_owner = ndesc_set_rx_owner, 269 .set_rx_owner = ndesc_set_rx_owner,
237 .get_rx_frame_len = ndesc_get_rx_frame_len, 270 .get_rx_frame_len = ndesc_get_rx_frame_len,
271 .enable_tx_timestamp = ndesc_enable_tx_timestamp,
272 .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
273 .get_timestamp = ndesc_get_timestamp,
274 .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
238}; 275};
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 43fc699b21cc..d0265a7d5a54 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -87,11 +87,14 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
87 return ret; 87 return ret;
88} 88}
89 89
90static void stmmac_refill_desc3(int bfsize, struct dma_desc *p) 90static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
91{ 91{
92 /* Fill DES3 in case of RING mode */ 92 struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
93 if (bfsize >= BUF_SIZE_8KiB) 93
94 p->des3 = p->des2 + BUF_SIZE_8KiB; 94 if (unlikely(priv->plat->has_gmac))
95 /* Fill DES3 in case of RING mode */
96 if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
97 p->des3 = p->des2 + BUF_SIZE_8KiB;
95} 98}
96 99
97/* In ring mode we need to fill the desc3 because it is used as buffer */ 100/* In ring mode we need to fill the desc3 because it is used as buffer */
@@ -100,7 +103,7 @@ static void stmmac_init_desc3(struct dma_desc *p)
100 p->des3 = p->des2 + BUF_SIZE_8KiB; 103 p->des3 = p->des2 + BUF_SIZE_8KiB;
101} 104}
102 105
103static void stmmac_clean_desc3(struct dma_desc *p) 106static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
104{ 107{
105 if (unlikely(p->des3)) 108 if (unlikely(p->des3))
106 p->des3 = 0; 109 p->des3 = 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 5176cae44b03..a21d1b9c9094 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -99,6 +99,10 @@ struct stmmac_priv {
99 unsigned int mode; 99 unsigned int mode;
100 int extend_desc; 100 int extend_desc;
101 int pcs; 101 int pcs;
102 int hwts_tx_en;
103 int hwts_rx_en;
104 unsigned int default_addend;
105 u32 adv_ts;
102}; 106};
103 107
104extern int phyaddr; 108extern int phyaddr;
@@ -108,6 +112,7 @@ extern int stmmac_mdio_register(struct net_device *ndev);
108extern void stmmac_set_ethtool_ops(struct net_device *netdev); 112extern void stmmac_set_ethtool_ops(struct net_device *netdev);
109extern const struct stmmac_desc_ops enh_desc_ops; 113extern const struct stmmac_desc_ops enh_desc_ops;
110extern const struct stmmac_desc_ops ndesc_ops; 114extern const struct stmmac_desc_ops ndesc_ops;
115extern const struct stmmac_hwtimestamp stmmac_ptp;
111int stmmac_freeze(struct net_device *ndev); 116int stmmac_freeze(struct net_device *ndev);
112int stmmac_restore(struct net_device *ndev); 117int stmmac_restore(struct net_device *ndev);
113int stmmac_resume(struct net_device *ndev); 118int stmmac_resume(struct net_device *ndev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 54e15db516fe..5b340c23fd6b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -27,6 +27,7 @@
27#include <linux/interrupt.h> 27#include <linux/interrupt.h>
28#include <linux/mii.h> 28#include <linux/mii.h>
29#include <linux/phy.h> 29#include <linux/phy.h>
30#include <linux/net_tstamp.h>
30#include <asm/io.h> 31#include <asm/io.h>
31 32
32#include "stmmac.h" 33#include "stmmac.h"
@@ -725,6 +726,35 @@ static int stmmac_set_coalesce(struct net_device *dev,
725 return 0; 726 return 0;
726} 727}
727 728
729static int stmmac_get_ts_info(struct net_device *dev,
730 struct ethtool_ts_info *info)
731{
732 struct stmmac_priv *priv = netdev_priv(dev);
733
734 if ((priv->hwts_tx_en) && (priv->hwts_rx_en)) {
735
736 info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
737 SOF_TIMESTAMPING_RX_HARDWARE |
738 SOF_TIMESTAMPING_RAW_HARDWARE;
739
740 info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
741
742 info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
743 (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
744 (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
745 (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
746 (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
747 (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
748 (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
749 (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
750 (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
751 (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
752 (1 << HWTSTAMP_FILTER_ALL));
753 return 0;
754 } else
755 return ethtool_op_get_ts_info(dev, info);
756}
757
728static const struct ethtool_ops stmmac_ethtool_ops = { 758static const struct ethtool_ops stmmac_ethtool_ops = {
729 .begin = stmmac_check_if_running, 759 .begin = stmmac_check_if_running,
730 .get_drvinfo = stmmac_ethtool_getdrvinfo, 760 .get_drvinfo = stmmac_ethtool_getdrvinfo,
@@ -744,7 +774,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
744 .get_eee = stmmac_ethtool_op_get_eee, 774 .get_eee = stmmac_ethtool_op_get_eee,
745 .set_eee = stmmac_ethtool_op_set_eee, 775 .set_eee = stmmac_ethtool_op_set_eee,
746 .get_sset_count = stmmac_get_sset_count, 776 .get_sset_count = stmmac_get_sset_count,
747 .get_ts_info = ethtool_op_get_ts_info, 777 .get_ts_info = stmmac_get_ts_info,
748 .get_coalesce = stmmac_get_coalesce, 778 .get_coalesce = stmmac_get_coalesce,
749 .set_coalesce = stmmac_set_coalesce, 779 .set_coalesce = stmmac_set_coalesce,
750}; 780};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
new file mode 100644
index 000000000000..380baeb016a9
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -0,0 +1,108 @@
1/*******************************************************************************
2 Copyright (C) 2013 Vayavya Labs Pvt Ltd
3
4 This implements all the API for managing HW timestamp & PTP.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms and conditions of the GNU General Public License,
8 version 2, as published by the Free Software Foundation.
9
10 This program is distributed in the hope it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18
19 The full GNU General Public License is included in this distribution in
20 the file called "COPYING".
21
22 Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
23 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
24*******************************************************************************/
25
26#include <linux/io.h>
27#include <linux/delay.h>
28#include "common.h"
29#include "stmmac_ptp.h"
30
31static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
32{
33 writel(data, ioaddr + PTP_TCR);
34}
35
36static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
37{
38 u32 value = readl(ioaddr + PTP_TCR);
39 unsigned long data;
40
41 /* Convert the ptp_clock to nano second
42 * formula = (1/ptp_clock) * 1000000000
43 * where, ptp_clock = 50MHz.
44 */
45 data = (1000000000ULL / 50000000);
46
47 /* 0.465ns accuracy */
48 if (value & PTP_TCR_TSCTRLSSR)
49 data = (data * 100) / 465;
50
51 writel(data, ioaddr + PTP_SSIR);
52}
53
54static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
55{
56 int limit;
57 u32 value;
58
59 writel(sec, ioaddr + PTP_STSUR);
60 writel(nsec, ioaddr + PTP_STNSUR);
61 /* issue command to initialize the system time value */
62 value = readl(ioaddr + PTP_TCR);
63 value |= PTP_TCR_TSINIT;
64 writel(value, ioaddr + PTP_TCR);
65
66 /* wait for present system time initialize to complete */
67 limit = 10;
68 while (limit--) {
69 if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
70 break;
71 mdelay(10);
72 }
73 if (limit < 0)
74 return -EBUSY;
75
76 return 0;
77}
78
79static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
80{
81 u32 value;
82 int limit;
83
84 writel(addend, ioaddr + PTP_TAR);
85 /* issue command to update the addend value */
86 value = readl(ioaddr + PTP_TCR);
87 value |= PTP_TCR_TSADDREG;
88 writel(value, ioaddr + PTP_TCR);
89
90 /* wait for present addend update to complete */
91 limit = 10;
92 while (limit--) {
93 if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
94 break;
95 mdelay(10);
96 }
97 if (limit < 0)
98 return -EBUSY;
99
100 return 0;
101}
102
103const struct stmmac_hwtimestamp stmmac_ptp = {
104 .config_hw_tstamping = stmmac_config_hw_tstamping,
105 .init_systime = stmmac_init_systime,
106 .config_sub_second_increment = stmmac_config_sub_second_increment,
107 .config_addend = stmmac_config_addend,
108};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 180eed7168c1..6906772069e3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -47,6 +47,8 @@
47#include <linux/debugfs.h> 47#include <linux/debugfs.h>
48#include <linux/seq_file.h> 48#include <linux/seq_file.h>
49#endif 49#endif
50#include <linux/net_tstamp.h>
51#include "stmmac_ptp.h"
50#include "stmmac.h" 52#include "stmmac.h"
51 53
52#undef STMMAC_DEBUG 54#undef STMMAC_DEBUG
@@ -311,6 +313,327 @@ static void stmmac_eee_adjust(struct stmmac_priv *priv)
311 priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link); 313 priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
312} 314}
313 315
316/* stmmac_get_tx_hwtstamp:
317 * @priv : pointer to private device structure.
318 * @entry : descriptor index to be used.
319 * @skb : the socket buffer
320 * Description :
321 * This function will read timestamp from the descriptor & pass it to stack.
322 * and also perform some sanity checks.
323 */
324static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
325 unsigned int entry,
326 struct sk_buff *skb)
327{
328 struct skb_shared_hwtstamps shhwtstamp;
329 u64 ns;
330 void *desc = NULL;
331
332 if (!priv->hwts_tx_en)
333 return;
334
335 /* if skb doesn't support hw tstamp */
336 if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
337 return;
338
339 if (priv->adv_ts)
340 desc = (priv->dma_etx + entry);
341 else
342 desc = (priv->dma_tx + entry);
343
344 /* check tx tstamp status */
345 if (!priv->hw->desc->get_tx_timestamp_status((struct dma_desc *)desc))
346 return;
347
348 /* get the valid tstamp */
349 ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
350
351 memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
352 shhwtstamp.hwtstamp = ns_to_ktime(ns);
353 /* pass tstamp to stack */
354 skb_tstamp_tx(skb, &shhwtstamp);
355
356 return;
357}
358
359/* stmmac_get_rx_hwtstamp:
360 * @priv : pointer to private device structure.
361 * @entry : descriptor index to be used.
362 * @skb : the socket buffer
363 * Description :
364 * This function will read received packet's timestamp from the descriptor
365 * and pass it to stack. It also perform some sanity checks.
366 */
367static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv,
368 unsigned int entry,
369 struct sk_buff *skb)
370{
371 struct skb_shared_hwtstamps *shhwtstamp = NULL;
372 u64 ns;
373 void *desc = NULL;
374
375 if (!priv->hwts_rx_en)
376 return;
377
378 if (priv->adv_ts)
379 desc = (priv->dma_erx + entry);
380 else
381 desc = (priv->dma_rx + entry);
382
383 /* if rx tstamp is not valid */
384 if (!priv->hw->desc->get_rx_timestamp_status(desc, priv->adv_ts))
385 return;
386
387 /* get valid tstamp */
388 ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
389 shhwtstamp = skb_hwtstamps(skb);
390 memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
391 shhwtstamp->hwtstamp = ns_to_ktime(ns);
392}
393
394/**
395 * stmmac_hwtstamp_ioctl - control hardware timestamping.
396 * @dev: device pointer.
397 * @ifr: An IOCTL specefic structure, that can contain a pointer to
398 * a proprietary structure used to pass information to the driver.
399 * Description:
400 * This function configures the MAC to enable/disable both outgoing(TX)
401 * and incoming(RX) packets time stamping based on user input.
402 * Return Value:
403 * 0 on success and an appropriate -ve integer on failure.
404 */
405static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
406{
407 struct stmmac_priv *priv = netdev_priv(dev);
408 struct hwtstamp_config config;
409 struct timespec now;
410 u64 temp = 0;
411 u32 ptp_v2 = 0;
412 u32 tstamp_all = 0;
413 u32 ptp_over_ipv4_udp = 0;
414 u32 ptp_over_ipv6_udp = 0;
415 u32 ptp_over_ethernet = 0;
416 u32 snap_type_sel = 0;
417 u32 ts_master_en = 0;
418 u32 ts_event_en = 0;
419 u32 value = 0;
420
421 if (!(priv->dma_cap.time_stamp || priv->adv_ts)) {
422 netdev_alert(priv->dev, "No support for HW time stamping\n");
423 priv->hwts_tx_en = 0;
424 priv->hwts_rx_en = 0;
425
426 return -EOPNOTSUPP;
427 }
428
429 if (copy_from_user(&config, ifr->ifr_data,
430 sizeof(struct hwtstamp_config)))
431 return -EFAULT;
432
433 pr_debug("%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
434 __func__, config.flags, config.tx_type, config.rx_filter);
435
436 /* reserved for future extensions */
437 if (config.flags)
438 return -EINVAL;
439
440 switch (config.tx_type) {
441 case HWTSTAMP_TX_OFF:
442 priv->hwts_tx_en = 0;
443 break;
444 case HWTSTAMP_TX_ON:
445 priv->hwts_tx_en = 1;
446 break;
447 default:
448 return -ERANGE;
449 }
450
451 if (priv->adv_ts) {
452 switch (config.rx_filter) {
453 /* time stamp no incoming packet at all */
454 case HWTSTAMP_FILTER_NONE:
455 config.rx_filter = HWTSTAMP_FILTER_NONE;
456 break;
457
458 /* PTP v1, UDP, any kind of event packet */
459 case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
460 config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
461 /* take time stamp for all event messages */
462 snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
463
464 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
465 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
466 break;
467
468 /* PTP v1, UDP, Sync packet */
469 case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
470 config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
471 /* take time stamp for SYNC messages only */
472 ts_event_en = PTP_TCR_TSEVNTENA;
473
474 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
475 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
476 break;
477
478 /* PTP v1, UDP, Delay_req packet */
479 case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
480 config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
481 /* take time stamp for Delay_Req messages only */
482 ts_master_en = PTP_TCR_TSMSTRENA;
483 ts_event_en = PTP_TCR_TSEVNTENA;
484
485 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
486 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
487 break;
488
489 /* PTP v2, UDP, any kind of event packet */
490 case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
491 config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
492 ptp_v2 = PTP_TCR_TSVER2ENA;
493 /* take time stamp for all event messages */
494 snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
495
496 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
497 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
498 break;
499
500 /* PTP v2, UDP, Sync packet */
501 case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
502 config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC;
503 ptp_v2 = PTP_TCR_TSVER2ENA;
504 /* take time stamp for SYNC messages only */
505 ts_event_en = PTP_TCR_TSEVNTENA;
506
507 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
508 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
509 break;
510
511 /* PTP v2, UDP, Delay_req packet */
512 case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
513 config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ;
514 ptp_v2 = PTP_TCR_TSVER2ENA;
515 /* take time stamp for Delay_Req messages only */
516 ts_master_en = PTP_TCR_TSMSTRENA;
517 ts_event_en = PTP_TCR_TSEVNTENA;
518
519 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
520 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
521 break;
522
523 /* PTP v2/802.AS1, any layer, any kind of event packet */
524 case HWTSTAMP_FILTER_PTP_V2_EVENT:
525 config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
526 ptp_v2 = PTP_TCR_TSVER2ENA;
527 /* take time stamp for all event messages */
528 snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
529
530 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
531 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
532 ptp_over_ethernet = PTP_TCR_TSIPENA;
533 break;
534
535 /* PTP v2/802.AS1, any layer, Sync packet */
536 case HWTSTAMP_FILTER_PTP_V2_SYNC:
537 config.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
538 ptp_v2 = PTP_TCR_TSVER2ENA;
539 /* take time stamp for SYNC messages only */
540 ts_event_en = PTP_TCR_TSEVNTENA;
541
542 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
543 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
544 ptp_over_ethernet = PTP_TCR_TSIPENA;
545 break;
546
547 /* PTP v2/802.AS1, any layer, Delay_req packet */
548 case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
549 config.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
550 ptp_v2 = PTP_TCR_TSVER2ENA;
551 /* take time stamp for Delay_Req messages only */
552 ts_master_en = PTP_TCR_TSMSTRENA;
553 ts_event_en = PTP_TCR_TSEVNTENA;
554
555 ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
556 ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
557 ptp_over_ethernet = PTP_TCR_TSIPENA;
558 break;
559
560 /* time stamp any incoming packet */
561 case HWTSTAMP_FILTER_ALL:
562 config.rx_filter = HWTSTAMP_FILTER_ALL;
563 tstamp_all = PTP_TCR_TSENALL;
564 break;
565
566 default:
567 return -ERANGE;
568 }
569 } else {
570 switch (config.rx_filter) {
571 case HWTSTAMP_FILTER_NONE:
572 config.rx_filter = HWTSTAMP_FILTER_NONE;
573 break;
574 default:
575 /* PTP v1, UDP, any kind of event packet */
576 config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
577 break;
578 }
579 }
580 priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
581
582 if (!priv->hwts_tx_en && !priv->hwts_rx_en)
583 priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
584 else {
585 value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR |
586 tstamp_all | ptp_v2 | ptp_over_ethernet |
587 ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
588 ts_master_en | snap_type_sel);
589
590 priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value);
591
592 /* program Sub Second Increment reg */
593 priv->hw->ptp->config_sub_second_increment(priv->ioaddr);
594
595 /* calculate default added value:
596 * formula is :
597 * addend = (2^32)/freq_div_ratio;
598 * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz
599 * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK;
600 * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to
601 * achive 20ns accuracy.
602 *
603 * 2^x * y == (y << x), hence
604 * 2^32 * 50000000 ==> (50000000 << 32)
605 */
606 temp = (u64)(50000000ULL << 32);
607 priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK);
608 priv->hw->ptp->config_addend(priv->ioaddr,
609 priv->default_addend);
610
611 /* initialize system time */
612 getnstimeofday(&now);
613 priv->hw->ptp->init_systime(priv->ioaddr, now.tv_sec,
614 now.tv_nsec);
615 }
616
617 return copy_to_user(ifr->ifr_data, &config,
618 sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
619}
620
621static void stmmac_init_ptp(struct stmmac_priv *priv)
622{
623 if (priv->dma_cap.time_stamp) {
624 pr_debug("IEEE 1588-2002 Time Stamp supported\n");
625 priv->adv_ts = 0;
626 }
627 if (priv->dma_cap.atime_stamp && priv->extend_desc) {
628 pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
629 priv->adv_ts = 1;
630 }
631
632 priv->hw->ptp = &stmmac_ptp;
633 priv->hwts_tx_en = 0;
634 priv->hwts_rx_en = 0;
635}
636
314/** 637/**
315 * stmmac_adjust_link 638 * stmmac_adjust_link
316 * @dev: net device structure 639 * @dev: net device structure
@@ -856,6 +1179,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
856 priv->xstats.tx_pkt_n++; 1179 priv->xstats.tx_pkt_n++;
857 } else 1180 } else
858 priv->dev->stats.tx_errors++; 1181 priv->dev->stats.tx_errors++;
1182
1183 stmmac_get_tx_hwtstamp(priv, entry, skb);
859 } 1184 }
860 TX_DBG("%s: curr %d, dirty %d\n", __func__, 1185 TX_DBG("%s: curr %d, dirty %d\n", __func__,
861 priv->cur_tx, priv->dirty_tx); 1186 priv->cur_tx, priv->dirty_tx);
@@ -867,8 +1192,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
867 DMA_TO_DEVICE); 1192 DMA_TO_DEVICE);
868 priv->tx_skbuff_dma[entry] = 0; 1193 priv->tx_skbuff_dma[entry] = 0;
869 } 1194 }
870 if (priv->mode == STMMAC_RING_MODE) 1195 priv->hw->ring->clean_desc3(priv, p);
871 priv->hw->ring->clean_desc3(p);
872 1196
873 if (likely(skb != NULL)) { 1197 if (likely(skb != NULL)) {
874 dev_kfree_skb(skb); 1198 dev_kfree_skb(skb);
@@ -1243,6 +1567,8 @@ static int stmmac_open(struct net_device *dev)
1243 1567
1244 stmmac_mmc_setup(priv); 1568 stmmac_mmc_setup(priv);
1245 1569
1570 stmmac_init_ptp(priv);
1571
1246#ifdef CONFIG_STMMAC_DEBUG_FS 1572#ifdef CONFIG_STMMAC_DEBUG_FS
1247 ret = stmmac_init_fs(dev); 1573 ret = stmmac_init_fs(dev);
1248 if (ret < 0) 1574 if (ret < 0)
@@ -1507,7 +1833,15 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
1507 1833
1508 dev->stats.tx_bytes += skb->len; 1834 dev->stats.tx_bytes += skb->len;
1509 1835
1510 skb_tx_timestamp(skb); 1836 if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
1837 priv->hwts_tx_en)) {
1838 /* declare that device is doing timestamping */
1839 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
1840 priv->hw->desc->enable_tx_timestamp(first);
1841 }
1842
1843 if (!priv->hwts_tx_en)
1844 skb_tx_timestamp(skb);
1511 1845
1512 priv->hw->dma->enable_dma_transmission(priv->ioaddr); 1846 priv->hw->dma->enable_dma_transmission(priv->ioaddr);
1513 1847
@@ -1545,9 +1879,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
1545 1879
1546 p->des2 = priv->rx_skbuff_dma[entry]; 1880 p->des2 = priv->rx_skbuff_dma[entry];
1547 1881
1548 if (unlikely((priv->mode == STMMAC_RING_MODE) && 1882 priv->hw->ring->refill_desc3(priv, p);
1549 (priv->plat->has_gmac)))
1550 priv->hw->ring->refill_desc3(bfsize, p);
1551 1883
1552 RX_DBG(KERN_INFO "\trefill entry #%d\n", entry); 1884 RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
1553 } 1885 }
@@ -1604,9 +1936,20 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
1604 &priv->xstats, 1936 &priv->xstats,
1605 priv->dma_erx + 1937 priv->dma_erx +
1606 entry); 1938 entry);
1607 if (unlikely(status == discard_frame)) 1939 if (unlikely(status == discard_frame)) {
1608 priv->dev->stats.rx_errors++; 1940 priv->dev->stats.rx_errors++;
1609 else { 1941 if (priv->hwts_rx_en && !priv->extend_desc) {
1942 /* DESC2 & DESC3 will be overwitten by device
1943 * with timestamp value, hence reinitialize
1944 * them in stmmac_rx_refill() function so that
1945 * device can reuse it.
1946 */
1947 priv->rx_skbuff[entry] = NULL;
1948 dma_unmap_single(priv->device,
1949 priv->rx_skbuff_dma[entry],
1950 priv->dma_buf_sz, DMA_FROM_DEVICE);
1951 }
1952 } else {
1610 struct sk_buff *skb; 1953 struct sk_buff *skb;
1611 int frame_len; 1954 int frame_len;
1612 1955
@@ -1635,6 +1978,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
1635 prefetch(skb->data - NET_IP_ALIGN); 1978 prefetch(skb->data - NET_IP_ALIGN);
1636 priv->rx_skbuff[entry] = NULL; 1979 priv->rx_skbuff[entry] = NULL;
1637 1980
1981 stmmac_get_rx_hwtstamp(priv, entry, skb);
1982
1638 skb_put(skb, frame_len); 1983 skb_put(skb, frame_len);
1639 dma_unmap_single(priv->device, 1984 dma_unmap_single(priv->device,
1640 priv->rx_skbuff_dma[entry], 1985 priv->rx_skbuff_dma[entry],
@@ -1855,21 +2200,30 @@ static void stmmac_poll_controller(struct net_device *dev)
1855 * a proprietary structure used to pass information to the driver. 2200 * a proprietary structure used to pass information to the driver.
1856 * @cmd: IOCTL command 2201 * @cmd: IOCTL command
1857 * Description: 2202 * Description:
1858 * Currently there are no special functionality supported in IOCTL, just the 2203 * Currently it supports just the phy_mii_ioctl(...) and HW time stamping.
1859 * phy_mii_ioctl(...) can be invoked.
1860 */ 2204 */
1861static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 2205static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
1862{ 2206{
1863 struct stmmac_priv *priv = netdev_priv(dev); 2207 struct stmmac_priv *priv = netdev_priv(dev);
1864 int ret; 2208 int ret = -EOPNOTSUPP;
1865 2209
1866 if (!netif_running(dev)) 2210 if (!netif_running(dev))
1867 return -EINVAL; 2211 return -EINVAL;
1868 2212
1869 if (!priv->phydev) 2213 switch (cmd) {
1870 return -EINVAL; 2214 case SIOCGMIIPHY:
1871 2215 case SIOCGMIIREG:
1872 ret = phy_mii_ioctl(priv->phydev, rq, cmd); 2216 case SIOCSMIIREG:
2217 if (!priv->phydev)
2218 return -EINVAL;
2219 ret = phy_mii_ioctl(priv->phydev, rq, cmd);
2220 break;
2221 case SIOCSHWTSTAMP:
2222 ret = stmmac_hwtstamp_ioctl(dev, rq);
2223 break;
2224 default:
2225 break;
2226 }
1873 2227
1874 return ret; 2228 return ret;
1875} 2229}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
new file mode 100644
index 000000000000..3dbc047622fa
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -0,0 +1,74 @@
1/******************************************************************************
2 PTP Header file
3
4 Copyright (C) 2013 Vayavya Labs Pvt Ltd
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms and conditions of the GNU General Public License,
8 version 2, as published by the Free Software Foundation.
9
10 This program is distributed in the hope it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18
19 The full GNU General Public License is included in this distribution in
20 the file called "COPYING".
21
22 Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
23******************************************************************************/
24
25#ifndef __STMMAC_PTP_H__
26#define __STMMAC_PTP_H__
27
28#define STMMAC_SYSCLOCK 62500000
29
30/* IEEE 1588 PTP register offsets */
31#define PTP_TCR 0x0700 /* Timestamp Control Reg */
32#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */
33#define PTP_STSR 0x0708 /* System Time – Seconds Regr */
34#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */
35#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */
36#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */
37#define PTP_TAR 0x0718 /* Timestamp Addend Reg */
38#define PTP_TTSR 0x071C /* Target Time Seconds Reg */
39#define PTP_TTNSR 0x0720 /* Target Time Nanoseconds Reg */
40#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
41#define PTP_TSR 0x0728 /* Timestamp Status */
42
43#define PTP_STNSUR_ADDSUB_SHIFT 31
44
45/* PTP TCR defines */
46#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
47#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
48#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */
49#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */
50/* Timestamp Interrupt Trigger Enable */
51#define PTP_TCR_TSTRIG 0x00000010
52#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */
53#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */
54/* Timestamp Digital or Binary Rollover Control */
55#define PTP_TCR_TSCTRLSSR 0x00000200
56
57/* Enable PTP packet Processing for Version 2 Format */
58#define PTP_TCR_TSVER2ENA 0x00000400
59/* Enable Processing of PTP over Ethernet Frames */
60#define PTP_TCR_TSIPENA 0x00000800
61/* Enable Processing of PTP Frames Sent over IPv6-UDP */
62#define PTP_TCR_TSIPV6ENA 0x00001000
63/* Enable Processing of PTP Frames Sent over IPv4-UDP */
64#define PTP_TCR_TSIPV4ENA 0x00002000
65/* Enable Timestamp Snapshot for Event Messages */
66#define PTP_TCR_TSEVNTENA 0x00004000
67/* Enable Snapshot for Messages Relevant to Master */
68#define PTP_TCR_TSMSTRENA 0x00008000
69/* Select PTP packets for Taking Snapshots */
70#define PTP_TCR_SNAPTYPSEL_1 0x00010000
71/* Enable MAC address for PTP Frame Filtering */
72#define PTP_TCR_TSENMACADDR 0x00040000
73
74#endif /* __STMMAC_PTP_H__ */