* [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
@ 2013-03-07 10:50 Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 1/9] stmmac: add tx_skbuff_dma to save descriptors used by PTP Giuseppe CAVALLARO
` (10 more replies)
0 siblings, 11 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro
These patches enhance the driver adding the PTP support
and the initial code for RGMII/SGMII/TBI/RTBI modes.
Thx goes to Rayagond that wrote and tested the PTP and
to Byungho for SGMII/RGMII.
Concerning the PTP, I have hacked/reviewed and tested many
part of these patches also verifying the back compatibility on
several HW and chips.
The PTP support is quite intrusive because it needs to support the extended
descriptors used for saving the HW timestamps.
These are available in new chip generations, only.
So we have actually found useful to use some Kconfig options to
surround PTP and extended descriptor support. This approach helped on
old platform (embeeded system) where PTP is not supported and where we
do not want to pay extra code and check in critical rx/tx paths.
Concerning the SGMII/RGMII we have already discussed about the support
in the net.dev Mailing list with Byungho where these patchs were partially
analysed.
So I have only ported them against the latest net-next (and on
top of PTP). I have added some missing things: e.g. some parts of the
ethtool for ANE. As we clarified with Byungho, we will add further
enhancements on top of these patches if needed.
I have also built all against ARM/SH/X68 platforms and no issues on
ST-Boxes (built-in & dyn modules).
Welcome feedback.
Peppe
Giuseppe Cavallaro (5):
stmmac: support extend descriptors
stmmac: add missing supported filters to get_ts_info
stmmac: start adding pcs and rgmii core irq
stmmac: initial support to manage pcs modes
stmmac: update the Doc and Version (PTP+SGMII)
Rayagond Kokatanur (4):
stmmac: add tx_skbuff_dma to save descriptors used by PTP
stmmac: add IEEE 1588-2002 PTP support
stmmac: add the support for PTP hw clock driver
stmmac: add IEEE 1588-2008 PTP V2 support
Documentation/networking/stmmac.txt | 39 ++-
drivers/net/ethernet/stmicro/stmmac/Kconfig | 40 ++
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 30 +-
drivers/net/ethernet/stmicro/stmmac/common.h | 106 ++++-
drivers/net/ethernet/stmicro/stmmac/descs.h | 47 ++-
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 40 ++-
.../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 104 ++++-
.../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 8 +-
.../net/ethernet/stmicro/stmmac/dwmac100_core.c | 3 +-
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c | 4 +-
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 1 -
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 110 ++++-
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 40 ++-
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 16 +-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 27 +-
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 159 ++++++-
.../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 183 +++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 543 +++++++++++++++++--
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 209 ++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 74 +++
21 files changed, 1669 insertions(+), 115 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
--
1.7.4.4
^ permalink raw reply [flat|nested] 29+ messages in thread
* [net-next.git 1/9] stmmac: add tx_skbuff_dma to save descriptors used by PTP
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support Giuseppe CAVALLARO
` (9 subsequent siblings)
10 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Rayagond Kokatanur
From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
This patch adds a new pointer variable called "tx_skbuff_dma" to private
data structure. This variable will holds the physical address of packet
to be transmitted & same will be used to free/unmap the memory once the
corresponding packet is transmitted by device.
Prior to this patch the descriptor buffer pointer(ie des2) itself was
being used for freeing/unmapping the buffer memory. But in case PTP v1
with normal descriptor the field(des2) will be overwritten by device
with timestamp value, hence driver will loose the buffer pointer to be
freed/unmapped.
Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Reviewed-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 3 +++
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 3 +++
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 21 ++++++++++++++++-----
4 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index 0668659..ad3d75f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -47,6 +47,7 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum);
while (len != 0) {
@@ -57,6 +58,7 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i),
bmax, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 0, bmax,
csum);
priv->hw->desc->set_tx_owner(desc);
@@ -67,6 +69,7 @@ unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device,
(skb->data + bmax * i), len,
DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 0, len,
csum);
priv->hw->desc->set_tx_owner(desc);
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 4b785e1..839e349 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -48,6 +48,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data,
bmax, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 1, bmax,
csum);
@@ -57,6 +58,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum);
wmb();
@@ -65,6 +67,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
nopaged_len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index b05df89..013a7d5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -37,6 +37,7 @@ struct stmmac_priv {
struct dma_desc *dma_tx ____cacheline_aligned;
dma_addr_t dma_tx_phy;
struct sk_buff **tx_skbuff;
+ dma_addr_t *tx_skbuff_dma;
unsigned int cur_tx;
unsigned int dirty_tx;
unsigned int dma_tx_size;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 39c6c55..260af93 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -540,6 +540,8 @@ static void init_dma_desc_rings(struct net_device *dev)
sizeof(struct dma_desc),
&priv->dma_rx_phy,
GFP_KERNEL);
+ priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
+ GFP_KERNEL);
priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
GFP_KERNEL);
priv->dma_tx =
@@ -591,6 +593,7 @@ static void init_dma_desc_rings(struct net_device *dev)
/* TX INITIALIZATION */
for (i = 0; i < txsize; i++) {
+ priv->tx_skbuff_dma[i] = 0;
priv->tx_skbuff[i] = NULL;
priv->dma_tx[i].des2 = 0;
}
@@ -638,12 +641,14 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
for (i = 0; i < priv->dma_tx_size; i++) {
if (priv->tx_skbuff[i] != NULL) {
struct dma_desc *p = priv->dma_tx + i;
- if (p->des2)
- dma_unmap_single(priv->device, p->des2,
+ if (priv->tx_skbuff_dma[i])
+ dma_unmap_single(priv->device,
+ priv->tx_skbuff_dma[i],
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
dev_kfree_skb_any(priv->tx_skbuff[i]);
priv->tx_skbuff[i] = NULL;
+ priv->tx_skbuff_dma[i] = 0;
}
}
}
@@ -664,6 +669,7 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
priv->dma_rx, priv->dma_rx_phy);
kfree(priv->rx_skbuff_dma);
kfree(priv->rx_skbuff);
+ kfree(priv->tx_skbuff_dma);
kfree(priv->tx_skbuff);
}
@@ -730,10 +736,13 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
TX_DBG("%s: curr %d, dirty %d\n", __func__,
priv->cur_tx, priv->dirty_tx);
- if (likely(p->des2))
- dma_unmap_single(priv->device, p->des2,
+ if (likely(priv->tx_skbuff_dma[entry])) {
+ dma_unmap_single(priv->device,
+ priv->tx_skbuff_dma[entry],
priv->hw->desc->get_tx_len(p),
DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = 0;
+ }
priv->hw->ring->clean_desc3(p);
if (likely(skb != NULL)) {
@@ -1249,7 +1258,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
desc = priv->dma_tx + entry;
} else {
desc->des2 = dma_map_single(priv->device, skb->data,
- nopaged_len, DMA_TO_DEVICE);
+ nopaged_len, DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
csum_insertion);
}
@@ -1264,6 +1274,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
TX_DBG("\t[entry %d] segment len: %d\n", entry, len);
desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
DMA_TO_DEVICE);
+ priv->tx_skbuff_dma[entry] = desc->des2;
priv->tx_skbuff[entry] = NULL;
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion);
wmb();
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 1/9] stmmac: add tx_skbuff_dma to save descriptors used by PTP Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-08 6:34 ` Richard Cochran
2013-03-07 10:50 ` [net-next.git 3/9] stmmac: support extend descriptors Giuseppe CAVALLARO
` (8 subsequent siblings)
10 siblings, 1 reply; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Rayagond Kokatanur
From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
This patch enhances the stmmac driver to support IEEE 1588-2002
PTP (Precision Time Protocol) version 1.
IEEE 1588-2002 standard defines a protocol, 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.
HW Timestamp support can be enabled while configuring the Kernel and
the Koption is: STMMAC_USE_HWSTAMP
At runtime, the support is verified by looking at the HW capability
register.
Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Hacked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 +
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 23 ++-
drivers/net/ethernet/stmicro/stmmac/common.h | 27 ++-
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 1 -
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 37 +++
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 34 +++
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 14 +-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 8 +
.../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 129 ++++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 255 +++++++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 72 ++++++
12 files changed, 588 insertions(+), 24 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index c0ea838..ef703b3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -71,5 +71,16 @@ config STMMAC_CHAINED
endchoice
+config STMMAC_USE_HWSTAMP
+ bool "Use IEEE 1588 Precision Time Protocol"
+ depends on STMMAC_ETH
+ select PTP_1588_CLOCK
+ default n
+ ---help---
+ Enable this option to support the IEEE 1588 Precision Time Protocol
+ (PTP) and HW Timestamps.
+ At runtime, on new chip generations, the hardware capability
+ register will be used to verify if either the IEEE 1588-2008 Advanced
+ Timestamping (PTPv2) or IEEE 1588-2002 (PTPv1) is actually supported.
endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index c8e8ea6..cc97c07 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -3,6 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
+stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index ad3d75f..dd60f6b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -92,16 +92,35 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
return ret;
}
-static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (priv->hwts_rx_en)
+ /* NOTE: Device will overwrite des3 with timestamp value if
+ * 1588-2002 time stamping is enabled, hence reinitialize it
+ * to keep explicit chaining in the descriptor.
+ */
+ p->des3 = (unsigned int)(priv->dma_rx +
+ ((priv->dirty_rx) + 1) % priv->dma_rx_size);
}
static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
{
}
-static void stmmac_clean_desc3(struct dma_desc *p)
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
+ int tstamp_taken)
{
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (tstamp_taken && priv->hw->desc->get_tx_ls(p))
+ /* NOTE: Device will overwrite des3 with timestamp value if
+ * 1588-2002 time stamping is enabled, hence reinitialize it
+ * to keep explicit chaining in the descriptor.
+ */
+ p->des3 = (unsigned int)(priv->dma_tx +
+ ((priv->dirty_tx + 1) % priv->dma_tx_size));
}
static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 186d148..fa8ff9b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -290,6 +290,16 @@ struct stmmac_desc_ops {
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
struct dma_desc *p);
+ /* Set tx timestamp enable bit */
+ void (*enable_tx_timestamp) (struct dma_desc *p);
+ /* get tx timestamp status */
+ int (*get_tx_timestamp_status) (struct dma_desc *p);
+ /* get tx/rx timestamp low value */
+ u32 (*get_timestamp_low) (struct dma_desc *p);
+ /* get tx/rx timestamp high value */
+ u32 (*get_timestamp_high) (struct dma_desc *p);
+ /* get rx timestamp status */
+ int (*get_rx_timestamp_status) (struct dma_desc *p);
};
struct stmmac_dma_ops {
@@ -346,6 +356,15 @@ struct stmmac_ops {
void (*set_eee_pls) (void __iomem *ioaddr, int link);
};
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+struct stmmac_hwtimestamp {
+ void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
+ void (*config_sub_second_increment) (void __iomem *ioaddr);
+ int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
+ int (*config_addend)(void __iomem *ioaddr, u32 addend);
+};
+#endif
+
struct mac_link {
int port;
int duplex;
@@ -360,11 +379,11 @@ struct mii_regs {
struct stmmac_ring_mode_ops {
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
- void (*refill_desc3) (int bfsize, struct dma_desc *p);
+ void (*refill_desc3) (void *priv, struct dma_desc *p);
void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size);
- void (*clean_desc3) (struct dma_desc *p);
+ void (*clean_desc3) (void *priv, struct dma_desc *p, int tstamp_taken);
int (*set_16kib_bfsize) (int mtu);
};
@@ -373,6 +392,9 @@ struct mac_device_info {
const struct stmmac_desc_ops *desc;
const struct stmmac_dma_ops *dma;
const struct stmmac_ring_mode_ops *ring;
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ const struct stmmac_hwtimestamp *ptp;
+#endif
struct mii_regs mii; /* MII register Addresses */
struct mac_link link;
unsigned int synopsys_uid;
@@ -390,5 +412,4 @@ extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
extern const struct stmmac_ring_mode_ops ring_mode_ops;
-
#endif /* __COMMON_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 491d7e9..8c4ea93 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -286,4 +286,3 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
addr[4] = hi_addr & 0xff;
addr[5] = (hi_addr >> 8) & 0xff;
}
-
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 2fc8ef9..4d635d5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -323,6 +323,38 @@ static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.erx.frame_length;
}
+static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
+{
+ p->des01.etx.time_stamp_enable = 1;
+}
+
+static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
+{
+ return p->des01.etx.time_stamp_status;
+}
+
+static u32 enh_desc_get_timestamp_low(struct dma_desc *p)
+{
+ /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
+ return p->des2;
+}
+
+static u32 enh_desc_get_timestamp_high(struct dma_desc *p)
+{
+ /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
+ return p->des3;
+}
+
+static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
+{
+ /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
+ if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ /* timestamp is currupted, hence don't store it */
+ return 0;
+ else
+ return 1;
+}
+
const struct stmmac_desc_ops enh_desc_ops = {
.tx_status = enh_desc_get_tx_status,
.rx_status = enh_desc_get_rx_status,
@@ -339,4 +371,9 @@ const struct stmmac_desc_ops enh_desc_ops = {
.set_tx_owner = enh_desc_set_tx_owner,
.set_rx_owner = enh_desc_set_rx_owner,
.get_rx_frame_len = enh_desc_get_rx_frame_len,
+ .enable_tx_timestamp = enh_desc_enable_tx_timestamp,
+ .get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
+ .get_timestamp_low = enh_desc_get_timestamp_low,
+ .get_timestamp_high = enh_desc_get_timestamp_high,
+ .get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 68962c5..edb5e88 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -215,6 +215,35 @@ static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.rx.frame_length;
}
+static void ndesc_enable_tx_timestamp(struct dma_desc *p)
+{
+ p->des01.tx.time_stamp_enable = 1;
+}
+
+static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
+{
+ return p->des01.tx.time_stamp_status;
+}
+
+static u32 ndesc_get_timestamp_low(struct dma_desc *p)
+{
+ return p->des2;
+}
+
+static u32 ndesc_get_timestamp_high(struct dma_desc *p)
+{
+ return p->des3;
+}
+
+static int ndesc_get_rx_timestamp_status(struct dma_desc *p)
+{
+ if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ /* timestamp is currupted, hence don't store it */
+ return 0;
+ else
+ return 1;
+}
+
const struct stmmac_desc_ops ndesc_ops = {
.tx_status = ndesc_get_tx_status,
.rx_status = ndesc_get_rx_status,
@@ -231,4 +260,9 @@ const struct stmmac_desc_ops ndesc_ops = {
.set_tx_owner = ndesc_set_tx_owner,
.set_rx_owner = ndesc_set_rx_owner,
.get_rx_frame_len = ndesc_get_rx_frame_len,
+ .enable_tx_timestamp = ndesc_enable_tx_timestamp,
+ .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
+ .get_timestamp_low = ndesc_get_timestamp_low,
+ .get_timestamp_high = ndesc_get_timestamp_high,
+ .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 839e349..94a1c2f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -85,11 +85,14 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
return ret;
}
-static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
+static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
- /* Fill DES3 in case of RING mode */
- if (bfsize >= BUF_SIZE_8KiB)
- p->des3 = p->des2 + BUF_SIZE_8KiB;
+ struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
+
+ if (unlikely(priv->plat->has_gmac))
+ /* Fill DES3 in case of RING mode */
+ if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
}
/* In ring mode we need to fill the desc3 because it is used
@@ -105,7 +108,8 @@ static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
{
}
-static void stmmac_clean_desc3(struct dma_desc *p)
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
+ int tstamp_taken)
{
if (unlikely(p->des3))
p->des3 = 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 013a7d5..665f2a2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -94,6 +94,11 @@ struct stmmac_priv {
u32 tx_coal_timer;
int use_riwt;
u32 rx_riwt;
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ int hwts_tx_en;
+ int hwts_rx_en;
+ unsigned int default_addend;
+#endif
};
extern int phyaddr;
@@ -103,6 +108,9 @@ extern int stmmac_mdio_register(struct net_device *ndev);
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops;
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+extern const struct stmmac_hwtimestamp stmmac_ptp;
+#endif
int stmmac_freeze(struct net_device *ndev);
int stmmac_restore(struct net_device *ndev);
int stmmac_resume(struct net_device *ndev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
new file mode 100644
index 0000000..be9e399
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This implements all the API for managing HW timestamp & PTP.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include "common.h"
+#include "stmmac_ptp.h"
+
+static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
+{
+ writel(data, ioaddr + PTP_TCR);
+}
+
+static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
+{
+ u32 value = readl(ioaddr + PTP_TCR);
+ unsigned long data;
+
+ /* Convert the ptp_clock to nano second
+ * formula = (1/ptp_clock) * 1000000000
+ * where, ptp_clock = 50MHz for FINE correction method &
+ * ptp_clock = STMMAC_SYSCLOCK for COARSE correction method
+ */
+ if (value & PTP_TCR_TSCFUPDT)
+ data = (1000000000ULL / 50000000);
+ else
+ data = (1000000000ULL / STMMAC_SYSCLOCK);
+
+ writel(data, ioaddr + PTP_SSIR);
+}
+
+static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
+{
+ int limit;
+ u32 value;
+
+ /* wait for previous(if any) system time initialize to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
+ break;
+ mdelay(10);
+ }
+
+ if (limit < 0)
+ return -EBUSY;
+
+ writel(sec, ioaddr + PTP_STSUR);
+ writel(nsec, ioaddr + PTP_STNSUR);
+ /* issue command to initialize the system time value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSINIT;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present system time initialize to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
+{
+ u32 value;
+ int limit;
+
+ /* wait for previous (if any) addend update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ writel(addend, ioaddr + PTP_TAR);
+ /* issue command to update the addend value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSADDREG;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present addend update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+const struct stmmac_hwtimestamp stmmac_ptp = {
+ .config_hw_tstamping = stmmac_config_hw_tstamping,
+ .init_systime = stmmac_init_systime,
+ .config_sub_second_increment = stmmac_config_sub_second_increment,
+ .config_addend = stmmac_config_addend,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 260af93..3bbd554 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -47,6 +47,10 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#endif
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+#include <linux/net_tstamp.h>
+#include "stmmac_ptp.h"
+#endif
#include "stmmac.h"
#undef STMMAC_DEBUG
@@ -304,6 +308,192 @@ static void stmmac_eee_adjust(struct stmmac_priv *priv)
priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
}
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+/* stmmac_get_tx_hwtstamp:
+ * @priv : pointer to private device structure.
+ * @p : pointer to desc structure.
+ * @skb : the socket buffer
+ * Description :
+ * This function will read timestamp from the descriptor & pass it to stack.
+ * and also perform some sanity checks.
+ * Return value :
+ * 1 if time stamp is taken & 0 if time stamp is not taken.
+ */
+static unsigned int stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
+ struct dma_desc *p,
+ struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps shhwtstamp;
+ u64 ns;
+
+ if (!priv->hwts_tx_en)
+ return 0;
+
+ /* if skb doesn't support hw tstamp */
+ if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
+ return 0;
+
+ /* check tx tstamp status */
+ if (!priv->hw->desc->get_tx_timestamp_status(p))
+ return 0;
+
+ /* get the valid tstamp */
+ ns = priv->hw->desc->get_timestamp_low(p);
+ /* convert high/sec time stamp value to nanosecond */
+ ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
+
+ memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamp.hwtstamp = ns_to_ktime(ns);
+ /* pass tstamp to stack */
+ skb_tstamp_tx(skb, &shhwtstamp);
+
+ return 1;
+}
+
+/* stmmac_get_rx_hwtstamp:
+ * @priv : pointer to private device structure.
+ * @p : pointer to desc structure.
+ * @skb : the socket buffer
+ * Description :
+ * This function will read received packet's timestamp from the descriptor
+ * and pass it to stack. It also perform some sanity checks.
+ */
+static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
+ struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps *shhwtstamp = NULL;
+ u64 ns;
+
+ if (!priv->hwts_rx_en)
+ return;
+
+ /* if rx tstamp is not valid */
+ if (!priv->hw->desc->get_rx_timestamp_status(p))
+ return;
+
+ /* get valid tstamp */
+ ns = priv->hw->desc->get_timestamp_low(p);
+ /* convert high/sec time stamp value to nanosecond */
+ ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
+ shhwtstamp = skb_hwtstamps(skb);
+ memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamp->hwtstamp = ns_to_ktime(ns);
+}
+
+/**
+ * stmmac_hwtstamp_ioctl - control hardware timestamping.
+ * @dev: device pointer.
+ * @ifr: An IOCTL specefic structure, that can contain a pointer to
+ * a proprietary structure used to pass information to the driver.
+ * Description:
+ * This function configures the MAC to enable/disable both outgoing(TX)
+ * and incoming(RX) packets time stamping based on user input.
+ * Return Value:
+ * 0 on success and an appropriate -ve integer on failure.
+ */
+static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct hwtstamp_config config;
+ struct timespec now;
+ u64 temp = 0;
+
+ if (!priv->dma_cap.time_stamp) {
+ netdev_alert(priv->dev, "No HW time stamping supported\n");
+ priv->hwts_tx_en = 0;
+ priv->hwts_rx_en = 0;
+
+ return -EOPNOTSUPP;
+ }
+
+ if (copy_from_user(&config, ifr->ifr_data,
+ sizeof(struct hwtstamp_config)))
+ return -EFAULT;
+
+ pr_debug("%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
+ __func__, config.flags, config.tx_type, config.rx_filter);
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ priv->hwts_tx_en = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->hwts_tx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+ default:
+ /* PTP v1, UDP, any kind of event packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ break;
+ }
+ priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
+
+ if (!priv->hwts_tx_en && !priv->hwts_rx_en)
+ priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
+ else {
+ priv->hw->ptp->config_hw_tstamping(priv->ioaddr,
+ (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT));
+
+ /* program Sub Second Increment reg */
+ priv->hw->ptp->config_sub_second_increment(priv->ioaddr);
+
+ /* calculate default added value:
+ * formula is :
+ * addend = (2^32)/freq_div_ratio;
+ * where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz
+ * hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK;
+ * NOTE: STMMAC_SYSCLOCK should be >= 50MHz to
+ * achive 20ns accuracy.
+ *
+ * 2^x * y == (y << x), hence
+ * 2^32 * 50000000 ==> (50000000 << 32)
+ */
+ temp = (u64)(50000000ULL << 32);
+ priv->default_addend = div_u64(temp, STMMAC_SYSCLOCK);
+ priv->hw->ptp->config_addend(priv->ioaddr,
+ priv->default_addend);
+
+ /* initialize system time */
+ getnstimeofday(&now);
+ priv->hw->ptp->init_systime(priv->ioaddr, now.tv_sec,
+ now.tv_nsec);
+ }
+
+ return copy_to_user(ifr->ifr_data, &config,
+ sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
+}
+
+static void stmmac_init_ptp(struct stmmac_priv *priv)
+{
+ if (priv->dma_cap.time_stamp)
+ pr_debug("IEEE 1588-2002 Time Stamp supported\n");
+ if (priv->dma_cap.atime_stamp)
+ pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
+
+ priv->hw->ptp = &stmmac_ptp;
+
+ priv->hwts_tx_en = 0;
+ priv->hwts_rx_en = 0;
+
+}
+#else
+#define stmmac_hwtstamp_ioctl(dev, ifr) (-EOPNOTSUPP)
+#define stmmac_get_rx_hwtstamp(priv, p, skb)
+#define stmmac_get_tx_hwtstamp(priv, p, skb) 0
+#define stmmac_init_ptp(priv)
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+
/**
* stmmac_adjust_link
* @dev: net device structure
@@ -712,6 +902,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
while (priv->dirty_tx != priv->cur_tx) {
int last;
+ unsigned int ts = 0;
unsigned int entry = priv->dirty_tx % txsize;
struct sk_buff *skb = priv->tx_skbuff[entry];
struct dma_desc *p = priv->dma_tx + entry;
@@ -732,6 +923,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
priv->xstats.tx_pkt_n++;
} else
priv->dev->stats.tx_errors++;
+
+ ts = stmmac_get_tx_hwtstamp(priv, p, skb);
}
TX_DBG("%s: curr %d, dirty %d\n", __func__,
priv->cur_tx, priv->dirty_tx);
@@ -743,7 +936,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
DMA_TO_DEVICE);
priv->tx_skbuff_dma[entry] = 0;
}
- priv->hw->ring->clean_desc3(p);
+ priv->hw->ring->clean_desc3(priv, p, ts);
if (likely(skb != NULL)) {
dev_kfree_skb(skb);
@@ -1027,6 +1220,7 @@ static int stmmac_open(struct net_device *dev)
goto open_error;
}
+
/* Create and initialize the TX/RX descriptors chains. */
priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
@@ -1093,6 +1287,8 @@ static int stmmac_open(struct net_device *dev)
stmmac_mmc_setup(priv);
+ stmmac_init_ptp(priv);
+
#ifdef CONFIG_STMMAC_DEBUG_FS
ret = stmmac_init_fs(dev);
if (ret < 0)
@@ -1325,7 +1521,17 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
- skb_tx_timestamp(skb);
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ priv->hwts_tx_en)) {
+ /* declare that device is doing timestamping */
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+ priv->hw->desc->enable_tx_timestamp(first);
+ }
+
+ if (!priv->hwts_tx_en)
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+ skb_tx_timestamp(skb);
priv->hw->dma->enable_dma_transmission(priv->ioaddr);
@@ -1357,8 +1563,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
(p + entry)->des2 = priv->rx_skbuff_dma[entry];
- if (unlikely(priv->plat->has_gmac))
- priv->hw->ring->refill_desc3(bfsize, p + entry);
+ priv->hw->ring->refill_desc3(priv, p + entry);
RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
}
@@ -1398,9 +1603,22 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
/* read the status of the incoming frame */
status = (priv->hw->desc->rx_status(&priv->dev->stats,
&priv->xstats, p));
- if (unlikely(status == discard_frame))
+ if (unlikely(status == discard_frame)) {
priv->dev->stats.rx_errors++;
- else {
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ if (priv->hwts_rx_en) {
+ /* DESC2 & DESC3 will be overwitten by device
+ * with timestamp value, hence reinitialize
+ * them in stmmac_rx_refill() function so that
+ * device can reuse it.
+ */
+ priv->rx_skbuff[entry] = NULL;
+ dma_unmap_single(priv->device,
+ priv->rx_skbuff_dma[entry],
+ priv->dma_buf_sz, DMA_FROM_DEVICE);
+ }
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+ } else {
struct sk_buff *skb;
int frame_len;
@@ -1429,6 +1647,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
prefetch(skb->data - NET_IP_ALIGN);
priv->rx_skbuff[entry] = NULL;
+ stmmac_get_rx_hwtstamp(priv, p, skb);
+
skb_put(skb, frame_len);
dma_unmap_single(priv->device,
priv->rx_skbuff_dma[entry],
@@ -1666,21 +1886,30 @@ static void stmmac_poll_controller(struct net_device *dev)
* a proprietary structure used to pass information to the driver.
* @cmd: IOCTL command
* Description:
- * Currently there are no special functionality supported in IOCTL, just the
- * phy_mii_ioctl(...) can be invoked.
+ * Currently it supports just the phy_mii_ioctl(...) and HW time stamping.
*/
static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct stmmac_priv *priv = netdev_priv(dev);
- int ret;
+ int ret = -EOPNOTSUPP;
if (!netif_running(dev))
return -EINVAL;
- if (!priv->phydev)
- return -EINVAL;
-
- ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ if (!priv->phydev)
+ return -EINVAL;
+ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+ break;
+ case SIOCSHWTSTAMP:
+ ret = stmmac_hwtstamp_ioctl(dev, rq);
+ break;
+ default:
+ break;
+ }
return ret;
}
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 0000000..d557696
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ PTP Header file
+
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+******************************************************************************/
+
+#ifndef __STMMAC_PTP_H__
+#define __STMMAC_PTP_H__
+
+#define STMMAC_SYSCLOCK 62500000
+
+/* IEEE 1588 PTP register offsets */
+#define PTP_TCR 0x0700 /* Timestamp Control Reg */
+#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */
+#define PTP_STSR 0x0708 /* System Time – Seconds Regr */
+#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */
+#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */
+#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */
+#define PTP_TAR 0x0718 /* Timestamp Addend Reg */
+#define PTP_TTSR 0x071C /* Target Time Seconds Reg */
+#define PTP_TTNSR 0x0720 /* Target Time Nanoseconds Reg */
+#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
+#define PTP_TSR 0x0728 /* Timestamp Status */
+
+/* PTP TCR defines */
+#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
+#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
+#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */
+#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */
+/* Timestamp Interrupt Trigger Enable */
+#define PTP_TCR_TSTRIG 0x00000010
+#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */
+#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */
+/* Timestamp Digital or Binary Rollover Control */
+#define PTP_TCR_TSCTRLSSR 0x00000200
+
+/* Enable PTP packet Processing for Version 2 Format */
+#define PTP_TCR_TSVER2ENA 0x00000400
+/* Enable Processing of PTP over Ethernet Frames */
+#define PTP_TCR_TSIPENA 0x00000800
+/* Enable Processing of PTP Frames Sent over IPv6-UDP */
+#define PTP_TCR_TSIPV6ENA 0x00001000
+/* Enable Processing of PTP Frames Sent over IPv4-UDP */
+#define PTP_TCR_TSIPV4ENA 0x00002000
+/* Enable Timestamp Snapshot for Event Messages */
+#define PTP_TCR_TSEVNTENA 0x00004000
+/* Enable Snapshot for Messages Relevant to Master */
+#define PTP_TCR_TSMSTRENA 0x00008000
+/* Select PTP packets for Taking Snapshots */
+#define PTP_TCR_SNAPTYPSEL_1 0x00010000
+/* Enable MAC address for PTP Frame Filtering */
+#define PTP_TCR_TSENMACADDR 0x00040000
+
+#endif /* __STMMAC_PTP_H__ */
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 3/9] stmmac: support extend descriptors
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 1/9] stmmac: add tx_skbuff_dma to save descriptors used by PTP Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 4/9] stmmac: add the support for PTP hw clock driver Giuseppe CAVALLARO
` (7 subsequent siblings)
10 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro, Rayagond Kokatanur
This patch adds a new driver Koption to support the
extend descriptors available in the chips newer than
the 3.50. In case of the extend descriptors cannot be
supported, at runtime, the probe function will fail.
This support extends the descriptor structure adding
the desc 4, 5, 6, 7 and give us extra information about
the received ethernet payload when it is carrying PTP
packets or TCP/UDP/ICMP over IP packets.
This introduce a small overhead in the receive process
so actually useful to debug and tack some important
fields in the descriptors.
Moreover, this support will be mandatory to have the
PTP version 2 where the extra descriptors 6 and 7
will be used to save the timestamp on enhanced
descriptor structure.
Thanks to Rayagond Kokatanur that sent me some parts
of this code inside the PTPv2 patches.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Cc: Rayagond Kokatanur <rayagond@vayavyalabs.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 13 +++++
drivers/net/ethernet/stmicro/stmmac/common.h | 29 +++++++++-
drivers/net/ethernet/stmicro/stmmac/descs.h | 47 +++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 1 +
.../net/ethernet/stmicro/stmmac/dwmac1000_dma.c | 8 ++-
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c | 4 +-
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 58 +++++++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 2 +-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 25 +++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 38 ++++++++++---
11 files changed, 206 insertions(+), 20 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index ef703b3..4fa974c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -83,4 +83,17 @@ config STMMAC_USE_HWSTAMP
register will be used to verify if either the IEEE 1588-2008 Advanced
Timestamping (PTPv2) or IEEE 1588-2002 (PTPv1) is actually supported.
+config STMMAC_EXTENDED_DESC
+ bool "Enable Extended descriptors (DES4-5-6-7)"
+ depends on STMMAC_ETH
+ default n
+ ---help---
+ This option enhances the descriptors to support the extended status
+ that gives some information about the receive Ethernet payload when
+ it is carrying PTP packets or TCP/UDP/ICMP over IP.
+ This option cannot be used on GMAC Synopsys older than the 3.50
+ so the driver's probe will fail in this scenario.
+ This option also is mandatory for PTPv2 because the extra descriptors
+ are used for saving timestamps.
+
endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index fa8ff9b..df7123a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -117,6 +117,31 @@ struct stmmac_extra_stats {
unsigned long irq_rx_path_in_lpi_mode_n;
unsigned long irq_rx_path_exit_lpi_mode_n;
unsigned long phy_eee_wakeup_error_n;
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* Extended RDES status */
+ unsigned long ip_hdr_err;
+ unsigned long ip_payload_err;
+ unsigned long ip_csum_bypassed;
+ unsigned long ipv4_pkt_rcvd;
+ unsigned long ipv6_pkt_rcvd;
+ unsigned long rx_msg_type_ext_no_ptp;
+ unsigned long rx_msg_type_sync;
+ unsigned long rx_msg_type_follow_up;
+ unsigned long rx_msg_type_delay_req;
+ unsigned long rx_msg_type_delay_resp;
+ unsigned long rx_msg_type_pdelay_req;
+ unsigned long rx_msg_type_pdelay_resp;
+ unsigned long rx_msg_type_pdelay_follow_up;
+ unsigned long ptp_frame_type;
+ unsigned long ptp_ver;
+ unsigned long timestamp_dropped;
+ unsigned long av_pkt_rcvd;
+ unsigned long av_tagged_pkt_rcvd;
+ unsigned long vlan_tag_priority_val;
+ unsigned long l3_filter_match;
+ unsigned long l4_filter_match;
+ unsigned long l3_l4_filter_no_match;
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
};
/* CSR Frequency Access Defines*/
@@ -289,7 +314,7 @@ struct stmmac_desc_ops {
int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type);
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p);
+ struct dma_desc *p, int atds);
/* Set tx timestamp enable bit */
void (*enable_tx_timestamp) (struct dma_desc *p);
/* get tx timestamp status */
@@ -305,7 +330,7 @@ struct stmmac_desc_ops {
struct stmmac_dma_ops {
/* DMA core initialization */
int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
- int burst_len, u32 dma_tx, u32 dma_rx);
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds);
/* Dump DMA registers */
void (*dump_regs) (void __iomem *ioaddr);
/* Set tx/rx threshold in the csr6 register
diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
index 223adf9..c3e8fe4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
@@ -60,7 +60,7 @@ struct dma_desc {
} rx;
struct {
/* RDES0 */
- u32 payload_csum_error:1;
+ u32 rx_mac_addr:1;
u32 crc_error:1;
u32 dribbling:1;
u32 error_gmii:1;
@@ -160,15 +160,56 @@ struct dma_desc {
} des01;
unsigned int des2;
unsigned int des3;
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ union {
+ struct {
+ u32 ip_payload_type:3;
+ u32 ip_hdr_err:1;
+ u32 ip_payload_err:1;
+ u32 ip_csum_bypassed:1;
+ u32 ipv4_pkt_rcvd:1;
+ u32 ipv6_pkt_rcvd:1;
+ u32 msg_type:4;
+ u32 ptp_frame_type:1;
+ u32 ptp_ver:1;
+ u32 timestamp_dropped:1;
+ u32 reserved:1;
+ u32 av_pkt_rcvd:1;
+ u32 av_tagged_pkt_rcvd:1;
+ u32 vlan_tag_priority_val:3;
+ u32 reserved3:3;
+ u32 l3_filter_match:1;
+ u32 l4_filter_match:1;
+ u32 l3_l4_filter_no_match:2;
+ u32 reserved4:4;
+ } erx;
+ struct {
+ u32 reserved;
+ } etx;
+ } des4;
+ unsigned int des5; /* Reserved */
+ unsigned int des6; /* Tx/Rx Timestamp Low */
+ unsigned int des7; /* Tx/Rx Timestamp High */
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
};
/* Transmit checksum insertion control */
enum tdes_csum_insertion {
cic_disabled = 0, /* Checksum Insertion Control */
cic_only_ip = 1, /* Only IP header */
- cic_no_pseudoheader = 2, /* IP header but pseudoheader
- * is not calculated */
+ /* IP header but pseudoheader is not calculated */
+ cic_no_pseudoheader = 2,
cic_full = 3, /* IP header and pseudoheader */
};
+/* Extended RDES4 definitions */
+#define RDES_EXT_NO_PTP 0
+#define RDES_EXT_SYNC 0x1
+#define RDES_EXT_FOLLOW_UP 0x2
+#define RDES_EXT_DELAY_REQ 0x3
+#define RDES_EXT_DELAY_RESP 0x4
+#define RDES_EXT_PDELAY_REQ 0x5
+#define RDES_EXT_PDELAY_RESP 0x6
+#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
+
#endif /* __DESCS_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 7ad56af..85466e5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -155,6 +155,7 @@ enum inter_frame_gap {
/* Programmable burst length (passed thorugh platform)*/
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
#define DMA_BUS_MODE_PBL_SHIFT 8
+#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
enum rx_tx_priority_ratio {
double_ratio = 0x00004000, /*2:1 */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index bf83c03..f1c4b2c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -30,8 +30,8 @@
#include "dwmac1000.h"
#include "dwmac_dma.h"
-static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
- int mb, int burst_len, u32 dma_tx, u32 dma_rx)
+static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
@@ -73,6 +73,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
#ifdef CONFIG_STMMAC_DA
value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
#endif
+
+ if (atds)
+ value |= DMA_BUS_MODE_ATDS;
+
writel(value, ioaddr + DMA_BUS_MODE);
/* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
index c2b4d55..e979a8b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
@@ -32,8 +32,8 @@
#include "dwmac100.h"
#include "dwmac_dma.h"
-static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb,
- int mb, int burst_len, u32 dma_tx, u32 dma_rx)
+static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
+ int burst_len, u32 dma_tx, u32 dma_rx, int atds)
{
u32 value = readl(ioaddr + DMA_BUS_MODE);
int limit;
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 4d635d5..50707c5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -150,8 +150,9 @@ static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
return ret;
}
+
static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p)
+ struct dma_desc *p, int atds)
{
int ret = good_frame;
struct net_device_stats *stats = (struct net_device_stats *)data;
@@ -198,7 +199,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
* At any rate, we need to understand if the CSUM hw computation is ok
* and report this info to the upper layers. */
ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
- p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
+ p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
if (unlikely(p->des01.erx.dribbling)) {
CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
@@ -225,6 +226,59 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
x->rx_vlan++;
}
#endif
+
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* On new chips the RDES0[0] is used for looking at the RDES4;
+ * note that atds won't be set for ID older than 3.50.
+ */
+ if (unlikely((atds) && (p->des01.erx.rx_mac_addr))) {
+ if (p->des4.erx.ip_hdr_err)
+ x->ip_hdr_err++;
+ if (p->des4.erx.ip_payload_err)
+ x->ip_payload_err++;
+ if (p->des4.erx.ip_csum_bypassed)
+ x->ip_csum_bypassed++;
+ if (p->des4.erx.ipv4_pkt_rcvd)
+ x->ipv4_pkt_rcvd++;
+ if (p->des4.erx.ipv6_pkt_rcvd)
+ x->ipv6_pkt_rcvd++;
+ if (p->des4.erx.msg_type == RDES_EXT_SYNC)
+ x->rx_msg_type_sync++;
+ else if (p->des4.erx.msg_type == RDES_EXT_FOLLOW_UP)
+ x->rx_msg_type_follow_up++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
+ x->rx_msg_type_delay_req++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)
+ x->rx_msg_type_delay_resp++;
+ else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
+ x->rx_msg_type_pdelay_req++;
+ else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)
+ x->rx_msg_type_pdelay_resp++;
+ else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_FOLLOW_UP)
+ x->rx_msg_type_pdelay_follow_up++;
+ else
+ x->rx_msg_type_ext_no_ptp++;
+ if (p->des4.erx.ptp_frame_type)
+ x->ptp_frame_type++;
+ if (p->des4.erx.ptp_ver)
+ x->ptp_ver++;
+ if (p->des4.erx.timestamp_dropped)
+ x->timestamp_dropped++;
+ if (p->des4.erx.av_pkt_rcvd)
+ x->av_pkt_rcvd++;
+ if (p->des4.erx.av_tagged_pkt_rcvd)
+ x->av_tagged_pkt_rcvd++;
+ if (p->des4.erx.vlan_tag_priority_val)
+ x->vlan_tag_priority_val++;
+ if (p->des4.erx.l3_filter_match)
+ x->l3_filter_match++;
+ if (p->des4.erx.l4_filter_match)
+ x->l4_filter_match++;
+ if (p->des4.erx.l3_l4_filter_no_match)
+ x->l3_l4_filter_no_match++;
+ }
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
+
return ret;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index edb5e88..9eefb6c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -73,7 +73,7 @@ static int ndesc_get_tx_len(struct dma_desc *p)
* In case of success, it returns good_frame because the GMAC device
* is supposed to be able to compute the csum in HW. */
static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
- struct dma_desc *p)
+ struct dma_desc *p, int atds)
{
int ret = good_frame;
struct net_device_stats *stats = (struct net_device_stats *)data;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 665f2a2..50b5f26 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -99,6 +99,7 @@ struct stmmac_priv {
int hwts_rx_en;
unsigned int default_addend;
#endif
+ int atds;
};
extern int phyaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index d1ac39c..5698bf3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -108,6 +108,31 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
STMMAC_STAT(phy_eee_wakeup_error_n),
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* Extended RDES status */
+ STMMAC_STAT(ip_hdr_err),
+ STMMAC_STAT(ip_payload_err),
+ STMMAC_STAT(ip_csum_bypassed),
+ STMMAC_STAT(ipv4_pkt_rcvd),
+ STMMAC_STAT(ipv6_pkt_rcvd),
+ STMMAC_STAT(rx_msg_type_ext_no_ptp),
+ STMMAC_STAT(rx_msg_type_sync),
+ STMMAC_STAT(rx_msg_type_follow_up),
+ STMMAC_STAT(rx_msg_type_delay_req),
+ STMMAC_STAT(rx_msg_type_delay_resp),
+ STMMAC_STAT(rx_msg_type_pdelay_req),
+ STMMAC_STAT(rx_msg_type_pdelay_resp),
+ STMMAC_STAT(rx_msg_type_pdelay_follow_up),
+ STMMAC_STAT(ptp_frame_type),
+ STMMAC_STAT(ptp_ver),
+ STMMAC_STAT(timestamp_dropped),
+ STMMAC_STAT(av_pkt_rcvd),
+ STMMAC_STAT(av_tagged_pkt_rcvd),
+ STMMAC_STAT(vlan_tag_priority_val),
+ STMMAC_STAT(l3_filter_match),
+ STMMAC_STAT(l4_filter_match),
+ STMMAC_STAT(l3_l4_filter_no_match),
+#endif /* CONFIG_STMMAC_EXTENDED_DESC */
};
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3bbd554..6174f34 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1058,15 +1058,29 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv)
* @priv : private structure
* Description: select the Enhanced/Alternate or Normal descriptors
*/
-static void stmmac_selec_desc_mode(struct stmmac_priv *priv)
+static int stmmac_selec_desc_mode(struct stmmac_priv *priv)
{
+ int ret = 0;
+
if (priv->plat->enh_desc) {
pr_info(" Enhanced/Alternate descriptors\n");
+#ifdef CONFIG_STMMAC_EXTENDED_DESC
+ /* GMAC older than 3.50 has no extended descriptors */
+ if (priv->synopsys_id >= DWMAC_CORE_3_50) {
+ pr_info("\tEnabled extended descriptors\n");
+ priv->atds = 1;
+ } else {
+ pr_err("ERROR: cannot support extended descriptors\n");
+ ret = -EOPNOTSUPP;
+ }
+#endif
priv->hw->desc = &enh_desc_ops;
} else {
pr_info(" Normal descriptors\n");
priv->hw->desc = &ndesc_ops;
}
+
+ return ret;
}
/**
@@ -1161,7 +1175,7 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
burst_len, priv->dma_tx_phy,
- priv->dma_rx_phy);
+ priv->dma_rx_phy, priv->atds);
}
/**
@@ -1602,7 +1616,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
/* read the status of the incoming frame */
status = (priv->hw->desc->rx_status(&priv->dev->stats,
- &priv->xstats, p));
+ &priv->xstats, p,
+ priv->atds));
if (unlikely(status == discard_frame)) {
priv->dev->stats.rx_errors++;
#ifdef CONFIG_STMMAC_USE_HWSTAMP
@@ -2117,7 +2132,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
*/
static int stmmac_hw_init(struct stmmac_priv *priv)
{
- int ret = 0;
+ int ret;
struct mac_device_info *mac;
/* Identify the MAC HW device */
@@ -2161,8 +2176,12 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
} else
pr_info(" No HW DMA feature register supported");
- /* Select the enhnaced/normal descriptor structures */
- stmmac_selec_desc_mode(priv);
+ /* Select the enhnaced/normal descriptor structures and return
+ * EOPNOTSUPP in case of failing.
+ */
+ ret = stmmac_selec_desc_mode(priv);
+ if (ret)
+ return ret;
/* Enable the IPC (Checksum Offload) and check if the feature has been
* enabled during the core configuration. */
@@ -2183,7 +2202,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
device_set_wakeup_capable(priv->device, 1);
}
- return ret;
+ return 0;
}
/**
@@ -2229,7 +2248,9 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
priv->plat->phy_addr = phyaddr;
/* Init MAC and get the capabilities */
- stmmac_hw_init(priv);
+ ret = stmmac_hw_init(priv);
+ if (ret)
+ goto error_free_netdev;
ndev->netdev_ops = &stmmac_netdev_ops;
@@ -2300,6 +2321,7 @@ error_clk_get:
unregister_netdev(ndev);
error_netdev_register:
netif_napi_del(&priv->napi);
+error_free_netdev:
free_netdev(ndev);
return NULL;
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 4/9] stmmac: add the support for PTP hw clock driver
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (2 preceding siblings ...)
2013-03-07 10:50 ` [net-next.git 3/9] stmmac: support extend descriptors Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-10 12:10 ` Richard Cochran
2013-03-07 10:50 ` [net-next.git 5/9] stmmac: add IEEE 1588-2008 PTP V2 support Giuseppe CAVALLARO
` (6 subsequent siblings)
10 siblings, 1 reply; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Rayagond Kokatanur
From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
This patch implements PHC (ptp hardware clock) driver for stmmac
driver to support 1588 PTP.
Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Hacked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +-
drivers/net/ethernet/stmicro/stmmac/common.h | 4 +
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 13 ++
.../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 50 +++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +++-
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 209 ++++++++++++++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 2 +
7 files changed, 303 insertions(+), 8 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index cc97c07..40ee3df 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -3,7 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
-stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o
+stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o stmmac_ptp.o
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index df7123a..a10974c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -387,6 +387,10 @@ struct stmmac_hwtimestamp {
void (*config_sub_second_increment) (void __iomem *ioaddr);
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
int (*config_addend)(void __iomem *ioaddr, u32 addend);
+ int (*adjust_systime)(void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub);
+ u32 (*get_systime_sec)(void __iomem *ioaddr);
+ u32 (*get_systime_nsec)(void __iomem *ioaddr);
};
#endif
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 50b5f26..2d6e2e1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -32,6 +32,10 @@
#include <linux/pci.h>
#include "common.h"
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+#include <linux/ptp_clock_kernel.h>
+#endif
+
struct stmmac_priv {
/* Frequently used values are kept adjacent for cache effect */
struct dma_desc *dma_tx ____cacheline_aligned;
@@ -98,6 +102,9 @@ struct stmmac_priv {
int hwts_tx_en;
int hwts_rx_en;
unsigned int default_addend;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_clock_ops;
+ spinlock_t ptp_lock;
#endif
int atds;
};
@@ -111,6 +118,12 @@ extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops;
#ifdef CONFIG_STMMAC_USE_HWSTAMP
extern const struct stmmac_hwtimestamp stmmac_ptp;
+extern int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub);
+extern u32 stmmac_get_systime_sec(void __iomem *ioaddr);
+extern u32 stmmac_get_systime_nsec(void __iomem *ioaddr);
+extern int stmmac_ptp_register(struct stmmac_priv *priv);
+extern void stmmac_ptp_unregister(struct stmmac_priv *priv);
#endif
int stmmac_freeze(struct net_device *ndev);
int stmmac_restore(struct net_device *ndev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
index be9e399..bec2278 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
@@ -121,9 +121,59 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
return 0;
}
+static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
+ int add_sub)
+{
+ u32 value;
+ int limit;
+
+ /* wait for previous(if any) system time adjust/update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ writel(sec, ioaddr + PTP_STSUR);
+ writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
+ ioaddr + PTP_STNSUR);
+ /* issue command to initialize the system time value */
+ value = readl(ioaddr + PTP_TCR);
+ value |= PTP_TCR_TSUPDT;
+ writel(value, ioaddr + PTP_TCR);
+
+ /* wait for present system time adjust/update to complete */
+ limit = 100;
+ while (limit--) {
+ if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
+ break;
+ mdelay(10);
+ }
+ if (limit < 0)
+ return -EBUSY;
+
+ return 0;
+}
+
+static u32 stmmac_get_systime_sec(void __iomem *ioaddr)
+{
+ return readl(ioaddr + PTP_STSR);
+}
+
+static u32 stmmac_get_systime_nsec(void __iomem *ioaddr)
+{
+ return readl(ioaddr + PTP_STNSR);
+}
+
const struct stmmac_hwtimestamp stmmac_ptp = {
.config_hw_tstamping = stmmac_config_hw_tstamping,
.init_systime = stmmac_init_systime,
.config_sub_second_increment = stmmac_config_sub_second_increment,
.config_addend = stmmac_config_addend,
+ .adjust_systime = stmmac_adjust_systime,
+ .get_systime_sec = stmmac_get_systime_sec,
+ .get_systime_nsec = stmmac_get_systime_nsec,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 6174f34..009abf8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -474,24 +474,37 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
}
-static void stmmac_init_ptp(struct stmmac_priv *priv)
+static int stmmac_init_ptp(struct stmmac_priv *priv)
{
- if (priv->dma_cap.time_stamp)
- pr_debug("IEEE 1588-2002 Time Stamp supported\n");
- if (priv->dma_cap.atime_stamp)
- pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
+ if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
+ return -EOPNOTSUPP;
+
+ if (netif_msg_hw(priv)) {
+ if (priv->dma_cap.time_stamp)
+ pr_debug("IEEE 1588-2002 Time Stamp supported\n");
+ if (priv->dma_cap.atime_stamp)
+ pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
+ }
priv->hw->ptp = &stmmac_ptp;
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
+ return stmmac_ptp_register(priv);
+}
+
+static void stmmac_release_ptp(struct stmmac_priv *priv)
+{
+ stmmac_ptp_unregister(priv);
}
+
#else
#define stmmac_hwtstamp_ioctl(dev, ifr) (-EOPNOTSUPP)
#define stmmac_get_rx_hwtstamp(priv, p, skb)
#define stmmac_get_tx_hwtstamp(priv, p, skb) 0
-#define stmmac_init_ptp(priv)
+#define stmmac_init_ptp(priv) 0
+#define stmmac_release_ptp(priv)
#endif /* CONFIG_STMMAC_USE_HWSTAMP */
/**
@@ -1301,7 +1314,9 @@ static int stmmac_open(struct net_device *dev)
stmmac_mmc_setup(priv);
- stmmac_init_ptp(priv);
+ ret = stmmac_init_ptp(priv);
+ if (ret)
+ pr_warn("%s: failed PTP initialisation\n", __func__);
#ifdef CONFIG_STMMAC_DEBUG_FS
ret = stmmac_init_fs(dev);
@@ -1403,6 +1418,8 @@ static int stmmac_release(struct net_device *dev)
#endif
clk_disable_unprepare(priv->stmmac_clk);
+ stmmac_release_ptp(priv);
+
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
new file mode 100644
index 0000000..53680bf
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ PTP 1588 clock using the STMMAC.
+
+ Copyright (C) 2013 Vayavya Labs Pvt Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
+*******************************************************************************/
+#include "stmmac.h"
+#include "stmmac_ptp.h"
+
+/**
+ * stmmac_adjust_freq
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ppb: desired period change in parts ber billion
+ *
+ * Description: this function will adjust the frequency of hardware clock.
+ */
+static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ u32 diff, addend;
+ int neg_adj = 0;
+ u64 adj;
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+
+ addend = priv->default_addend;
+ adj = addend;
+ adj *= ppb;
+ /* div_u64 will divided the "adj" by "1000000000ULL"
+ * and return the quotient
+ */
+ diff = div_u64(adj, 1000000000ULL);
+
+ addend = neg_adj ? (addend - diff) : (addend + diff);
+
+ priv->hw->ptp->config_addend(priv->ioaddr, addend);
+
+ return 0;
+}
+
+/**
+ * stmmac_adjust_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @delta: desired change in nanoseconds
+ *
+ * Description: this function will shift/adjust the hardware clock time.
+ */
+static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+ u32 sec, nsec;
+ u32 quotient, reminder;
+ int neg_adj = 0;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ if (delta < 0) {
+ neg_adj = 1;
+ delta = -delta;
+ }
+
+ quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
+ sec = quotient;
+ nsec = reminder;
+ priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/**
+ * stmmac_get_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ts: pointer to hold time/result
+ *
+ * Description: this function will read the current time from the
+ * hardware clock and store it in @ts.
+ */
+static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ ts->tv_sec = priv->hw->ptp->get_systime_sec(priv->ioaddr);
+ ts->tv_nsec = priv->hw->ptp->get_systime_nsec(priv->ioaddr);
+
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ return 0;
+}
+
+/**
+ * stmmac_set_time
+ *
+ * @ptp: pointer to ptp_clock_info structure
+ * @ts: time value to set
+ *
+ * Description: this function will set the current time on the
+ * hardware clock.
+ */
+static int stmmac_set_time(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ struct stmmac_priv *priv =
+ container_of(ptp, struct stmmac_priv, ptp_clock_ops);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->ptp_lock, flags);
+
+ priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
+
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ return 0;
+}
+
+static int stmmac_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+/* structure describing a PTP hardware clock */
+static struct ptp_clock_info stmmac_ptp_clock_ops = {
+ .owner = THIS_MODULE,
+ .name = "stmmac_ptp_clock",
+ .max_adj = STMMAC_SYSCLOCK,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .adjfreq = stmmac_adjust_freq,
+ .adjtime = stmmac_adjust_time,
+ .gettime = stmmac_get_time,
+ .settime = stmmac_set_time,
+ .enable = stmmac_enable,
+};
+
+/**
+ * stmmac_ptp_register
+ *
+ * @ndev: net device pointer
+ *
+ * Description: this function will register the ptp clock driver
+ * to kernel. It also does some house keeping work.
+ */
+int stmmac_ptp_register(struct stmmac_priv *priv)
+{
+ spin_lock_init(&priv->ptp_lock);
+ priv->ptp_clock_ops = stmmac_ptp_clock_ops;
+
+ priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
+ priv->device);
+ if (IS_ERR(priv->ptp_clock)) {
+ priv->ptp_clock = NULL;
+ pr_err("ptp_clock_register() failed on %s\n", priv->dev->name);
+ } else
+ pr_debug("Added PTP HW clock successfully on %s\n",
+ priv->dev->name);
+
+ return 0;
+}
+
+/**
+ * stmmac_ptp_unregister
+ *
+ * @ndev: net device pointer
+ *
+ * Description: this function will remove/unregister the ptp clock driver
+ * from the kernel.
+ */
+void stmmac_ptp_unregister(struct stmmac_priv *priv)
+{
+ if (priv->ptp_clock) {
+ ptp_clock_unregister(priv->ptp_clock);
+ pr_debug("Removed PTP HW clock successfully on %s\n",
+ priv->dev->name);
+ }
+}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index d557696..3dbc047 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -40,6 +40,8 @@
#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
#define PTP_TSR 0x0728 /* Timestamp Status */
+#define PTP_STNSUR_ADDSUB_SHIFT 31
+
/* PTP TCR defines */
#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 5/9] stmmac: add IEEE 1588-2008 PTP V2 support
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (3 preceding siblings ...)
2013-03-07 10:50 ` [net-next.git 4/9] stmmac: add the support for PTP hw clock driver Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info Giuseppe CAVALLARO
` (5 subsequent siblings)
10 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Rayagond Kokatanur
From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
This patch enhances the stmmac driver to support IEEE 1588-2008 PTP v2
timestamping.
Basic TimeStamps (IEEE 1588-2002 Precision Time Protocol) is selected
by using the STMMAC_USE_HWSTAMP option and at run-time, thanks to
the HW capability register, we verify if the support can be used.
This "basic" TimeStamp support can be used on chips that have the
normal descriptor structures.
To support the IEEE 1588-2008 Precision Time Protocol (Advanced
TimeStamping) the HW has to be the Extended descriptors (DES4-5-6-7)
so this is firtly solved by Kconfig and at runtime all is verified
according to the HW capability register.
Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
Hacked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 24 ++-
drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 26 ++-
drivers/net/ethernet/stmicro/stmmac/common.h | 10 +-
drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 39 +++--
drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 10 +-
drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 3 +-
.../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 4 +
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 192 +++++++++++++++++---
8 files changed, 242 insertions(+), 66 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 4fa974c..cdd63a5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -72,16 +72,32 @@ config STMMAC_CHAINED
endchoice
config STMMAC_USE_HWSTAMP
- bool "Use IEEE 1588 Precision Time Protocol"
+ bool "IEEE 1588-2002 Precision Time Protocol (HW TimeStamping)"
depends on STMMAC_ETH
select PTP_1588_CLOCK
default n
---help---
- Enable this option to support the IEEE 1588 Precision Time Protocol
- (PTP) and HW Timestamps.
+ Enable this option to support the IEEE 1588-2008 Precision Time
+ Protocol (PTP) and HW Timestamps.
+ At runtime, on new chip generations, the hardware capability
+ register will be used to verify if IEEE 1588-2002 is actually
+ supported.
+ This mode can be also supported by chip with normal descriptor
+ structures and w/o Extended descriptors.
+
+config STMMAC_USE_HW_A_STAMP
+ bool "IEEE 1588-2008 Precision Time Protocol (Advanced TimeStamping)"
+ depends on STMMAC_ETH
+ select STMMAC_USE_HWSTAMP
+ select STMMAC_EXTENDED_DESC
+ default n
+ ---help---
+ Enable this option to support the IEEE 1588-2008 Precision Time
+ Protocol (PTP) Advanced HW Timestamps.
At runtime, on new chip generations, the hardware capability
register will be used to verify if either the IEEE 1588-2008 Advanced
- Timestamping (PTPv2) or IEEE 1588-2002 (PTPv1) is actually supported.
+ Timestamping. To support this, it is mandatory to have the extended
+ descriptor support.
config STMMAC_EXTENDED_DESC
bool "Enable Extended descriptors (DES4-5-6-7)"
diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
index dd60f6b..61e870f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
@@ -94,6 +94,7 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
{
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
if (priv->hwts_rx_en)
@@ -101,26 +102,29 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
* 1588-2002 time stamping is enabled, hence reinitialize it
* to keep explicit chaining in the descriptor.
*/
- p->des3 = (unsigned int)(priv->dma_rx +
- ((priv->dirty_rx) + 1) % priv->dma_rx_size);
+ p->des3 = (unsigned int)(priv->dma_rx_phy +
+ (((priv->dirty_rx) + 1) %
+ priv->dma_rx_size) *
+ sizeof(struct dma_desc));
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
}
static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
{
}
-static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
- int tstamp_taken)
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
{
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
- if (tstamp_taken && priv->hw->desc->get_tx_ls(p))
- /* NOTE: Device will overwrite des3 with timestamp value if
- * 1588-2002 time stamping is enabled, hence reinitialize it
- * to keep explicit chaining in the descriptor.
- */
- p->des3 = (unsigned int)(priv->dma_tx +
- ((priv->dirty_tx + 1) % priv->dma_tx_size));
+ if (priv->hwts_tx_en && priv->hw->desc->get_tx_ls(p)
+ && !priv->dma_cap.atime_stamp)
+ p->des3 = (unsigned int)(priv->dma_tx_phy +
+ (((priv->dirty_tx + 1) %
+ priv->dma_tx_size) *
+ sizeof(struct dma_desc)));
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
}
static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index a10974c..f5965b6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -315,16 +315,18 @@ struct stmmac_desc_ops {
/* Return the reception status looking at the RDES1 */
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
struct dma_desc *p, int atds);
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
/* Set tx timestamp enable bit */
void (*enable_tx_timestamp) (struct dma_desc *p);
/* get tx timestamp status */
int (*get_tx_timestamp_status) (struct dma_desc *p);
/* get tx/rx timestamp low value */
- u32 (*get_timestamp_low) (struct dma_desc *p);
+ u32 (*get_timestamp_low) (struct dma_desc *p, u32 ats);
/* get tx/rx timestamp high value */
- u32 (*get_timestamp_high) (struct dma_desc *p);
+ u32 (*get_timestamp_high) (struct dma_desc *p, u32 ats);
/* get rx timestamp status */
- int (*get_rx_timestamp_status) (struct dma_desc *p);
+ int (*get_rx_timestamp_status) (struct dma_desc *p, u32 ats);
+#endif
};
struct stmmac_dma_ops {
@@ -412,7 +414,7 @@ struct stmmac_ring_mode_ops {
void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
unsigned int size);
- void (*clean_desc3) (void *priv, struct dma_desc *p, int tstamp_taken);
+ void (*clean_desc3) (void *priv, struct dma_desc *p);
int (*set_16kib_bfsize) (int mtu);
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
index 50707c5..581f82b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
@@ -377,6 +377,7 @@ static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.erx.frame_length;
}
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
{
p->des01.etx.time_stamp_enable = 1;
@@ -387,27 +388,39 @@ static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
return p->des01.etx.time_stamp_status;
}
-static u32 enh_desc_get_timestamp_low(struct dma_desc *p)
+static u32 enh_desc_get_timestamp_low(struct dma_desc *p, u32 ats)
{
- /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
- return p->des2;
+#ifdef CONFIG_STMMAC_USE_HW_A_STAMP
+ if (ats)
+ return p->des6;
+ else
+#endif /* CONFIG_STMMAC_USE_HW_A_STAMP */
+ return p->des2;
}
-static u32 enh_desc_get_timestamp_high(struct dma_desc *p)
+static u32 enh_desc_get_timestamp_high(struct dma_desc *p, u32 ats)
{
- /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
- return p->des3;
+#ifdef CONFIG_STMMAC_USE_HW_A_STAMP
+ if (ats)
+ return p->des7;
+ else
+#endif /* CONFIG_STMMAC_USE_HW_A_STAMP */
+ return p->des2;
}
-static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
+static int enh_desc_get_rx_timestamp_status(struct dma_desc *p, u32 ats)
{
- /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
- if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ if (ats)
+ return p->des01.erx.ipc_csum_error;
+ else {
/* timestamp is currupted, hence don't store it */
- return 0;
- else
- return 1;
+ if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
+ return 0;
+ else
+ return 1;
+ }
}
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
const struct stmmac_desc_ops enh_desc_ops = {
.tx_status = enh_desc_get_tx_status,
@@ -425,9 +438,11 @@ const struct stmmac_desc_ops enh_desc_ops = {
.set_tx_owner = enh_desc_set_tx_owner,
.set_rx_owner = enh_desc_set_rx_owner,
.get_rx_frame_len = enh_desc_get_rx_frame_len,
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
.get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
.get_timestamp_low = enh_desc_get_timestamp_low,
.get_timestamp_high = enh_desc_get_timestamp_high,
.get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
+#endif
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
index 9eefb6c..3770942 100644
--- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
+++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
@@ -215,6 +215,7 @@ static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
return p->des01.rx.frame_length;
}
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
static void ndesc_enable_tx_timestamp(struct dma_desc *p)
{
p->des01.tx.time_stamp_enable = 1;
@@ -225,17 +226,17 @@ static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
return p->des01.tx.time_stamp_status;
}
-static u32 ndesc_get_timestamp_low(struct dma_desc *p)
+static u32 ndesc_get_timestamp_low(struct dma_desc *p, u32 ats)
{
return p->des2;
}
-static u32 ndesc_get_timestamp_high(struct dma_desc *p)
+static u32 ndesc_get_timestamp_high(struct dma_desc *p, u32 ats)
{
return p->des3;
}
-static int ndesc_get_rx_timestamp_status(struct dma_desc *p)
+static int ndesc_get_rx_timestamp_status(struct dma_desc *p, u32 ats)
{
if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
/* timestamp is currupted, hence don't store it */
@@ -243,6 +244,7 @@ static int ndesc_get_rx_timestamp_status(struct dma_desc *p)
else
return 1;
}
+#endif
const struct stmmac_desc_ops ndesc_ops = {
.tx_status = ndesc_get_tx_status,
@@ -260,9 +262,11 @@ const struct stmmac_desc_ops ndesc_ops = {
.set_tx_owner = ndesc_set_tx_owner,
.set_rx_owner = ndesc_set_rx_owner,
.get_rx_frame_len = ndesc_get_rx_frame_len,
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
.enable_tx_timestamp = ndesc_enable_tx_timestamp,
.get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
.get_timestamp_low = ndesc_get_timestamp_low,
.get_timestamp_high = ndesc_get_timestamp_high,
.get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
+#endif
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
index 94a1c2f..fbcc454 100644
--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
@@ -108,8 +108,7 @@ static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
{
}
-static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
- int tstamp_taken)
+static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
{
if (unlikely(p->des3))
p->des3 = 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
index bec2278..5c71836 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
@@ -48,6 +48,10 @@ static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
else
data = (1000000000ULL / STMMAC_SYSCLOCK);
+ /* 0.465ns accuracy */
+ if (value & PTP_TCR_TSCTRLSSR)
+ data = (data * 100) / 465;
+
writel(data, ioaddr + PTP_SSIR);
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 009abf8..ae92191 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -316,38 +316,36 @@ static void stmmac_eee_adjust(struct stmmac_priv *priv)
* Description :
* This function will read timestamp from the descriptor & pass it to stack.
* and also perform some sanity checks.
- * Return value :
- * 1 if time stamp is taken & 0 if time stamp is not taken.
*/
-static unsigned int stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
- struct dma_desc *p,
- struct sk_buff *skb)
+static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
+ struct sk_buff *skb)
{
struct skb_shared_hwtstamps shhwtstamp;
+ u32 ats = priv->dma_cap.atime_stamp;
u64 ns;
if (!priv->hwts_tx_en)
- return 0;
+ return;
/* if skb doesn't support hw tstamp */
if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
- return 0;
+ return;
/* check tx tstamp status */
if (!priv->hw->desc->get_tx_timestamp_status(p))
- return 0;
+ return;
/* get the valid tstamp */
- ns = priv->hw->desc->get_timestamp_low(p);
+ ns = priv->hw->desc->get_timestamp_low(p, ats);
/* convert high/sec time stamp value to nanosecond */
- ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
+ ns += (priv->hw->desc->get_timestamp_high(p, ats) * 1000000000ULL);
memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
shhwtstamp.hwtstamp = ns_to_ktime(ns);
/* pass tstamp to stack */
skb_tstamp_tx(skb, &shhwtstamp);
- return 1;
+ return;
}
/* stmmac_get_rx_hwtstamp:
@@ -362,19 +360,20 @@ static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
struct sk_buff *skb)
{
struct skb_shared_hwtstamps *shhwtstamp = NULL;
+ u32 ats = priv->dma_cap.atime_stamp;
u64 ns;
if (!priv->hwts_rx_en)
return;
/* if rx tstamp is not valid */
- if (!priv->hw->desc->get_rx_timestamp_status(p))
+ if (!priv->hw->desc->get_rx_timestamp_status(p, ats))
return;
/* get valid tstamp */
- ns = priv->hw->desc->get_timestamp_low(p);
+ ns = priv->hw->desc->get_timestamp_low(p, ats);
/* convert high/sec time stamp value to nanosecond */
- ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
+ ns += (priv->hw->desc->get_timestamp_high(p, ats) * 1000000000ULL);
shhwtstamp = skb_hwtstamps(skb);
memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
shhwtstamp->hwtstamp = ns_to_ktime(ns);
@@ -397,8 +396,17 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
struct hwtstamp_config config;
struct timespec now;
u64 temp = 0;
-
- if (!priv->dma_cap.time_stamp) {
+ u32 ptp_v2 = 0;
+ u32 tstamp_all = 0;
+ u32 ptp_over_ipv4_udp = 0;
+ u32 ptp_over_ipv6_udp = 0;
+ u32 ptp_over_ethernet = 0;
+ u32 snap_type_sel = 0;
+ u32 ts_master_en = 0;
+ u32 ts_event_en = 0;
+ u32 value = 0;
+
+ if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) {
netdev_alert(priv->dev, "No HW time stamping supported\n");
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
@@ -428,22 +436,147 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
return -ERANGE;
}
- switch (config.rx_filter) {
- case HWTSTAMP_FILTER_NONE:
- config.rx_filter = HWTSTAMP_FILTER_NONE;
- break;
- default:
+ if (priv->dma_cap.atime_stamp) {
+ switch (config.rx_filter) {
+ /* time stamp no incoming packet at all */
+ case HWTSTAMP_FILTER_NONE:
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+
/* PTP v1, UDP, any kind of event packet */
- config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
- break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ /* take time stamp for all event messages */
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ /* PTP v1, UDP, Sync packet */
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
+ /* take time stamp for SYNC messages only */
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ /* PTP v1, UDP, Delay_req packet */
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
+ /* take time stamp for Delay_Req messages only */
+ ts_master_en = PTP_TCR_TSMSTRENA;
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ /* PTP v2, UDP, any kind of event packet */
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for all event messages */
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ /* PTP v2, UDP, Sync packet */
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for SYNC messages only */
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ /* PTP v2, UDP, Delay_req packet */
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for Delay_Req messages only */
+ ts_master_en = PTP_TCR_TSMSTRENA;
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ break;
+
+ /* PTP v2/802.AS1, any layer, any kind of event packet */
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for all event messages */
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ ptp_over_ethernet = PTP_TCR_TSIPENA;
+ break;
+
+ /* PTP v2/802.AS1, any layer, Sync packet */
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for SYNC messages only */
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ ptp_over_ethernet = PTP_TCR_TSIPENA;
+ break;
+
+ /* PTP v2/802.AS1, any layer, Delay_req packet */
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
+ ptp_v2 = PTP_TCR_TSVER2ENA;
+ /* take time stamp for Delay_Req messages only */
+ ts_master_en = PTP_TCR_TSMSTRENA;
+ ts_event_en = PTP_TCR_TSEVNTENA;
+
+ ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
+ ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
+ ptp_over_ethernet = PTP_TCR_TSIPENA;
+ break;
+
+ /* time stamp any incoming packet */
+ case HWTSTAMP_FILTER_ALL:
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ tstamp_all = PTP_TCR_TSENALL;
+ break;
+
+ default:
+ return -ERANGE;
+ }
+ } else {
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
+ break;
+ default:
+ /* PTP v1, UDP, any kind of event packet */
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+ break;
+ }
}
+
priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
if (!priv->hwts_tx_en && !priv->hwts_rx_en)
priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0);
else {
- priv->hw->ptp->config_hw_tstamping(priv->ioaddr,
- (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT));
+ value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR |
+ tstamp_all | ptp_v2 | ptp_over_ethernet |
+ ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
+ ts_master_en | snap_type_sel);
+
+ priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value);
/* program Sub Second Increment reg */
priv->hw->ptp->config_sub_second_increment(priv->ioaddr);
@@ -454,7 +587,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
* where, freq_div_ratio = STMMAC_SYSCLOCK/50MHz
* hence, addend = ((2^32) * 50MHz)/STMMAC_SYSCLOCK;
* NOTE: STMMAC_SYSCLOCK should be >= 50MHz to
- * achive 20ns accuracy.
+ * achive 20ns accuracy.
*
* 2^x * y == (y << x), hence
* 2^32 * 50000000 ==> (50000000 << 32)
@@ -502,7 +635,7 @@ static void stmmac_release_ptp(struct stmmac_priv *priv)
#else
#define stmmac_hwtstamp_ioctl(dev, ifr) (-EOPNOTSUPP)
#define stmmac_get_rx_hwtstamp(priv, p, skb)
-#define stmmac_get_tx_hwtstamp(priv, p, skb) 0
+#define stmmac_get_tx_hwtstamp(priv, p, skb)
#define stmmac_init_ptp(priv) 0
#define stmmac_release_ptp(priv)
#endif /* CONFIG_STMMAC_USE_HWSTAMP */
@@ -915,7 +1048,6 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
while (priv->dirty_tx != priv->cur_tx) {
int last;
- unsigned int ts = 0;
unsigned int entry = priv->dirty_tx % txsize;
struct sk_buff *skb = priv->tx_skbuff[entry];
struct dma_desc *p = priv->dma_tx + entry;
@@ -937,7 +1069,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
} else
priv->dev->stats.tx_errors++;
- ts = stmmac_get_tx_hwtstamp(priv, p, skb);
+ stmmac_get_tx_hwtstamp(priv, p, skb);
}
TX_DBG("%s: curr %d, dirty %d\n", __func__,
priv->cur_tx, priv->dirty_tx);
@@ -949,7 +1081,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
DMA_TO_DEVICE);
priv->tx_skbuff_dma[entry] = 0;
}
- priv->hw->ring->clean_desc3(priv, p, ts);
+ priv->hw->ring->clean_desc3(priv, p);
if (likely(skb != NULL)) {
dev_kfree_skb(skb);
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (4 preceding siblings ...)
2013-03-07 10:50 ` [net-next.git 5/9] stmmac: add IEEE 1588-2008 PTP V2 support Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-10 12:36 ` Richard Cochran
2013-03-07 10:50 ` [net-next.git 7/9] stmmac: start adding pcs and rgmii core irq Giuseppe CAVALLARO
` (4 subsequent siblings)
10 siblings, 1 reply; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro
This patch updates the filters for ethtool's get_ts_info to return support for
all filters which can be supported after having added the PTP support.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 37 +++++++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 1 -
3 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 2d6e2e1..a9a10dd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -34,6 +34,7 @@
#ifdef CONFIG_STMMAC_USE_HWSTAMP
#include <linux/ptp_clock_kernel.h>
+#include <linux/net_tstamp.h>
#endif
struct stmmac_priv {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 5698bf3..88d2d25 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -629,6 +629,41 @@ static int stmmac_set_coalesce(struct net_device *dev,
return 0;
}
+static int stmmac_get_ts_info(struct net_device *dev,
+ struct ethtool_ts_info *info)
+{
+#ifdef CONFIG_STMMAC_USE_HWSTAMP
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ if (priv->dma_cap.atime_stamp) {
+
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+
+ if (priv->ptp_clock)
+ info->phc_index = ptp_clock_index(priv->ptp_clock);
+
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
+
+ info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_ALL));
+ }
+ return 0;
+#else
+ return ethtool_op_get_ts_info(dev, info);
+#endif /* CONFIG_STMMAC_USE_HWSTAMP */
+}
+
static const struct ethtool_ops stmmac_ethtool_ops = {
.begin = stmmac_check_if_running,
.get_drvinfo = stmmac_ethtool_getdrvinfo,
@@ -648,7 +683,7 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
.get_eee = stmmac_ethtool_op_get_eee,
.set_eee = stmmac_ethtool_op_set_eee,
.get_sset_count = stmmac_get_sset_count,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = stmmac_get_ts_info,
.get_coalesce = stmmac_get_coalesce,
.set_coalesce = stmmac_set_coalesce,
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ae92191..8786939 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -48,7 +48,6 @@
#include <linux/seq_file.h>
#endif
#ifdef CONFIG_STMMAC_USE_HWSTAMP
-#include <linux/net_tstamp.h>
#include "stmmac_ptp.h"
#endif
#include "stmmac.h"
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 7/9] stmmac: start adding pcs and rgmii core irq
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (5 preceding siblings ...)
2013-03-07 10:50 ` [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 8/9] stmmac: initial support to manage pcs modes Giuseppe CAVALLARO
` (3 subsequent siblings)
10 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro, Udit Kumar
This patch starts adding in the main ISR the management of the PCS and
RGMII/SGMII core interrupts. This is to help further development
on this area. Currently the core irq handler only clears the
PCS and S-R_MII interrupts and reports the event in the ethtool stats.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Tested-by: Byungho An <bh74.an@samsung.com>
Cc: Udit Kumar <udit-dlh.kumar@st.com>
---
drivers/net/ethernet/stmicro/stmmac/common.h | 25 ++++++-----
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 5 +-
.../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 44 ++++++++++++-------
.../net/ethernet/stmicro/stmmac/dwmac100_core.c | 3 +-
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 3 +
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 24 ++---------
6 files changed, 54 insertions(+), 50 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index f5965b6..42e2a87 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -117,6 +117,10 @@ struct stmmac_extra_stats {
unsigned long irq_rx_path_in_lpi_mode_n;
unsigned long irq_rx_path_exit_lpi_mode_n;
unsigned long phy_eee_wakeup_error_n;
+ /* PCS */
+ unsigned long irq_pcs_ane_n;
+ unsigned long irq_pcs_link_n;
+ unsigned long irq_rgmii_n;
#ifdef CONFIG_STMMAC_EXTENDED_DESC
/* Extended RDES status */
unsigned long ip_hdr_err;
@@ -219,16 +223,14 @@ enum dma_irq_status {
handle_tx = 0x8,
};
-enum core_specific_irq_mask {
- core_mmc_tx_irq = 1,
- core_mmc_rx_irq = 2,
- core_mmc_rx_csum_offload_irq = 4,
- core_irq_receive_pmt_irq = 8,
- core_irq_tx_path_in_lpi_mode = 16,
- core_irq_tx_path_exit_lpi_mode = 32,
- core_irq_rx_path_in_lpi_mode = 64,
- core_irq_rx_path_exit_lpi_mode = 128,
-};
+#define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 1)
+#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 2)
+#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 3)
+#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 4)
+
+#define CORE_PCS_ANE_COMPLETE (1 << 5)
+#define CORE_PCS_LINK_STATUS (1 << 6)
+#define CORE_RGMII_IRQ (1 << 7)
/* DMA HW capabilities */
struct dma_features {
@@ -364,7 +366,8 @@ struct stmmac_ops {
/* Dump MAC registers */
void (*dump_regs) (void __iomem *ioaddr);
/* Handle extra events on specific interrupts hw dependent */
- int (*host_irq_status) (void __iomem *ioaddr);
+ int (*host_irq_status) (void __iomem *ioaddr,
+ struct stmmac_extra_stats *x);
/* Multicast filter setting */
void (*set_filter) (struct net_device *dev, int id);
/* Flow control setting */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 85466e5..6dd689e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -89,13 +89,14 @@ enum power_event {
(reg * 8))
#define GMAC_MAX_PERFECT_ADDRESSES 32
+/* PCS registers (AN/TBI/SGMII/RGMII) offset */
#define GMAC_AN_CTRL 0x000000c0 /* AN control */
#define GMAC_AN_STATUS 0x000000c4 /* AN status */
#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */
-#define GMAC_ANE_LINK 0x000000cc /* Auto-Neg. link partener ability */
+#define GMAC_ANE_LPA 0x000000cc /* Auto-Neg. link partener ability */
#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */
#define GMAC_TBI 0x000000d4 /* TBI extend status */
-#define GMAC_GMII_STATUS 0x000000d8 /* S/R-GMII status */
+#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */
/* GMAC Configuration defines */
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index bfe0226..ff4c79e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -194,58 +194,70 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
}
-static int dwmac1000_irq_status(void __iomem *ioaddr)
+static int dwmac1000_irq_status(void __iomem *ioaddr,
+ struct stmmac_extra_stats *x)
{
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
- int status = 0;
+ int ret = 0;
/* Not used events (e.g. MMC interrupts) are not handled. */
if ((intr_status & mmc_tx_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
readl(ioaddr + GMAC_MMC_TX_INTR));
- status |= core_mmc_tx_irq;
+ x->mmc_tx_irq_n++;
}
if (unlikely(intr_status & mmc_rx_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
readl(ioaddr + GMAC_MMC_RX_INTR));
- status |= core_mmc_rx_irq;
+ x->mmc_rx_irq_n++;
}
if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
- status |= core_mmc_rx_csum_offload_irq;
+ x->mmc_rx_csum_offload_irq_n++;
}
if (unlikely(intr_status & pmt_irq)) {
CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
/* clear the PMT bits 5 and 6 by reading the PMT
* status register. */
readl(ioaddr + GMAC_PMT);
- status |= core_irq_receive_pmt_irq;
+ x->irq_receive_pmt_irq_n++;
}
/* MAC trx/rx EEE LPI entry/exit interrupts */
if (intr_status & lpiis_irq) {
/* Clean LPI interrupt by reading the Reg 12 */
- u32 lpi_status = readl(ioaddr + LPI_CTRL_STATUS);
+ ret = readl(ioaddr + LPI_CTRL_STATUS);
- if (lpi_status & LPI_CTRL_STATUS_TLPIEN) {
+ if (ret & LPI_CTRL_STATUS_TLPIEN) {
CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
- status |= core_irq_tx_path_in_lpi_mode;
+ x->irq_tx_path_in_lpi_mode_n++;
}
- if (lpi_status & LPI_CTRL_STATUS_TLPIEX) {
+ if (ret & LPI_CTRL_STATUS_TLPIEX) {
CHIP_DBG(KERN_INFO "GMAC TX exit from LPI\n");
- status |= core_irq_tx_path_exit_lpi_mode;
+ x->irq_tx_path_exit_lpi_mode_n++;
}
- if (lpi_status & LPI_CTRL_STATUS_RLPIEN) {
+ if (ret & LPI_CTRL_STATUS_RLPIEN) {
CHIP_DBG(KERN_INFO "GMAC RX entered in LPI\n");
- status |= core_irq_rx_path_in_lpi_mode;
+ x->irq_rx_path_in_lpi_mode_n++;
}
- if (lpi_status & LPI_CTRL_STATUS_RLPIEX) {
+ if (ret & LPI_CTRL_STATUS_RLPIEX) {
CHIP_DBG(KERN_INFO "GMAC RX exit from LPI\n");
- status |= core_irq_rx_path_exit_lpi_mode;
+ x->irq_rx_path_exit_lpi_mode_n++;
}
}
- return status;
+ if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC PCS ANE IRQ\n");
+ readl(ioaddr + GMAC_AN_STATUS);
+ x->irq_pcs_ane_n++;
+ }
+ if (intr_status & rgmii_irq) {
+ CHIP_DBG(KERN_INFO "GMAC RGMII IRQ status\n");
+ readl(ioaddr + GMAC_S_R_GMII);
+ x->irq_rgmii_n++;
+ }
+
+ return ret;
}
static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index f83210e..cb86a58 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
@@ -72,7 +72,8 @@ static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
return 0;
}
-static int dwmac100_irq_status(void __iomem *ioaddr)
+static int dwmac100_irq_status(void __iomem *ioaddr,
+ struct stmmac_extra_stats *x)
{
return 0;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 88d2d25..d78234e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -108,6 +108,9 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
STMMAC_STAT(phy_eee_wakeup_error_n),
+ /* PCS */
+ STMMAC_STAT(irq_pcs_ane_n),
+ STMMAC_STAT(irq_rgmii_n),
#ifdef CONFIG_STMMAC_EXTENDED_DESC
/* Extended RDES status */
STMMAC_STAT(ip_hdr_err),
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 8786939..7d2ee6f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1998,30 +1998,14 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
/* To handle GMAC own interrupts */
if (priv->plat->has_gmac) {
int status = priv->hw->mac->host_irq_status((void __iomem *)
- dev->base_addr);
+ dev->base_addr,
+ &priv->xstats);
if (unlikely(status)) {
- if (status & core_mmc_tx_irq)
- priv->xstats.mmc_tx_irq_n++;
- if (status & core_mmc_rx_irq)
- priv->xstats.mmc_rx_irq_n++;
- if (status & core_mmc_rx_csum_offload_irq)
- priv->xstats.mmc_rx_csum_offload_irq_n++;
- if (status & core_irq_receive_pmt_irq)
- priv->xstats.irq_receive_pmt_irq_n++;
-
/* For LPI we need to save the tx status */
- if (status & core_irq_tx_path_in_lpi_mode) {
- priv->xstats.irq_tx_path_in_lpi_mode_n++;
+ if (status & CORE_IRQ_TX_PATH_IN_LPI_MODE)
priv->tx_path_in_lpi_mode = true;
- }
- if (status & core_irq_tx_path_exit_lpi_mode) {
- priv->xstats.irq_tx_path_exit_lpi_mode_n++;
+ if (status & CORE_IRQ_TX_PATH_EXIT_LPI_MODE)
priv->tx_path_in_lpi_mode = false;
- }
- if (status & core_irq_rx_path_in_lpi_mode)
- priv->xstats.irq_rx_path_in_lpi_mode_n++;
- if (status & core_irq_rx_path_exit_lpi_mode)
- priv->xstats.irq_rx_path_exit_lpi_mode_n++;
}
}
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 8/9] stmmac: initial support to manage pcs modes
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (6 preceding siblings ...)
2013-03-07 10:50 ` [net-next.git 7/9] stmmac: start adding pcs and rgmii core irq Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 9/9] stmmac: update the Doc and Version (PTP+SGMII) Giuseppe CAVALLARO
` (2 subsequent siblings)
10 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro
This patch adds the minimal support to manage the PCS
modes (RGMII/SGMII) and restart the ANE.
Both TBI and RTBI are not yet supported.
Thanks to Byungho that wrote some part of this code
and tested SGMII too.
The only thing to be fixed is the get/set pause in
ethtool.
Signed-off-by: Byungho An <bh74.an@samsung.com>
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/ethernet/stmicro/stmmac/common.h | 21 +++++
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h | 34 +++++++
.../net/ethernet/stmicro/stmmac/dwmac1000_core.c | 64 +++++++++++++-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 94 ++++++++++++++++++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 59 ++++++++++---
6 files changed, 257 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 42e2a87..a9f8e77 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -121,6 +121,9 @@ struct stmmac_extra_stats {
unsigned long irq_pcs_ane_n;
unsigned long irq_pcs_link_n;
unsigned long irq_rgmii_n;
+ unsigned long pcs_link;
+ unsigned long pcs_duplex;
+ unsigned long pcs_speed;
#ifdef CONFIG_STMMAC_EXTENDED_DESC
/* Extended RDES status */
unsigned long ip_hdr_err;
@@ -167,6 +170,12 @@ struct stmmac_extra_stats {
#define FLOW_TX 2
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
+/* PCS defines */
+#define STMMAC_PCS_RGMII (1 << 0)
+#define STMMAC_PCS_SGMII (1 << 1)
+#define STMMAC_PCS_TBI (1 << 2)
+#define STMMAC_PCS_RTBI (1 << 3)
+
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
/* DAM HW feature register fields */
@@ -232,6 +241,16 @@ enum dma_irq_status {
#define CORE_PCS_LINK_STATUS (1 << 6)
#define CORE_RGMII_IRQ (1 << 7)
+struct rgmii_adv {
+ unsigned int pause;
+ unsigned int duplex;
+ unsigned int lp_pause;
+ unsigned int lp_duplex;
+};
+
+#define STMMAC_PCS_PAUSE 1
+#define STMMAC_PCS_ASYM_PAUSE 2
+
/* DMA HW capabilities */
struct dma_features {
unsigned int mbps_10_100;
@@ -384,6 +403,8 @@ struct stmmac_ops {
void (*reset_eee_mode) (void __iomem *ioaddr);
void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
void (*set_eee_pls) (void __iomem *ioaddr, int link);
+ void (*ctrl_ane) (void __iomem *ioaddr, bool restart);
+ void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv);
};
#ifdef CONFIG_STMMAC_USE_HWSTAMP
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 6dd689e..57f4e8f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -98,6 +98,38 @@ enum power_event {
#define GMAC_TBI 0x000000d4 /* TBI extend status */
#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */
+/* AN Configuration defines */
+#define GMAC_AN_CTRL_RAN 0x00000200 /* Restart Auto-Negotiation */
+#define GMAC_AN_CTRL_ANE 0x00001000 /* Auto-Negotiation Enable */
+#define GMAC_AN_CTRL_ELE 0x00004000 /* External Loopback Enable */
+#define GMAC_AN_CTRL_ECD 0x00010000 /* Enable Comma Detect */
+#define GMAC_AN_CTRL_LR 0x00020000 /* Lock to Reference */
+#define GMAC_AN_CTRL_SGMRAL 0x00040000 /* SGMII RAL Control */
+
+/* AN Status defines */
+#define GMAC_AN_STATUS_LS 0x00000004 /* Link Status 0:down 1:up */
+#define GMAC_AN_STATUS_ANA 0x00000008 /* Auto-Negotiation Ability */
+#define GMAC_AN_STATUS_ANC 0x00000020 /* Auto-Negotiation Complete */
+#define GMAC_AN_STATUS_ES 0x00000100 /* Extended Status */
+
+/* Register 54 (SGMII/RGMII status register) */
+#define GMAC_S_R_GMII_LINK 0x8
+#define GMAC_S_R_GMII_SPEED 0x5
+#define GMAC_S_R_GMII_SPEED_SHIFT 0x1
+#define GMAC_S_R_GMII_MODE 0x1
+#define GMAC_S_R_GMII_SPEED_125 2
+#define GMAC_S_R_GMII_SPEED_25 1
+
+/* Common ADV and LPA defines */
+#define GMAC_ANE_FD (1 << 5)
+#define GMAC_ANE_HD (1 << 6)
+#define GMAC_ANE_PSE (3 << 7)
+#define GMAC_ANE_PSE_SHIFT 7
+
+ /* GMAC Configuration defines */
+#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
+#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
+
/* GMAC Configuration defines */
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
@@ -232,5 +264,7 @@ enum rtc_control {
#define GMAC_MMC_TX_INTR 0x108
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
+
+
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
#endif /* __DWMAC1000_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index ff4c79e..29138da 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -28,6 +28,7 @@
#include <linux/crc32.h>
#include <linux/slab.h>
+#include <linux/ethtool.h>
#include <asm/io.h>
#include "dwmac1000.h"
@@ -193,7 +194,6 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
writel(pmt, ioaddr + GMAC_PMT);
}
-
static int dwmac1000_irq_status(void __iomem *ioaddr,
struct stmmac_extra_stats *x)
{
@@ -252,9 +252,30 @@ static int dwmac1000_irq_status(void __iomem *ioaddr,
x->irq_pcs_ane_n++;
}
if (intr_status & rgmii_irq) {
- CHIP_DBG(KERN_INFO "GMAC RGMII IRQ status\n");
- readl(ioaddr + GMAC_S_R_GMII);
+ u32 status = readl(ioaddr + GMAC_S_R_GMII);
+ CHIP_DBG(KERN_INFO "GMAC RGMII/SGMII interrupt\n");
x->irq_rgmii_n++;
+
+ /* Save and dump the link status. */
+ if (status & GMAC_S_R_GMII_LINK) {
+ int speed_value = (status & GMAC_S_R_GMII_SPEED) >>
+ GMAC_S_R_GMII_SPEED_SHIFT;
+ x->pcs_duplex = (status & GMAC_S_R_GMII_MODE);
+
+ if (speed_value == GMAC_S_R_GMII_SPEED_125)
+ x->pcs_speed = SPEED_1000;
+ else if (speed_value == GMAC_S_R_GMII_SPEED_25)
+ x->pcs_speed = SPEED_100;
+ else
+ x->pcs_speed = SPEED_10;
+
+ x->pcs_link = 1;
+ pr_debug("Link is Up - %d/%s\n", (int) x->pcs_speed,
+ x->pcs_duplex ? "Full" : "Half");
+ } else {
+ x->pcs_link = 0;
+ pr_debug("Link is Down\n");
+ }
}
return ret;
@@ -309,6 +330,41 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
writel(value, ioaddr + LPI_TIMER_CTRL);
}
+static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart)
+{
+ u32 value;
+
+ value = readl(ioaddr + GMAC_AN_CTRL);
+ /* auto negotiation enable and External Loopback enable */
+ value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;
+
+ if (restart)
+ value |= GMAC_AN_CTRL_RAN;
+
+ writel(value, ioaddr + GMAC_AN_CTRL);
+}
+
+static void dwmac1000_get_adv(void __iomem *ioaddr, struct rgmii_adv *adv)
+{
+ u32 value = readl(ioaddr + GMAC_ANE_ADV);
+
+ if (value & GMAC_ANE_FD)
+ adv->duplex = DUPLEX_FULL;
+ if (value & GMAC_ANE_HD)
+ adv->duplex |= DUPLEX_HALF;
+
+ adv->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
+
+ value = readl(ioaddr + GMAC_ANE_LPA);
+
+ if (value & GMAC_ANE_FD)
+ adv->lp_duplex = DUPLEX_FULL;
+ if (value & GMAC_ANE_HD)
+ adv->lp_duplex = DUPLEX_HALF;
+
+ adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
+}
+
static const struct stmmac_ops dwmac1000_ops = {
.core_init = dwmac1000_core_init,
.rx_ipc = dwmac1000_rx_ipc_enable,
@@ -323,6 +379,8 @@ static const struct stmmac_ops dwmac1000_ops = {
.reset_eee_mode = dwmac1000_reset_eee_mode,
.set_eee_timer = dwmac1000_set_eee_timer,
.set_eee_pls = dwmac1000_set_eee_pls,
+ .ctrl_ane = dwmac1000_ctrl_ane,
+ .get_adv = dwmac1000_get_adv,
};
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index a9a10dd..200011d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -99,6 +99,7 @@ struct stmmac_priv {
u32 tx_coal_timer;
int use_riwt;
u32 rx_riwt;
+ int pcs;
#ifdef CONFIG_STMMAC_USE_HWSTAMP
int hwts_tx_en;
int hwts_rx_en;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index d78234e..f5cc5ce 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -247,6 +247,70 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
struct stmmac_priv *priv = netdev_priv(dev);
struct phy_device *phy = priv->phydev;
int rc;
+
+ if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
+ struct rgmii_adv adv;
+
+ if (!priv->xstats.pcs_link) {
+ ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+ cmd->duplex = DUPLEX_UNKNOWN;
+ return 0;
+ }
+ cmd->duplex = priv->xstats.pcs_duplex;
+
+ ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
+
+ /* Get and convert ADV/LP_ADV from the HW AN registers */
+ if (priv->hw->mac->get_adv)
+ priv->hw->mac->get_adv(priv->ioaddr, &adv);
+ else
+ return -EOPNOTSUPP; /* should never happen indeed */
+
+ /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
+
+ if (adv.pause & STMMAC_PCS_PAUSE)
+ cmd->advertising |= ADVERTISED_Pause;
+ if (adv.pause & STMMAC_PCS_ASYM_PAUSE)
+ cmd->advertising |= ADVERTISED_Asym_Pause;
+ if (adv.lp_pause & STMMAC_PCS_PAUSE)
+ cmd->lp_advertising |= ADVERTISED_Pause;
+ if (adv.lp_pause & STMMAC_PCS_ASYM_PAUSE)
+ cmd->lp_advertising |= ADVERTISED_Asym_Pause;
+
+ /* Reg49[3] always set because ANE is always supported */
+ cmd->autoneg = ADVERTISED_Autoneg;
+ cmd->supported |= SUPPORTED_Autoneg;
+ cmd->advertising |= ADVERTISED_Autoneg;
+ cmd->lp_advertising |= ADVERTISED_Autoneg;
+
+ if (adv.duplex) {
+ cmd->supported |= (SUPPORTED_1000baseT_Full |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_10baseT_Full);
+ cmd->advertising |= (ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Full);
+ } else {
+ cmd->supported |= (SUPPORTED_1000baseT_Half |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_10baseT_Half);
+ cmd->advertising |= (ADVERTISED_1000baseT_Half |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_10baseT_Half);
+ }
+ if (adv.lp_duplex)
+ cmd->lp_advertising |= (ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Full);
+ else
+ cmd->lp_advertising |= (ADVERTISED_1000baseT_Half |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_10baseT_Half);
+ cmd->port = PORT_OTHER;
+
+ return 0;
+ }
+
if (phy == NULL) {
pr_err("%s: %s: PHY is not registered\n",
__func__, dev->name);
@@ -271,6 +335,30 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
struct phy_device *phy = priv->phydev;
int rc;
+ if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
+ u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
+
+ /* Only support ANE */
+ if (cmd->autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ mask &= (ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full);
+
+ spin_lock(&priv->lock);
+ if (priv->hw->mac->ctrl_ane)
+ priv->hw->mac->ctrl_ane(priv->ioaddr, 1);
+ spin_unlock(&priv->lock);
+ }
+
+ return 0;
+ }
+
spin_lock(&priv->lock);
rc = phy_ethtool_sset(phy, cmd);
spin_unlock(&priv->lock);
@@ -340,6 +428,9 @@ stmmac_get_pauseparam(struct net_device *netdev,
{
struct stmmac_priv *priv = netdev_priv(netdev);
+ if (priv->pcs) /* FIXME */
+ return;
+
spin_lock(&priv->lock);
pause->rx_pause = 0;
@@ -363,6 +454,9 @@ stmmac_set_pauseparam(struct net_device *netdev,
int new_pause = FLOW_OFF;
int ret = 0;
+ if (priv->pcs) /* FIXME */
+ return -EOPNOTSUPP;
+
spin_lock(&priv->lock);
if (pause->rx_pause)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 7d2ee6f..a25b54c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -733,6 +733,24 @@ static void stmmac_adjust_link(struct net_device *dev)
DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n");
}
+static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
+{
+ int interface = priv->plat->interface;
+
+ if (priv->dma_cap.pcs) {
+ if ((interface & PHY_INTERFACE_MODE_RGMII) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_ID) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_RXID) ||
+ (interface & PHY_INTERFACE_MODE_RGMII_TXID)) {
+ pr_debug("STMMAC: PCS RGMII support enable\n");
+ priv->pcs = STMMAC_PCS_RGMII;
+ } else if (interface & PHY_INTERFACE_MODE_SGMII) {
+ pr_debug("STMMAC: PCS SGMII support enable\n");
+ priv->pcs = STMMAC_PCS_SGMII;
+ }
+ }
+}
+
/**
* stmmac_init_phy - PHY initialization
* @dev: net device structure
@@ -1372,13 +1390,15 @@ static int stmmac_open(struct net_device *dev)
stmmac_check_ether_addr(priv);
- ret = stmmac_init_phy(dev);
- if (unlikely(ret)) {
- pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
- goto open_error;
+ if (!priv->pcs) {
+ ret = stmmac_init_phy(dev);
+ if (unlikely(ret)) {
+ pr_err("%s: Cannot attach to PHY (error: %d)\n",
+ __func__, ret);
+ goto open_error;
+ }
}
-
/* Create and initialize the TX/RX descriptors chains. */
priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
@@ -1469,7 +1489,12 @@ static int stmmac_open(struct net_device *dev)
phy_start(priv->phydev);
priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER;
- priv->eee_enabled = stmmac_eee_init(priv);
+
+ /* Using PCS we cannot dial with the phy registers at this stage
+ * so we do not support extra feature like EEE.
+ */
+ if (!priv->pcs)
+ priv->eee_enabled = stmmac_eee_init(priv);
stmmac_init_tx_coalesce(priv);
@@ -1478,6 +1503,9 @@ static int stmmac_open(struct net_device *dev)
priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
}
+ if (priv->pcs && priv->hw->mac->ctrl_ane)
+ priv->hw->mac->ctrl_ane(priv->ioaddr, 0);
+
napi_enable(&priv->napi);
netif_start_queue(dev);
@@ -2437,12 +2465,16 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
else
priv->clk_csr = priv->plat->clk_csr;
- /* MDIO bus Registration */
- ret = stmmac_mdio_register(ndev);
- if (ret < 0) {
- pr_debug("%s: MDIO bus (id: %d) registration failed",
- __func__, priv->plat->bus_id);
- goto error_mdio_register;
+ stmmac_check_pcs_mode(priv);
+
+ if (!priv->pcs) {
+ /* MDIO bus Registration */
+ ret = stmmac_mdio_register(ndev);
+ if (ret < 0) {
+ pr_debug("%s: MDIO bus (id: %d) registration failed",
+ __func__, priv->plat->bus_id);
+ goto error_mdio_register;
+ }
}
return priv;
@@ -2475,7 +2507,8 @@ int stmmac_dvr_remove(struct net_device *ndev)
priv->hw->dma->stop_tx(priv->ioaddr);
stmmac_set_mac(priv->ioaddr, false);
- stmmac_mdio_unregister(ndev);
+ if (!priv->pcs)
+ stmmac_mdio_unregister(ndev);
netif_carrier_off(ndev);
unregister_netdev(ndev);
free_netdev(ndev);
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [net-next.git 9/9] stmmac: update the Doc and Version (PTP+SGMII)
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (7 preceding siblings ...)
2013-03-07 10:50 ` [net-next.git 8/9] stmmac: initial support to manage pcs modes Giuseppe CAVALLARO
@ 2013-03-07 10:50 ` Giuseppe CAVALLARO
2013-03-07 20:34 ` [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) David Miller
2013-03-08 6:04 ` Richard Cochran
10 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-07 10:50 UTC (permalink / raw)
To: netdev; +Cc: bh74.an, ayagond, Giuseppe Cavallaro
This patch updates the stmmac.txt file adding
information related to the PTP and SGMII/RGMII
supports.
Also the patch updates the driver version to:
March_2013.
Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
Documentation/networking/stmmac.txt | 39 ++++++++++++++++++++++++-
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 +-
2 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt
index f9fa6db..f7d8c3d 100644
--- a/Documentation/networking/stmmac.txt
+++ b/Documentation/networking/stmmac.txt
@@ -326,6 +326,41 @@ To enter in Tx LPI mode the driver needs to have a software timer
that enable and disable the LPI mode when there is nothing to be
transmitted.
-7) TODO:
+7) Extended descriptors
+The CONFIG_STMMAC_EXTENDED_DESC option can be enabled to use the
+the extended status in the descriptors. For RDESC, that gives some
+information about the receive Ethernet payload when it is carrying PTP
+packets or TCP/UDP/ICMP over IP.
+This option cannot be used on GMAC Synopsys older than the 3.50
+so the driver's probe will fail in this scenario.
+This option also is mandatory for PTPv2 because the extra descriptors
+are used for saving the hardware timestamps.
+
+8) Precision Time Protocol (PTP)
+The driver supports the IEEE 1588-2002, Precision Time Protocol (PTP),
+which enables precise synchronization of clocks in measurement and
+control systems implemented with technologies such as network
+communication.
+This is the Kernel option to enable it: CONFIG_STMMAC_USE_HWSTAMP
+
+In addition to the basic timestamp features mentioned in IEEE 1588-2002
+Timestamps, new GMAC cores support the advanced timestamp features.
+IEEE 1588-2008 that can be enabled when configure the Kernel. This is
+its option: CONFIG_STMMAC_USE_HW_A_STAMP
+To use this support the HW has to have the extended descriptors.
+At run time this will be verified by looking at the HW capability
+register.
+
+9) SGMII/RGMII supports
+New GMAC devices provide own way to manage RGMII/SGMII.
+This information is available at run-time by looking at the
+HW capability register. This means that the stmmac can manage
+auto-negotiation and link status w/o using the PHYLIB stuff
+In fact, the HW provides a subset of extended registers to
+restart the ANE, verify Full/Half duplex mode and Speed.
+Also thanks to these registers it is possible to look at the
+Auto-negotiated Link Parter Ability.
+
+10) TODO:
o XGMAC is not supported.
- o Add the PTP - precision time protocol
+ o Complete the TBI & RTBI support.
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 200011d..78bc4d1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -24,7 +24,7 @@
#define __STMMAC_H__
#define STMMAC_RESOURCE_NAME "stmmaceth"
-#define DRV_MODULE_VERSION "Nov_2012"
+#define DRV_MODULE_VERSION "March_2013"
#include <linux/clk.h>
#include <linux/stmmac.h>
--
1.7.4.4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (8 preceding siblings ...)
2013-03-07 10:50 ` [net-next.git 9/9] stmmac: update the Doc and Version (PTP+SGMII) Giuseppe CAVALLARO
@ 2013-03-07 20:34 ` David Miller
2013-03-08 7:16 ` Giuseppe CAVALLARO
2013-03-08 6:04 ` Richard Cochran
10 siblings, 1 reply; 29+ messages in thread
From: David Miller @ 2013-03-07 20:34 UTC (permalink / raw)
To: peppe.cavallaro; +Cc: netdev, bh74.an, ayagond
From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
Date: Thu, 7 Mar 2013 11:50:10 +0100
> The PTP support is quite intrusive because it needs to support the extended
> descriptors used for saving the HW timestamps.
> These are available in new chip generations, only.
> So we have actually found useful to use some Kconfig options to
> surround PTP and extended descriptor support. This approach helped on
> old platform (embeeded system) where PTP is not supported and where we
> do not want to pay extra code and check in critical rx/tx paths.
I would prefer run time handling of all of this.
You do not need to put extra checks in the fast paths, instead you
have different methods that get hooked up into the netdev_ops
based upon chip capabilities/features/mode.
Thanks.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
` (9 preceding siblings ...)
2013-03-07 20:34 ` [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) David Miller
@ 2013-03-08 6:04 ` Richard Cochran
2013-03-08 6:39 ` Giuseppe CAVALLARO
10 siblings, 1 reply; 29+ messages in thread
From: Richard Cochran @ 2013-03-08 6:04 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: netdev, bh74.an, ayagond
On Thu, Mar 07, 2013 at 11:50:10AM +0100, Giuseppe CAVALLARO wrote:
> Rayagond Kokatanur (4):
> stmmac: add tx_skbuff_dma to save descriptors used by PTP
> stmmac: add IEEE 1588-2002 PTP support
> stmmac: add the support for PTP hw clock driver
> stmmac: add IEEE 1588-2008 PTP V2 support
In the future, for PTP clock and time stamping patches, I would
appreciate being put on CC.
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
2013-03-07 10:50 ` [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support Giuseppe CAVALLARO
@ 2013-03-08 6:34 ` Richard Cochran
2013-03-08 7:02 ` Giuseppe CAVALLARO
0 siblings, 1 reply; 29+ messages in thread
From: Richard Cochran @ 2013-03-08 6:34 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: netdev, bh74.an, ayagond, Rayagond Kokatanur
I have a few comments, below.
On Thu, Mar 07, 2013 at 11:50:12AM +0100, Giuseppe CAVALLARO wrote:
> From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
>
> This patch enhances the stmmac driver to support IEEE 1588-2002
> PTP (Precision Time Protocol) version 1.
>
> IEEE 1588-2002 standard defines a protocol, 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.
>
> HW Timestamp support can be enabled while configuring the Kernel and
> the Koption is: STMMAC_USE_HWSTAMP
> At runtime, the support is verified by looking at the HW capability
> register.
As davem said, since you have the ability to detect this at run time,
then there is no need for a kconfig option.
> Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
> Hacked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> ---
> drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 +
> drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
> drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 23 ++-
> drivers/net/ethernet/stmicro/stmmac/common.h | 27 ++-
> drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 1 -
> drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 37 +++
> drivers/net/ethernet/stmicro/stmmac/norm_desc.c | 34 +++
> drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 14 +-
> drivers/net/ethernet/stmicro/stmmac/stmmac.h | 8 +
> .../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 129 ++++++++++
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 255 +++++++++++++++++++-
> drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 72 ++++++
> 12 files changed, 588 insertions(+), 24 deletions(-)
> create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
> create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> index c0ea838..ef703b3 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
> +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
> @@ -71,5 +71,16 @@ config STMMAC_CHAINED
>
> endchoice
>
> +config STMMAC_USE_HWSTAMP
> + bool "Use IEEE 1588 Precision Time Protocol"
> + depends on STMMAC_ETH
> + select PTP_1588_CLOCK
> + default n
> + ---help---
> + Enable this option to support the IEEE 1588 Precision Time Protocol
> + (PTP) and HW Timestamps.
> + At runtime, on new chip generations, the hardware capability
> + register will be used to verify if either the IEEE 1588-2008 Advanced
> + Timestamping (PTPv2) or IEEE 1588-2002 (PTPv1) is actually supported.
>
> endif
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index c8e8ea6..cc97c07 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -3,6 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
> stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
> stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
> stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
> +stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o
> stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
> dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
> dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
> diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
> index ad3d75f..dd60f6b 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c
> @@ -92,16 +92,35 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
> return ret;
> }
>
> -static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
> +static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
> {
> + struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
> +
> + if (priv->hwts_rx_en)
> + /* NOTE: Device will overwrite des3 with timestamp value if
> + * 1588-2002 time stamping is enabled, hence reinitialize it
> + * to keep explicit chaining in the descriptor.
> + */
> + p->des3 = (unsigned int)(priv->dma_rx +
> + ((priv->dirty_rx) + 1) % priv->dma_rx_size);
> }
>
> static void stmmac_init_desc3(int des3_as_data_buf, struct dma_desc *p)
> {
> }
>
> -static void stmmac_clean_desc3(struct dma_desc *p)
> +static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
> + int tstamp_taken)
> {
> + struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
> +
> + if (tstamp_taken && priv->hw->desc->get_tx_ls(p))
> + /* NOTE: Device will overwrite des3 with timestamp value if
> + * 1588-2002 time stamping is enabled, hence reinitialize it
> + * to keep explicit chaining in the descriptor.
> + */
> + p->des3 = (unsigned int)(priv->dma_tx +
> + ((priv->dirty_tx + 1) % priv->dma_tx_size));
> }
>
> static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
> diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
> index 186d148..fa8ff9b 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/common.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/common.h
> @@ -290,6 +290,16 @@ struct stmmac_desc_ops {
> /* Return the reception status looking at the RDES1 */
> int (*rx_status) (void *data, struct stmmac_extra_stats *x,
> struct dma_desc *p);
> + /* Set tx timestamp enable bit */
> + void (*enable_tx_timestamp) (struct dma_desc *p);
> + /* get tx timestamp status */
> + int (*get_tx_timestamp_status) (struct dma_desc *p);
> + /* get tx/rx timestamp low value */
> + u32 (*get_timestamp_low) (struct dma_desc *p);
> + /* get tx/rx timestamp high value */
> + u32 (*get_timestamp_high) (struct dma_desc *p);
These two separate functions should be combined into one.
> + /* get rx timestamp status */
> + int (*get_rx_timestamp_status) (struct dma_desc *p);
> };
>
> struct stmmac_dma_ops {
> @@ -346,6 +356,15 @@ struct stmmac_ops {
> void (*set_eee_pls) (void __iomem *ioaddr, int link);
> };
>
> +#ifdef CONFIG_STMMAC_USE_HWSTAMP
> +struct stmmac_hwtimestamp {
> + void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
> + void (*config_sub_second_increment) (void __iomem *ioaddr);
> + int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
> + int (*config_addend)(void __iomem *ioaddr, u32 addend);
> +};
> +#endif
> +
> struct mac_link {
> int port;
> int duplex;
> @@ -360,11 +379,11 @@ struct mii_regs {
> struct stmmac_ring_mode_ops {
> unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
> unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
> - void (*refill_desc3) (int bfsize, struct dma_desc *p);
> + void (*refill_desc3) (void *priv, struct dma_desc *p);
> void (*init_desc3) (int des3_as_data_buf, struct dma_desc *p);
> void (*init_dma_chain) (struct dma_desc *des, dma_addr_t phy_addr,
> unsigned int size);
> - void (*clean_desc3) (struct dma_desc *p);
> + void (*clean_desc3) (void *priv, struct dma_desc *p, int tstamp_taken);
> int (*set_16kib_bfsize) (int mtu);
> };
>
> @@ -373,6 +392,9 @@ struct mac_device_info {
> const struct stmmac_desc_ops *desc;
> const struct stmmac_dma_ops *dma;
> const struct stmmac_ring_mode_ops *ring;
> +#ifdef CONFIG_STMMAC_USE_HWSTAMP
> + const struct stmmac_hwtimestamp *ptp;
> +#endif
> struct mii_regs mii; /* MII register Addresses */
> struct mac_link link;
> unsigned int synopsys_uid;
> @@ -390,5 +412,4 @@ extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
>
> extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
> extern const struct stmmac_ring_mode_ops ring_mode_ops;
> -
> #endif /* __COMMON_H__ */
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
> index 491d7e9..8c4ea93 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
> @@ -286,4 +286,3 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
> addr[4] = hi_addr & 0xff;
> addr[5] = (hi_addr >> 8) & 0xff;
> }
> -
> diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
> index 2fc8ef9..4d635d5 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c
> @@ -323,6 +323,38 @@ static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
> return p->des01.erx.frame_length;
> }
>
> +static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
> +{
> + p->des01.etx.time_stamp_enable = 1;
> +}
> +
> +static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
> +{
> + return p->des01.etx.time_stamp_status;
> +}
> +
> +static u32 enh_desc_get_timestamp_low(struct dma_desc *p)
> +{
> + /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
> + return p->des2;
> +}
> +
> +static u32 enh_desc_get_timestamp_high(struct dma_desc *p)
> +{
> + /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
> + return p->des3;
> +}
> +
> +static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
> +{
> + /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
Why not fix these FIXMEs for the next respin?
> + if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
> + /* timestamp is currupted, hence don't store it */
corrupted
> + return 0;
> + else
> + return 1;
> +}
> +
> const struct stmmac_desc_ops enh_desc_ops = {
> .tx_status = enh_desc_get_tx_status,
> .rx_status = enh_desc_get_rx_status,
> @@ -339,4 +371,9 @@ const struct stmmac_desc_ops enh_desc_ops = {
> .set_tx_owner = enh_desc_set_tx_owner,
> .set_rx_owner = enh_desc_set_rx_owner,
> .get_rx_frame_len = enh_desc_get_rx_frame_len,
> + .enable_tx_timestamp = enh_desc_enable_tx_timestamp,
> + .get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
> + .get_timestamp_low = enh_desc_get_timestamp_low,
> + .get_timestamp_high = enh_desc_get_timestamp_high,
> + .get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
> };
> diff --git a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
> index 68962c5..edb5e88 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
> @@ -215,6 +215,35 @@ static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
> return p->des01.rx.frame_length;
> }
>
> +static void ndesc_enable_tx_timestamp(struct dma_desc *p)
> +{
> + p->des01.tx.time_stamp_enable = 1;
> +}
> +
> +static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
> +{
> + return p->des01.tx.time_stamp_status;
> +}
> +
> +static u32 ndesc_get_timestamp_low(struct dma_desc *p)
> +{
> + return p->des2;
> +}
> +
> +static u32 ndesc_get_timestamp_high(struct dma_desc *p)
> +{
> + return p->des3;
> +}
> +
> +static int ndesc_get_rx_timestamp_status(struct dma_desc *p)
> +{
> + if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
> + /* timestamp is currupted, hence don't store it */
corrupted
> + return 0;
> + else
> + return 1;
> +}
> +
> const struct stmmac_desc_ops ndesc_ops = {
> .tx_status = ndesc_get_tx_status,
> .rx_status = ndesc_get_rx_status,
> @@ -231,4 +260,9 @@ const struct stmmac_desc_ops ndesc_ops = {
> .set_tx_owner = ndesc_set_tx_owner,
> .set_rx_owner = ndesc_set_rx_owner,
> .get_rx_frame_len = ndesc_get_rx_frame_len,
> + .enable_tx_timestamp = ndesc_enable_tx_timestamp,
> + .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
> + .get_timestamp_low = ndesc_get_timestamp_low,
> + .get_timestamp_high = ndesc_get_timestamp_high,
> + .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
> };
> diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
> index 839e349..94a1c2f 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c
> @@ -85,11 +85,14 @@ static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
> return ret;
> }
>
> -static void stmmac_refill_desc3(int bfsize, struct dma_desc *p)
> +static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
> {
> - /* Fill DES3 in case of RING mode */
> - if (bfsize >= BUF_SIZE_8KiB)
> - p->des3 = p->des2 + BUF_SIZE_8KiB;
> + struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
> +
> + if (unlikely(priv->plat->has_gmac))
> + /* Fill DES3 in case of RING mode */
> + if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
> + p->des3 = p->des2 + BUF_SIZE_8KiB;
> }
>
> /* In ring mode we need to fill the desc3 because it is used
> @@ -105,7 +108,8 @@ static void stmmac_init_dma_chain(struct dma_desc *des, dma_addr_t phy_addr,
> {
> }
>
> -static void stmmac_clean_desc3(struct dma_desc *p)
> +static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p,
> + int tstamp_taken)
> {
> if (unlikely(p->des3))
> p->des3 = 0;
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> index 013a7d5..665f2a2 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> @@ -94,6 +94,11 @@ struct stmmac_priv {
> u32 tx_coal_timer;
> int use_riwt;
> u32 rx_riwt;
> +#ifdef CONFIG_STMMAC_USE_HWSTAMP
> + int hwts_tx_en;
> + int hwts_rx_en;
> + unsigned int default_addend;
> +#endif
> };
>
> extern int phyaddr;
> @@ -103,6 +108,9 @@ extern int stmmac_mdio_register(struct net_device *ndev);
> extern void stmmac_set_ethtool_ops(struct net_device *netdev);
> extern const struct stmmac_desc_ops enh_desc_ops;
> extern const struct stmmac_desc_ops ndesc_ops;
> +#ifdef CONFIG_STMMAC_USE_HWSTAMP
> +extern const struct stmmac_hwtimestamp stmmac_ptp;
> +#endif
> int stmmac_freeze(struct net_device *ndev);
> int stmmac_restore(struct net_device *ndev);
> int stmmac_resume(struct net_device *ndev);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
> new file mode 100644
> index 0000000..be9e399
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
> @@ -0,0 +1,129 @@
> +/*******************************************************************************
> + Copyright (C) 2013 Vayavya Labs Pvt Ltd
> +
> + This implements all the API for managing HW timestamp & PTP.
> +
> + This program is free software; you can redistribute it and/or modify it
> + under the terms and conditions of the GNU General Public License,
> + version 2, as published by the Free Software Foundation.
> +
> + This program is distributed in the hope it will be useful, but WITHOUT
> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + more details.
> +
> + You should have received a copy of the GNU General Public License along with
> + this program; if not, write to the Free Software Foundation, Inc.,
> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> + Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
> + Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> +*******************************************************************************/
> +
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include "common.h"
> +#include "stmmac_ptp.h"
> +
> +static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
> +{
> + writel(data, ioaddr + PTP_TCR);
> +}
> +
> +static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
> +{
> + u32 value = readl(ioaddr + PTP_TCR);
> + unsigned long data;
> +
> + /* Convert the ptp_clock to nano second
> + * formula = (1/ptp_clock) * 1000000000
> + * where, ptp_clock = 50MHz for FINE correction method &
> + * ptp_clock = STMMAC_SYSCLOCK for COARSE correction method
> + */
What are these coarse/fine method? Can't we always use the fine one?
> + if (value & PTP_TCR_TSCFUPDT)
> + data = (1000000000ULL / 50000000);
> + else
> + data = (1000000000ULL / STMMAC_SYSCLOCK);
> +
> + writel(data, ioaddr + PTP_SSIR);
> +}
> +
> +static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
> +{
> + int limit;
> + u32 value;
> +
> + /* wait for previous(if any) system time initialize to complete */
> + limit = 100;
> + while (limit--) {
> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
> + break;
> + mdelay(10);
> + }
> +
> + if (limit < 0)
> + return -EBUSY;
> +
Ugh, this is terrible...
> + writel(sec, ioaddr + PTP_STSUR);
> + writel(nsec, ioaddr + PTP_STNSUR);
> + /* issue command to initialize the system time value */
> + value = readl(ioaddr + PTP_TCR);
> + value |= PTP_TCR_TSINIT;
> + writel(value, ioaddr + PTP_TCR);
> +
> + /* wait for present system time initialize to complete */
> + limit = 100;
> + while (limit--) {
> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
> + break;
> + mdelay(10);
> + }
> + if (limit < 0)
> + return -EBUSY;
... for a number of reasons.
1. You are polling for 100*10ms = one second, and the caller has
disabled interrupts! This is way too long. Is the hardware really
that slow? If so, then you need to use delayed work or find some
other way not to block.
2. You are waiting both before and after for the status bit. Pick one
or the other. You don't need both.
This same pattern is repeated a few times here, and it needs fixing in
each case.
> +
> + return 0;
> +}
> +
> +static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
> +{
> + u32 value;
> + int limit;
> +
> + /* wait for previous (if any) addend update to complete */
> + limit = 100;
> + while (limit--) {
> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
> + break;
> + mdelay(10);
> + }
> + if (limit < 0)
> + return -EBUSY;
> +
> + writel(addend, ioaddr + PTP_TAR);
> + /* issue command to update the addend value */
> + value = readl(ioaddr + PTP_TCR);
> + value |= PTP_TCR_TSADDREG;
> + writel(value, ioaddr + PTP_TCR);
> +
> + /* wait for present addend update to complete */
> + limit = 100;
> + while (limit--) {
> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
> + break;
> + mdelay(10);
> + }
> + if (limit < 0)
> + return -EBUSY;
> +
> + return 0;
> +}
> +
> +const struct stmmac_hwtimestamp stmmac_ptp = {
> + .config_hw_tstamping = stmmac_config_hw_tstamping,
> + .init_systime = stmmac_init_systime,
> + .config_sub_second_increment = stmmac_config_sub_second_increment,
> + .config_addend = stmmac_config_addend,
> +};
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 260af93..3bbd554 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -47,6 +47,10 @@
> #include <linux/debugfs.h>
> #include <linux/seq_file.h>
> #endif
> +#ifdef CONFIG_STMMAC_USE_HWSTAMP
> +#include <linux/net_tstamp.h>
> +#include "stmmac_ptp.h"
> +#endif
> #include "stmmac.h"
>
> #undef STMMAC_DEBUG
> @@ -304,6 +308,192 @@ static void stmmac_eee_adjust(struct stmmac_priv *priv)
> priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
> }
>
> +#ifdef CONFIG_STMMAC_USE_HWSTAMP
> +/* stmmac_get_tx_hwtstamp:
> + * @priv : pointer to private device structure.
> + * @p : pointer to desc structure.
> + * @skb : the socket buffer
> + * Description :
> + * This function will read timestamp from the descriptor & pass it to stack.
> + * and also perform some sanity checks.
> + * Return value :
> + * 1 if time stamp is taken & 0 if time stamp is not taken.
> + */
> +static unsigned int stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
> + struct dma_desc *p,
> + struct sk_buff *skb)
> +{
> + struct skb_shared_hwtstamps shhwtstamp;
> + u64 ns;
> +
> + if (!priv->hwts_tx_en)
> + return 0;
> +
> + /* if skb doesn't support hw tstamp */
> + if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
> + return 0;
> +
> + /* check tx tstamp status */
> + if (!priv->hw->desc->get_tx_timestamp_status(p))
> + return 0;
> +
> + /* get the valid tstamp */
> + ns = priv->hw->desc->get_timestamp_low(p);
> + /* convert high/sec time stamp value to nanosecond */
> + ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
> +
> + memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
> + shhwtstamp.hwtstamp = ns_to_ktime(ns);
> + /* pass tstamp to stack */
> + skb_tstamp_tx(skb, &shhwtstamp);
> +
> + return 1;
> +}
> +
> +/* stmmac_get_rx_hwtstamp:
> + * @priv : pointer to private device structure.
> + * @p : pointer to desc structure.
> + * @skb : the socket buffer
> + * Description :
> + * This function will read received packet's timestamp from the descriptor
> + * and pass it to stack. It also perform some sanity checks.
> + */
> +static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
> + struct sk_buff *skb)
> +{
> + struct skb_shared_hwtstamps *shhwtstamp = NULL;
> + u64 ns;
> +
> + if (!priv->hwts_rx_en)
> + return;
> +
> + /* if rx tstamp is not valid */
> + if (!priv->hw->desc->get_rx_timestamp_status(p))
> + return;
> +
> + /* get valid tstamp */
> + ns = priv->hw->desc->get_timestamp_low(p);
> + /* convert high/sec time stamp value to nanosecond */
> + ns += priv->hw->desc->get_timestamp_high(p) * 1000000000ULL;
> + shhwtstamp = skb_hwtstamps(skb);
> + memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
> + shhwtstamp->hwtstamp = ns_to_ktime(ns);
> +}
> +
> +/**
> + * stmmac_hwtstamp_ioctl - control hardware timestamping.
> + * @dev: device pointer.
> + * @ifr: An IOCTL specefic structure, that can contain a pointer to
> + * a proprietary structure used to pass information to the driver.
> + * Description:
> + * This function configures the MAC to enable/disable both outgoing(TX)
> + * and incoming(RX) packets time stamping based on user input.
> + * Return Value:
> + * 0 on success and an appropriate -ve integer on failure.
> + */
> +static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
> +{
> + struct stmmac_priv *priv = netdev_priv(dev);
> + struct hwtstamp_config config;
> + struct timespec now;
> + u64 temp = 0;
You add this new code here, but you change it all around again a few
patches later. Please just submit the final, combined version.
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
2013-03-08 6:04 ` Richard Cochran
@ 2013-03-08 6:39 ` Giuseppe CAVALLARO
0 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-08 6:39 UTC (permalink / raw)
To: Richard Cochran; +Cc: netdev, bh74.an, ayagond
On 3/8/2013 7:04 AM, Richard Cochran wrote:
> On Thu, Mar 07, 2013 at 11:50:10AM +0100, Giuseppe CAVALLARO wrote:
>
>> Rayagond Kokatanur (4):
>> stmmac: add tx_skbuff_dma to save descriptors used by PTP
>> stmmac: add IEEE 1588-2002 PTP support
>> stmmac: add the support for PTP hw clock driver
>> stmmac: add IEEE 1588-2008 PTP V2 support
>
> In the future, for PTP clock and time stamping patches, I would
> appreciate being put on CC.
Sorry Richard, I didn't know. You will be in copy when I send
the next patches.
Peppe
> Thanks,
> Richard
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
2013-03-08 6:34 ` Richard Cochran
@ 2013-03-08 7:02 ` Giuseppe CAVALLARO
2013-03-08 7:51 ` Rayagond K
` (2 more replies)
0 siblings, 3 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-08 7:02 UTC (permalink / raw)
To: Richard Cochran; +Cc: netdev, bh74.an, Rayagond K, Rayagond Kokatanur
On 3/8/2013 7:34 AM, Richard Cochran wrote:
> I have a few comments, below.
thanks for them.
>> HW Timestamp support can be enabled while configuring the Kernel and
>> the Koption is: STMMAC_USE_HWSTAMP
>> At runtime, the support is verified by looking at the HW capability
>> register.
>
> As davem said, since you have the ability to detect this at run time,
> then there is no need for a kconfig option.
I'll try to give you more details about this replying to D. Miller
[snip]
>> + /* get tx/rx timestamp low value */
>> + u32 (*get_timestamp_low) (struct dma_desc *p);
>> + /* get tx/rx timestamp high value */
>> + u32 (*get_timestamp_high) (struct dma_desc *p);
>
> These two separate functions should be combined into one.
ok
>> + /* get rx timestamp status */
>> + int (*get_rx_timestamp_status) (struct dma_desc *p);
>> +
>> +static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
>> +{
>> + /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
>
> Why not fix these FIXMEs for the next respin?
This is fixed in the patch #5 where we use the extended descriptors
for PTP2.
>> + if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
>> + /* timestamp is currupted, hence don't store it */
>
> corrupted
thanks
>> + /* Convert the ptp_clock to nano second
>> + * formula = (1/ptp_clock) * 1000000000
>> + * where, ptp_clock = 50MHz for FINE correction method &
>> + * ptp_clock = STMMAC_SYSCLOCK for COARSE correction method
>> + */
>
> What are these coarse/fine method? Can't we always use the fine one?
This is explained in the "4.1.2 System Time Register Module" of Synopsys
Databook. Summarizing, the MAC can have an optional module and use this
coarse correction method. In the fine correction method, a slave clock’s
frequency drift with respect to the master clock is corrected over a
period of time instead of in one clock, as in coarse correction.
Pls, Rayagond feels free to provide more details...
>> + if (value & PTP_TCR_TSCFUPDT)
>> + data = (1000000000ULL / 50000000);
>> + else
>> + data = (1000000000ULL / STMMAC_SYSCLOCK);
>> +
>> + writel(data, ioaddr + PTP_SSIR);
>> +}
>> +
>> +static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
>> +{
>> + int limit;
>> + u32 value;
>> +
>> + /* wait for previous(if any) system time initialize to complete */
>> + limit = 100;
>> + while (limit--) {
>> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
>> + break;
>> + mdelay(10);
>> + }
>> +
>> + if (limit < 0)
>> + return -EBUSY;
>> +
>
> Ugh, this is terrible...
>
>> + writel(sec, ioaddr + PTP_STSUR);
>> + writel(nsec, ioaddr + PTP_STNSUR);
>> + /* issue command to initialize the system time value */
>> + value = readl(ioaddr + PTP_TCR);
>> + value |= PTP_TCR_TSINIT;
>> + writel(value, ioaddr + PTP_TCR);
>> +
>> + /* wait for present system time initialize to complete */
>> + limit = 100;
>> + while (limit--) {
>> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
>> + break;
>> + mdelay(10);
>> + }
>> + if (limit < 0)
>> + return -EBUSY;
>
> ... for a number of reasons.
>
> 1. You are polling for 100*10ms = one second, and the caller has
> disabled interrupts! This is way too long. Is the hardware really
> that slow? If so, then you need to use delayed work or find some
> other way not to block.
>
> 2. You are waiting both before and after for the status bit. Pick one
> or the other. You don't need both.
>
> This same pattern is repeated a few times here, and it needs fixing in
> each case.
This is for the Author. I've no HW where test. Rayagond tested all on
his side. Pls Rayagond fixes it and gives me the new code.
>> + struct stmmac_priv *priv = netdev_priv(dev);
>> + struct hwtstamp_config config;
>> + struct timespec now;
>> + u64 temp = 0;
>
> You add this new code here, but you change it all around again a few
> patches later. Please just submit the final, combined version.
we kept these separately because the patch #5 (for example) depends on
another one that adds the extended descriptor support. Also If I add
all the code in a single patch this will be very big. I had some
problems to review all separately. So I suspect that if we merge all
in a single patch this will not help (especially myself). At any rate,
tell me if you prefer to have a single patch. I can do that.
peppe
>
> Thanks,
> Richard
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
2013-03-07 20:34 ` [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) David Miller
@ 2013-03-08 7:16 ` Giuseppe CAVALLARO
2013-03-08 16:22 ` David Miller
0 siblings, 1 reply; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-08 7:16 UTC (permalink / raw)
To: David Miller; +Cc: netdev, bh74.an, Rayagond K
Hello David
On 3/7/2013 9:34 PM, David Miller wrote:
> From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
> Date: Thu, 7 Mar 2013 11:50:10 +0100
>
>> The PTP support is quite intrusive because it needs to support the extended
>> descriptors used for saving the HW timestamps.
>> These are available in new chip generations, only.
>> So we have actually found useful to use some Kconfig options to
>> surround PTP and extended descriptor support. This approach helped on
>> old platform (embeeded system) where PTP is not supported and where we
>> do not want to pay extra code and check in critical rx/tx paths.
>
> I would prefer run time handling of all of this.
>
> You do not need to put extra checks in the fast paths, instead you
> have different methods that get hooked up into the netdev_ops
> based upon chip capabilities/features/mode.
I don't also like to see ifdef in C code and I always tried to
avoid them in the stmmac.
Indeed I haven't well explained the main reason of this Kconfig. Sorry!
To support PTPv2, we need to change the main descriptor structure
adding new fields (DES4,5,6,7).
The DESC4 is used for saving some extra information. For this reason
I added this support in a separate patch.
The DES6/7 are used for saving HW timestamps.
Unfortunately this new layout breaks the compatibility with old chips.
On new chips that supports the extended descriptors, in fact, we have a
ATDS bit in the DMA MODE register to allow the DMA to use the new
alternate structure.
This is not completely supported in old chips.
For this reason I decided to add these extra Koption.
Welcome advice.
Peppe
>
> Thanks.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
2013-03-08 7:02 ` Giuseppe CAVALLARO
@ 2013-03-08 7:51 ` Rayagond K
2013-03-10 12:25 ` Richard Cochran
[not found] ` <CAJ3bTp6tQ4L0vya9-eO0E+19Wk74uNJonbA9hqc+fgN77dcjOQ@mail.gmail.com>
2 siblings, 0 replies; 29+ messages in thread
From: Rayagond K @ 2013-03-08 7:51 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: Richard Cochran, netdev, bh74.an
On Fri, Mar 8, 2013 at 12:32 PM, Giuseppe CAVALLARO
<peppe.cavallaro@st.com> wrote:
>
> On 3/8/2013 7:34 AM, Richard Cochran wrote:
>>
>> I have a few comments, below.
>
>
> thanks for them.
>
>
>>> HW Timestamp support can be enabled while configuring the Kernel and
>>> the Koption is: STMMAC_USE_HWSTAMP
>>> At runtime, the support is verified by looking at the HW capability
>>> register.
>>
>>
>> As davem said, since you have the ability to detect this at run time,
>> then there is no need for a kconfig option.
>
>
> I'll try to give you more details about this replying to D. Miller
>
> [snip]
>
>
>>> + /* get tx/rx timestamp low value */
>>> + u32 (*get_timestamp_low) (struct dma_desc *p);
>>> + /* get tx/rx timestamp high value */
>>> + u32 (*get_timestamp_high) (struct dma_desc *p);
>>
>>
>> These two separate functions should be combined into one.
>
>
> ok
>
>
>>> + /* get rx timestamp status */
>>> + int (*get_rx_timestamp_status) (struct dma_desc *p);
>
>
>>> +
>>> +static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
>>> +{
>>> + /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
>>
>>
>> Why not fix these FIXMEs for the next respin?
>
>
> This is fixed in the patch #5 where we use the extended descriptors
> for PTP2.
>
>
>>> + if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
>>> + /* timestamp is currupted, hence don't store it */
>>
>>
>> corrupted
>
>
> thanks
>
>
>
>>> + /* Convert the ptp_clock to nano second
>>> + * formula = (1/ptp_clock) * 1000000000
>>> + * where, ptp_clock = 50MHz for FINE correction method &
>>> + * ptp_clock = STMMAC_SYSCLOCK for COARSE correction method
>>> + */
>>
>>
>> What are these coarse/fine method? Can't we always use the fine one?
>
>
> This is explained in the "4.1.2 System Time Register Module" of Synopsys
> Databook. Summarizing, the MAC can have an optional module and use this
> coarse correction method. In the fine correction method, a slave clock’s
> frequency drift with respect to the master clock is corrected over a period
> of time instead of in one clock, as in coarse correction.
>
> Pls, Rayagond feels free to provide more details...
Yes Synopsys core support two method for correcting the system time ie
COARSE method and FINE method.
In the fine correction method, a slave clock’s frequency drift with
respect to the master clock (as defined in IEEE 1588) is corrected
over a period of time instead of in one clock, as in coarse
correction. This helps maintain linear time and does not introduce
drastic changes (or a large jitter) in the reference time between PTP
Sync message intervals.
And updating the SSNR (Sub Second Increment Register) depends on which
method is selected during the initialization.
>
>>> + if (value & PTP_TCR_TSCFUPDT)
>>> + data = (1000000000ULL / 50000000);
>>> + else
>>> + data = (1000000000ULL / STMMAC_SYSCLOCK);
>>> +
>>> + writel(data, ioaddr + PTP_SSIR);
>>> +}
>>> +
>>> +static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
>>> +{
>>> + int limit;
>>> + u32 value;
>>> +
>>> + /* wait for previous(if any) system time initialize to complete
>>> */
>>> + limit = 100;
>>> + while (limit--) {
>>> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
>>> + break;
>>> + mdelay(10);
>>> + }
>>> +
>>> + if (limit < 0)
>>> + return -EBUSY;
>>> +
>>
>>
>> Ugh, this is terrible...
>>
>>> + writel(sec, ioaddr + PTP_STSUR);
>>> + writel(nsec, ioaddr + PTP_STNSUR);
>>> + /* issue command to initialize the system time value */
>>> + value = readl(ioaddr + PTP_TCR);
>>> + value |= PTP_TCR_TSINIT;
>>> + writel(value, ioaddr + PTP_TCR);
>>> +
>>> + /* wait for present system time initialize to complete */
>>> + limit = 100;
>>> + while (limit--) {
>>> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
>>> + break;
>>> + mdelay(10);
>>> + }
>>> + if (limit < 0)
>>> + return -EBUSY;
>>
>>
>> ... for a number of reasons.
>>
>> 1. You are polling for 100*10ms = one second, and the caller has
>> disabled interrupts! This is way too long. Is the hardware really
>> that slow? If so, then you need to use delayed work or find some
>> other way not to block.
Sorry for this, during testing I just used maximum delay as there was
bug in the HW initially. But after fixing the HW issue I noticed that
HW is not that much slow. We will reduce the delay in all functions.
>>
>> 2. You are waiting both before and after for the status bit. Pick one
>> or the other. You don't need both.
>>
>> This same pattern is repeated a few times here, and it needs fixing in
>> each case.
Sure will change it. I added just to make sure double check here.
Practically first wait is not required, will remove this.
>
>
> This is for the Author. I've no HW where test. Rayagond tested all on his
> side. Pls Rayagond fixes it and gives me the new code.
>
>
>>> + struct stmmac_priv *priv = netdev_priv(dev);
>>> + struct hwtstamp_config config;
>>> + struct timespec now;
>>> + u64 temp = 0;
>>
>>
>> You add this new code here, but you change it all around again a few
>> patches later. Please just submit the final, combined version.
>
>
> we kept these separately because the patch #5 (for example) depends on
> another one that adds the extended descriptor support. Also If I add
> all the code in a single patch this will be very big. I had some
> problems to review all separately. So I suspect that if we merge all
> in a single patch this will not help (especially myself). At any rate,
> tell me if you prefer to have a single patch. I can do that.
>
> peppe
>>
>>
>> Thanks,
>> Richard
>>
>
Thanks
Rayagond.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
2013-03-08 7:16 ` Giuseppe CAVALLARO
@ 2013-03-08 16:22 ` David Miller
2013-03-11 7:11 ` Giuseppe CAVALLARO
0 siblings, 1 reply; 29+ messages in thread
From: David Miller @ 2013-03-08 16:22 UTC (permalink / raw)
To: peppe.cavallaro; +Cc: netdev, bh74.an, rayagond
From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
Date: Fri, 08 Mar 2013 08:16:24 +0100
> Hello David
>
> On 3/7/2013 9:34 PM, David Miller wrote:
>> From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
>> Date: Thu, 7 Mar 2013 11:50:10 +0100
>>
>>> The PTP support is quite intrusive because it needs to support the
>>> extended
>>> descriptors used for saving the HW timestamps.
>>> These are available in new chip generations, only.
>>> So we have actually found useful to use some Kconfig options to
>>> surround PTP and extended descriptor support. This approach helped on
>>> old platform (embeeded system) where PTP is not supported and where we
>>> do not want to pay extra code and check in critical rx/tx paths.
>>
>> I would prefer run time handling of all of this.
>>
>> You do not need to put extra checks in the fast paths, instead you
>> have different methods that get hooked up into the netdev_ops
>> based upon chip capabilities/features/mode.
...
> Welcome advice.
Exactly what I told you above. You have two sets of routines,
one that deal with the older descriptors and one set that deals
with the new descriptors that can do PTP.
And you hook up different interrupt handler, NAPI poll, and
netdev_ops based upon the chip's capabilities.
You need no runtime testing, only a test a probe time to setup
things up properly.
What is so hard about this to understand?
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 4/9] stmmac: add the support for PTP hw clock driver
2013-03-07 10:50 ` [net-next.git 4/9] stmmac: add the support for PTP hw clock driver Giuseppe CAVALLARO
@ 2013-03-10 12:10 ` Richard Cochran
[not found] ` <CAJ3bTp7n-Y6TYrhDMe58fALtX5O34qifO9khWYXpo-OwnrRKiQ@mail.gmail.com>
0 siblings, 1 reply; 29+ messages in thread
From: Richard Cochran @ 2013-03-10 12:10 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: netdev, bh74.an, ayagond, Rayagond Kokatanur
I have a few comments, below.
On Thu, Mar 07, 2013 at 11:50:14AM +0100, Giuseppe CAVALLARO wrote:
> From: Rayagond Kokatanur <rayagond@vayavyalabs.com>
>
> This patch implements PHC (ptp hardware clock) driver for stmmac
> driver to support 1588 PTP.
>
> Signed-off-by: Rayagond Kokatanur <rayagond@vayavyalabs.com>
> Hacked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
> ---
> drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +-
> drivers/net/ethernet/stmicro/stmmac/common.h | 4 +
> drivers/net/ethernet/stmicro/stmmac/stmmac.h | 13 ++
> .../net/ethernet/stmicro/stmmac/stmmac_hwstamp.c | 50 +++++
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 31 +++-
> drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 209 ++++++++++++++++++++
> drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 2 +
> 7 files changed, 303 insertions(+), 8 deletions(-)
> create mode 100644 drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
> index cc97c07..40ee3df 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
> +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
> @@ -3,7 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
> stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
> stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
> stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
> -stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o
> +stmmac-$(CONFIG_STMMAC_USE_HWSTAMP) += stmmac_hwstamp.o stmmac_ptp.o
> stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
> dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
> dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
> diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
> index df7123a..a10974c 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/common.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/common.h
> @@ -387,6 +387,10 @@ struct stmmac_hwtimestamp {
> void (*config_sub_second_increment) (void __iomem *ioaddr);
> int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
> int (*config_addend)(void __iomem *ioaddr, u32 addend);
> + int (*adjust_systime)(void __iomem *ioaddr, u32 sec, u32 nsec,
> + int add_sub);
> + u32 (*get_systime_sec)(void __iomem *ioaddr);
> + u32 (*get_systime_nsec)(void __iomem *ioaddr);
No need here for two separate functions. Combine them into one get_systime().
> };
> #endif
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> index 50b5f26..2d6e2e1 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
> @@ -32,6 +32,10 @@
> #include <linux/pci.h>
> #include "common.h"
>
> +#ifdef CONFIG_STMMAC_USE_HWSTAMP
> +#include <linux/ptp_clock_kernel.h>
> +#endif
> +
> struct stmmac_priv {
> /* Frequently used values are kept adjacent for cache effect */
> struct dma_desc *dma_tx ____cacheline_aligned;
> @@ -98,6 +102,9 @@ struct stmmac_priv {
> int hwts_tx_en;
> int hwts_rx_en;
> unsigned int default_addend;
> + struct ptp_clock *ptp_clock;
> + struct ptp_clock_info ptp_clock_ops;
> + spinlock_t ptp_lock;
> #endif
> int atds;
> };
> @@ -111,6 +118,12 @@ extern const struct stmmac_desc_ops enh_desc_ops;
> extern const struct stmmac_desc_ops ndesc_ops;
> #ifdef CONFIG_STMMAC_USE_HWSTAMP
> extern const struct stmmac_hwtimestamp stmmac_ptp;
> +extern int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
> + int add_sub);
> +extern u32 stmmac_get_systime_sec(void __iomem *ioaddr);
> +extern u32 stmmac_get_systime_nsec(void __iomem *ioaddr);
> +extern int stmmac_ptp_register(struct stmmac_priv *priv);
> +extern void stmmac_ptp_unregister(struct stmmac_priv *priv);
> #endif
> int stmmac_freeze(struct net_device *ndev);
> int stmmac_restore(struct net_device *ndev);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
> index be9e399..bec2278 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwstamp.c
> @@ -121,9 +121,59 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
> return 0;
> }
>
> +static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
> + int add_sub)
> +{
> + u32 value;
> + int limit;
> +
> + /* wait for previous(if any) system time adjust/update to complete */
These busy loops also need fixing, like in the other patch.
> + limit = 100;
> + while (limit--) {
> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
> + break;
> + mdelay(10);
> + }
> + if (limit < 0)
> + return -EBUSY;
> +
> + writel(sec, ioaddr + PTP_STSUR);
> + writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
> + ioaddr + PTP_STNSUR);
> + /* issue command to initialize the system time value */
> + value = readl(ioaddr + PTP_TCR);
> + value |= PTP_TCR_TSUPDT;
> + writel(value, ioaddr + PTP_TCR);
> +
> + /* wait for present system time adjust/update to complete */
> + limit = 100;
> + while (limit--) {
> + if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
> + break;
> + mdelay(10);
> + }
> + if (limit < 0)
> + return -EBUSY;
> +
> + return 0;
> +}
> +
> +static u32 stmmac_get_systime_sec(void __iomem *ioaddr)
> +{
> + return readl(ioaddr + PTP_STSR);
> +}
> +
> +static u32 stmmac_get_systime_nsec(void __iomem *ioaddr)
> +{
> + return readl(ioaddr + PTP_STNSR);
> +}
> +
> const struct stmmac_hwtimestamp stmmac_ptp = {
> .config_hw_tstamping = stmmac_config_hw_tstamping,
> .init_systime = stmmac_init_systime,
> .config_sub_second_increment = stmmac_config_sub_second_increment,
> .config_addend = stmmac_config_addend,
> + .adjust_systime = stmmac_adjust_systime,
> + .get_systime_sec = stmmac_get_systime_sec,
> + .get_systime_nsec = stmmac_get_systime_nsec,
> };
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 6174f34..009abf8 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -474,24 +474,37 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
> sizeof(struct hwtstamp_config)) ? -EFAULT : 0;
> }
>
> -static void stmmac_init_ptp(struct stmmac_priv *priv)
> +static int stmmac_init_ptp(struct stmmac_priv *priv)
> {
> - if (priv->dma_cap.time_stamp)
> - pr_debug("IEEE 1588-2002 Time Stamp supported\n");
> - if (priv->dma_cap.atime_stamp)
> - pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
> + if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
> + return -EOPNOTSUPP;
> +
> + if (netif_msg_hw(priv)) {
> + if (priv->dma_cap.time_stamp)
> + pr_debug("IEEE 1588-2002 Time Stamp supported\n");
> + if (priv->dma_cap.atime_stamp)
> + pr_debug("IEEE 1588-2008 Advanced Time Stamp supported\n");
> + }
>
> priv->hw->ptp = &stmmac_ptp;
>
> priv->hwts_tx_en = 0;
> priv->hwts_rx_en = 0;
>
> + return stmmac_ptp_register(priv);
> +}
> +
> +static void stmmac_release_ptp(struct stmmac_priv *priv)
> +{
> + stmmac_ptp_unregister(priv);
> }
> +
> #else
> #define stmmac_hwtstamp_ioctl(dev, ifr) (-EOPNOTSUPP)
> #define stmmac_get_rx_hwtstamp(priv, p, skb)
> #define stmmac_get_tx_hwtstamp(priv, p, skb) 0
> -#define stmmac_init_ptp(priv)
> +#define stmmac_init_ptp(priv) 0
> +#define stmmac_release_ptp(priv)
> #endif /* CONFIG_STMMAC_USE_HWSTAMP */
>
> /**
> @@ -1301,7 +1314,9 @@ static int stmmac_open(struct net_device *dev)
>
> stmmac_mmc_setup(priv);
>
> - stmmac_init_ptp(priv);
> + ret = stmmac_init_ptp(priv);
> + if (ret)
> + pr_warn("%s: failed PTP initialisation\n", __func__);
>
> #ifdef CONFIG_STMMAC_DEBUG_FS
> ret = stmmac_init_fs(dev);
> @@ -1403,6 +1418,8 @@ static int stmmac_release(struct net_device *dev)
> #endif
> clk_disable_unprepare(priv->stmmac_clk);
>
> + stmmac_release_ptp(priv);
> +
> return 0;
> }
>
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
> new file mode 100644
> index 0000000..53680bf
> --- /dev/null
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
> @@ -0,0 +1,209 @@
> +/*******************************************************************************
> + PTP 1588 clock using the STMMAC.
> +
> + Copyright (C) 2013 Vayavya Labs Pvt Ltd
> +
> + This program is free software; you can redistribute it and/or modify it
> + under the terms and conditions of the GNU General Public License,
> + version 2, as published by the Free Software Foundation.
> +
> + This program is distributed in the hope it will be useful, but WITHOUT
> + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + more details.
> +
> + You should have received a copy of the GNU General Public License along with
> + this program; if not, write to the Free Software Foundation, Inc.,
> + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
> +
> + The full GNU General Public License is included in this distribution in
> + the file called "COPYING".
> +
> + Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
> +*******************************************************************************/
> +#include "stmmac.h"
> +#include "stmmac_ptp.h"
> +
> +/**
> + * stmmac_adjust_freq
> + *
> + * @ptp: pointer to ptp_clock_info structure
> + * @ppb: desired period change in parts ber billion
> + *
> + * Description: this function will adjust the frequency of hardware clock.
> + */
> +static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
> +{
> + struct stmmac_priv *priv =
> + container_of(ptp, struct stmmac_priv, ptp_clock_ops);
> + u32 diff, addend;
> + int neg_adj = 0;
> + u64 adj;
> +
> + if (ppb < 0) {
> + neg_adj = 1;
> + ppb = -ppb;
> + }
> +
> + addend = priv->default_addend;
> + adj = addend;
> + adj *= ppb;
> + /* div_u64 will divided the "adj" by "1000000000ULL"
> + * and return the quotient
> + */
No need to comment what div_u64 does. We know that already.
> + diff = div_u64(adj, 1000000000ULL);
> +
> + addend = neg_adj ? (addend - diff) : (addend + diff);
> +
> + priv->hw->ptp->config_addend(priv->ioaddr, addend);
Don't you need locking here to protect against concurrent callers of
config_addend?
> +
> + return 0;
> +}
> +
> +/**
> + * stmmac_adjust_time
> + *
> + * @ptp: pointer to ptp_clock_info structure
> + * @delta: desired change in nanoseconds
> + *
> + * Description: this function will shift/adjust the hardware clock time.
> + */
> +static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
> +{
> + struct stmmac_priv *priv =
> + container_of(ptp, struct stmmac_priv, ptp_clock_ops);
> + unsigned long flags;
> + u32 sec, nsec;
> + u32 quotient, reminder;
> + int neg_adj = 0;
> +
> + spin_lock_irqsave(&priv->ptp_lock, flags);
You have locked too much code here. The arithmetic on stack variables
is already reentrant.
> +
> + if (delta < 0) {
> + neg_adj = 1;
> + delta = -delta;
> + }
> +
> + quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
> + sec = quotient;
> + nsec = reminder;
Lock here instead.
> + priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
> +
> + spin_unlock_irqrestore(&priv->lock, flags);
> +
> + return 0;
> +}
> +
> +/**
> + * stmmac_get_time
> + *
> + * @ptp: pointer to ptp_clock_info structure
> + * @ts: pointer to hold time/result
> + *
> + * Description: this function will read the current time from the
> + * hardware clock and store it in @ts.
> + */
> +static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
> +{
> + struct stmmac_priv *priv =
> + container_of(ptp, struct stmmac_priv, ptp_clock_ops);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->ptp_lock, flags);
> +
> + ts->tv_sec = priv->hw->ptp->get_systime_sec(priv->ioaddr);
> + ts->tv_nsec = priv->hw->ptp->get_systime_nsec(priv->ioaddr);
See, use just one function instead of two.
> +
> + spin_unlock_irqrestore(&priv->ptp_lock, flags);
> +
> + return 0;
> +}
> +
> +/**
> + * stmmac_set_time
> + *
> + * @ptp: pointer to ptp_clock_info structure
> + * @ts: time value to set
> + *
> + * Description: this function will set the current time on the
> + * hardware clock.
> + */
> +static int stmmac_set_time(struct ptp_clock_info *ptp,
> + const struct timespec *ts)
> +{
> + struct stmmac_priv *priv =
> + container_of(ptp, struct stmmac_priv, ptp_clock_ops);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->ptp_lock, flags);
> +
> + priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
> +
> + spin_unlock_irqrestore(&priv->ptp_lock, flags);
> +
> + return 0;
> +}
> +
> +static int stmmac_enable(struct ptp_clock_info *ptp,
> + struct ptp_clock_request *rq, int on)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +/* structure describing a PTP hardware clock */
> +static struct ptp_clock_info stmmac_ptp_clock_ops = {
> + .owner = THIS_MODULE,
> + .name = "stmmac_ptp_clock",
> + .max_adj = STMMAC_SYSCLOCK,
This should be the maximum adjustment supported by the clock, in parts
per billion, not the clock frequency.
> + .n_alarm = 0,
> + .n_ext_ts = 0,
> + .n_per_out = 0,
> + .pps = 0,
> + .adjfreq = stmmac_adjust_freq,
> + .adjtime = stmmac_adjust_time,
> + .gettime = stmmac_get_time,
> + .settime = stmmac_set_time,
> + .enable = stmmac_enable,
> +};
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
2013-03-08 7:02 ` Giuseppe CAVALLARO
2013-03-08 7:51 ` Rayagond K
@ 2013-03-10 12:25 ` Richard Cochran
2013-03-10 12:40 ` Richard Cochran
2013-03-11 6:35 ` Giuseppe CAVALLARO
[not found] ` <CAJ3bTp6tQ4L0vya9-eO0E+19Wk74uNJonbA9hqc+fgN77dcjOQ@mail.gmail.com>
2 siblings, 2 replies; 29+ messages in thread
From: Richard Cochran @ 2013-03-10 12:25 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: netdev, bh74.an, Rayagond K
On Fri, Mar 08, 2013 at 08:02:21AM +0100, Giuseppe CAVALLARO wrote:
> On 3/8/2013 7:34 AM, Richard Cochran wrote:
> >>+
> >>+static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
> >>+{
> >>+ /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
> >
> >Why not fix these FIXMEs for the next respin?
>
> This is fixed in the patch #5 where we use the extended descriptors
> for PTP2.
If possible, it is nice for the reviewers and for the logic of the
patch series to order the changes so that these FIXMEs go away.
> >>+ struct hwtstamp_config config;
> >>+ struct timespec now;
> >>+ u64 temp = 0;
> >
> >You add this new code here, but you change it all around again a few
> >patches later. Please just submit the final, combined version.
>
> we kept these separately because the patch #5 (for example) depends on
> another one that adds the extended descriptor support. Also If I add
> all the code in a single patch this will be very big. I had some
> problems to review all separately. So I suspect that if we merge all
> in a single patch this will not help (especially myself). At any rate,
> tell me if you prefer to have a single patch. I can do that.
I am not asking for bigger patches. It is good to arrange your patches
in small steps, since that makes both reviewing and bisecting easier.
However, for brand new code, I find it quite annoying to read one
patch, and then to have it all re-written in the next one. (If a new
function *only* grows during a patch series, that is easy to follow.)
So what I would like to see is a logical, understandable series of
small steps, but when new code appears, it is the real, final form.
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
[not found] ` <CAJ3bTp6tQ4L0vya9-eO0E+19Wk74uNJonbA9hqc+fgN77dcjOQ@mail.gmail.com>
@ 2013-03-10 12:31 ` Richard Cochran
0 siblings, 0 replies; 29+ messages in thread
From: Richard Cochran @ 2013-03-10 12:31 UTC (permalink / raw)
To: Rayagond K; +Cc: Giuseppe CAVALLARO, netdev, bh74.an
On Fri, Mar 08, 2013 at 01:15:00PM +0530, Rayagond K wrote:
> On Fri, Mar 8, 2013 at 12:32 PM, Giuseppe CAVALLARO <peppe.cavallaro@st.com>wrote:
> > On 3/8/2013 7:34 AM, Richard Cochran wrote:
> >> What are these coarse/fine method? Can't we always use the fine one?
> >>
> >
> > This is explained in the "4.1.2 System Time Register Module" of Synopsys
> > Databook. Summarizing, the MAC can have an optional module and use this
> > coarse correction method. In the fine correction method, a slave clock’s
> > frequency drift with respect to the master clock is corrected over a period
> > of time instead of in one clock, as in coarse correction.
> >
> > Pls, Rayagond feels free to provide more details...
>
>
> Yes Synopsys core support two method for correcting the system time
> ie COARSE method and FINE method.
>
> In the fine correction method, a slave clock’s frequency drift with respect
> to the master clock (as defined in IEEE 1588) is corrected over a period of
> time instead of in one clock, as in coarse correction. This helps maintain
> linear time and does not introduce drastic changes (or a large jitter) in
> the reference time between PTP Sync message intervals.
So it sounds like to me that you only should offer the COARSE
method. Smoothly changing the frequency of the clock is the job of the
clock servo which is running in user space.
Although some clocks (like this one and the phyter, for example) have
the ability to smoothly correct a given offset over a given time, we
do not have any user/kernel API for making use of this feature.
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info
2013-03-07 10:50 ` [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info Giuseppe CAVALLARO
@ 2013-03-10 12:36 ` Richard Cochran
2013-03-11 6:39 ` Giuseppe CAVALLARO
0 siblings, 1 reply; 29+ messages in thread
From: Richard Cochran @ 2013-03-10 12:36 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: netdev, bh74.an, ayagond
On Thu, Mar 07, 2013 at 11:50:16AM +0100, Giuseppe CAVALLARO wrote:
> This patch updates the filters for ethtool's get_ts_info to return support for
> all filters which can be supported after having added the PTP support.
This code should ideally appear in the same patch where the filtering
support first appears.
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
2013-03-10 12:25 ` Richard Cochran
@ 2013-03-10 12:40 ` Richard Cochran
2013-03-11 6:35 ` Giuseppe CAVALLARO
1 sibling, 0 replies; 29+ messages in thread
From: Richard Cochran @ 2013-03-10 12:40 UTC (permalink / raw)
To: Giuseppe CAVALLARO; +Cc: netdev, bh74.an, Rayagond K
On Sun, Mar 10, 2013 at 01:25:54PM +0100, Richard Cochran wrote:
> So what I would like to see is a logical, understandable series of
> small steps, but when new code appears, it is the real, final form.
Here is the order of patches that has made sense for other cards:
1. add hw time stamping support (all possible kinds) via so_timestamping
2. add ptp hardware clock support via ptp_clock_register
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support
2013-03-10 12:25 ` Richard Cochran
2013-03-10 12:40 ` Richard Cochran
@ 2013-03-11 6:35 ` Giuseppe CAVALLARO
1 sibling, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-11 6:35 UTC (permalink / raw)
To: Richard Cochran; +Cc: netdev, bh74.an, Rayagond K
On 3/10/2013 1:25 PM, Richard Cochran wrote:
> On Fri, Mar 08, 2013 at 08:02:21AM +0100, Giuseppe CAVALLARO wrote:
>> On 3/8/2013 7:34 AM, Richard Cochran wrote:
>
>>>> +
>>>> +static int enh_desc_get_rx_timestamp_status(struct dma_desc *p)
>>>> +{
>>>> + /* FIXME if Enhance descriptor with 8 DWORDS is enabled */
>>>
>>> Why not fix these FIXMEs for the next respin?
>>
>> This is fixed in the patch #5 where we use the extended descriptors
>> for PTP2.
>
> If possible, it is nice for the reviewers and for the logic of the
> patch series to order the changes so that these FIXMEs go away.
>
>>>> + struct hwtstamp_config config;
>>>> + struct timespec now;
>>>> + u64 temp = 0;
>>>
>>> You add this new code here, but you change it all around again a few
>>> patches later. Please just submit the final, combined version.
>>
>> we kept these separately because the patch #5 (for example) depends on
>> another one that adds the extended descriptor support. Also If I add
>> all the code in a single patch this will be very big. I had some
>> problems to review all separately. So I suspect that if we merge all
>> in a single patch this will not help (especially myself). At any rate,
>> tell me if you prefer to have a single patch. I can do that.
>
> I am not asking for bigger patches. It is good to arrange your patches
> in small steps, since that makes both reviewing and bisecting easier.
I tried to do that :-(
>
> However, for brand new code, I find it quite annoying to read one
> patch, and then to have it all re-written in the next one. (If a new
> function *only* grows during a patch series, that is easy to follow.)
>
> So what I would like to see is a logical, understandable series of
> small steps, but when new code appears, it is the real, final form.
Ok, I'll try to better re-organize the patches in the next version.
Thx a lot
Peppe
>
> Thanks,
> Richard
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info
2013-03-10 12:36 ` Richard Cochran
@ 2013-03-11 6:39 ` Giuseppe CAVALLARO
0 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-11 6:39 UTC (permalink / raw)
To: Richard Cochran; +Cc: netdev, bh74.an, ayagond
On 3/10/2013 1:36 PM, Richard Cochran wrote:
> On Thu, Mar 07, 2013 at 11:50:16AM +0100, Giuseppe CAVALLARO wrote:
>> This patch updates the filters for ethtool's get_ts_info to return support for
>> all filters which can be supported after having added the PTP support.
>
> This code should ideally appear in the same patch where the filtering
> support first appears.
Ok, I'll add it inside the patch that adds the support.
peppe
>
> Thanks,
> Richard
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
2013-03-08 16:22 ` David Miller
@ 2013-03-11 7:11 ` Giuseppe CAVALLARO
2013-03-22 14:27 ` Giuseppe CAVALLARO
0 siblings, 1 reply; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-11 7:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev, bh74.an, rayagond
On 3/8/2013 5:22 PM, David Miller wrote:
> From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
> Date: Fri, 08 Mar 2013 08:16:24 +0100
>
>> Hello David
>>
>> On 3/7/2013 9:34 PM, David Miller wrote:
>>> From: Giuseppe CAVALLARO <peppe.cavallaro@st.com>
>>> Date: Thu, 7 Mar 2013 11:50:10 +0100
>>>
>>>> The PTP support is quite intrusive because it needs to support the
>>>> extended
>>>> descriptors used for saving the HW timestamps.
>>>> These are available in new chip generations, only.
>>>> So we have actually found useful to use some Kconfig options to
>>>> surround PTP and extended descriptor support. This approach helped on
>>>> old platform (embeeded system) where PTP is not supported and where we
>>>> do not want to pay extra code and check in critical rx/tx paths.
>>>
>>> I would prefer run time handling of all of this.
>>>
>>> You do not need to put extra checks in the fast paths, instead you
>>> have different methods that get hooked up into the netdev_ops
>>> based upon chip capabilities/features/mode.
> ...
>> Welcome advice.
>
> Exactly what I told you above. You have two sets of routines,
> one that deal with the older descriptors and one set that deals
> with the new descriptors that can do PTP.
>
> And you hook up different interrupt handler, NAPI poll, and
> netdev_ops based upon the chip's capabilities.
>
> You need no runtime testing, only a test a probe time to setup
> things up properly.
> What is so hard about this to understand?
This is exactly what the driver does to manage different chip versions
w/o using any ifdef. So fortunately I had already understood this :-).
Unfortunately, just in this case, I've met some problems on
implementing the code because We have three cases:
1- normal desc
2- enhanced desc.
3- enhanced desc + extended desc.
-------------
|_ Also used for PTPv2
To support extended desc (3) we have to modify the main descriptor
structure and it is not good for the case (2) where the DMA will expect
to use these descriptors:
-------------
| des0 | status / conf
-------------
| des1 | status / conf
-------------
| des2 | Buffer 1 Address [31:0]
-------------
| des3 | Buffer 2 Address [31:0] or Next Descriptor Addr
-------------
but we have added other 4 fields:
struct des {
unsigned int des0;
unsigned int des1;
unsigned int des2;
unsigned int des3;
unsigned int des4; |
unsigned int des5; |_ extended
unsigned int des6; |
unsigned int des7; |
}
and this structure cannot be used.
In fact, if the HW supports the extended desc we have to program a
register to allow the DMA to walk through the new structure.
At any case, I'll arrange to change the code removing the Koption and
continuing (as done in the past) to setup at probe time the right
configuration. This will be in the next version of the patches.
Thx
Peppe
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 4/9] stmmac: add the support for PTP hw clock driver
[not found] ` <CAJ3bTp7n-Y6TYrhDMe58fALtX5O34qifO9khWYXpo-OwnrRKiQ@mail.gmail.com>
@ 2013-03-11 18:55 ` Richard Cochran
2013-03-12 4:43 ` Rayagond K
0 siblings, 1 reply; 29+ messages in thread
From: Richard Cochran @ 2013-03-11 18:55 UTC (permalink / raw)
To: Rayagond K; +Cc: Giuseppe CAVALLARO, netdev, bh74.an
On Sun, Mar 10, 2013 at 08:37:24PM +0530, Rayagond K wrote:
> On Sun, Mar 10, 2013 at 5:40 PM, Richard Cochran <richardcochran@gmail.com>wrote:
> > Don't you need locking here to protect against concurrent callers of
> > config_addend?
> >
>
> Yes we need locking here too, will add it.
>
> But I can see no locking in this function in other two driver'e
> ppt_ixp46x.c and gianfar_ptp.c. So I just followed these two driver.
Those two drivers don't need locking, because setting the addend
register is a single 32 bit write operation in both cases.
In your driver, setting the addend involves a sequence of writes and
reads, in addition to polling a status bit, so you do need to
serialize access to those registers.
Thanks,
Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 4/9] stmmac: add the support for PTP hw clock driver
2013-03-11 18:55 ` Richard Cochran
@ 2013-03-12 4:43 ` Rayagond K
0 siblings, 0 replies; 29+ messages in thread
From: Rayagond K @ 2013-03-12 4:43 UTC (permalink / raw)
To: Richard Cochran; +Cc: Giuseppe CAVALLARO, netdev, bh74.an
On Tue, Mar 12, 2013 at 12:25 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> On Sun, Mar 10, 2013 at 08:37:24PM +0530, Rayagond K wrote:
>> On Sun, Mar 10, 2013 at 5:40 PM, Richard Cochran <richardcochran@gmail.com>wrote:
>
>> > Don't you need locking here to protect against concurrent callers of
>> > config_addend?
>> >
>>
>> Yes we need locking here too, will add it.
>>
>> But I can see no locking in this function in other two driver'e
>> ppt_ixp46x.c and gianfar_ptp.c. So I just followed these two driver.
>
> Those two drivers don't need locking, because setting the addend
> register is a single 32 bit write operation in both cases.
>
> In your driver, setting the addend involves a sequence of writes and
> reads, in addition to polling a status bit, so you do need to
> serialize access to those registers.
Okay, will take lock in our driver. Thank you.
>
> Thanks,
> Richard
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII)
2013-03-11 7:11 ` Giuseppe CAVALLARO
@ 2013-03-22 14:27 ` Giuseppe CAVALLARO
0 siblings, 0 replies; 29+ messages in thread
From: Giuseppe CAVALLARO @ 2013-03-22 14:27 UTC (permalink / raw)
To: netdev; +Cc: David Miller, bh74.an, rayagond, Richard Cochran
On 3/11/2013 8:11 AM, Giuseppe CAVALLARO wrote:
[snip]
> At any case, I'll arrange to change the code removing the Koption and
> continuing (as done in the past) to setup at probe time the right
> configuration. This will be in the next version of the patches.
I've finally completed this task and I've reworked all the code to
completely remove the Koption (also for chain/ring mode).
Now all is done at probe time as discussed in this email thread.
On top of this, the PTP will be ported with Richard's advice
Pls let me know if there are other suggestions about the patches, I have
sent, so I can review and update them before resending the new versions.
peppe
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2013-03-22 14:44 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-07 10:50 [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 1/9] stmmac: add tx_skbuff_dma to save descriptors used by PTP Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 2/9] stmmac: add IEEE 1588-2002 PTP support Giuseppe CAVALLARO
2013-03-08 6:34 ` Richard Cochran
2013-03-08 7:02 ` Giuseppe CAVALLARO
2013-03-08 7:51 ` Rayagond K
2013-03-10 12:25 ` Richard Cochran
2013-03-10 12:40 ` Richard Cochran
2013-03-11 6:35 ` Giuseppe CAVALLARO
[not found] ` <CAJ3bTp6tQ4L0vya9-eO0E+19Wk74uNJonbA9hqc+fgN77dcjOQ@mail.gmail.com>
2013-03-10 12:31 ` Richard Cochran
2013-03-07 10:50 ` [net-next.git 3/9] stmmac: support extend descriptors Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 4/9] stmmac: add the support for PTP hw clock driver Giuseppe CAVALLARO
2013-03-10 12:10 ` Richard Cochran
[not found] ` <CAJ3bTp7n-Y6TYrhDMe58fALtX5O34qifO9khWYXpo-OwnrRKiQ@mail.gmail.com>
2013-03-11 18:55 ` Richard Cochran
2013-03-12 4:43 ` Rayagond K
2013-03-07 10:50 ` [net-next.git 5/9] stmmac: add IEEE 1588-2008 PTP V2 support Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 6/9] stmmac: add missing supported filters to get_ts_info Giuseppe CAVALLARO
2013-03-10 12:36 ` Richard Cochran
2013-03-11 6:39 ` Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 7/9] stmmac: start adding pcs and rgmii core irq Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 8/9] stmmac: initial support to manage pcs modes Giuseppe CAVALLARO
2013-03-07 10:50 ` [net-next.git 9/9] stmmac: update the Doc and Version (PTP+SGMII) Giuseppe CAVALLARO
2013-03-07 20:34 ` [net-next.git 0/9] stmmac: update to March_2013 (adding PTP & RGMII/SGMII) David Miller
2013-03-08 7:16 ` Giuseppe CAVALLARO
2013-03-08 16:22 ` David Miller
2013-03-11 7:11 ` Giuseppe CAVALLARO
2013-03-22 14:27 ` Giuseppe CAVALLARO
2013-03-08 6:04 ` Richard Cochran
2013-03-08 6:39 ` Giuseppe CAVALLARO
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).