Commit 744dfcb1 authored by David S. Miller's avatar David S. Miller

Merge branch 'stmmac-ptp'

Giuseppe Cavallaro says:

====================
stmmac: fix PTP support

This subset of patches aim to fix the PTP support
for the stmmac and especially for 4.x chip series.
While setting PTP on an ST box with 4.00a Ethernet
core, the kernel panics due to a broken settings
of the descriptors. The patches review the
register configuration, the algo used for configuring
the protocol, the way to get the timestamp inside
the RX/TX descriptors and, in the end, the statistics
displayed by ethtool.

V2: RESEND all the patches adding the Acked-by.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 24803f38 ee112c12
...@@ -120,14 +120,17 @@ struct stmmac_extra_stats { ...@@ -120,14 +120,17 @@ struct stmmac_extra_stats {
unsigned long ip_csum_bypassed; unsigned long ip_csum_bypassed;
unsigned long ipv4_pkt_rcvd; unsigned long ipv4_pkt_rcvd;
unsigned long ipv6_pkt_rcvd; unsigned long ipv6_pkt_rcvd;
unsigned long rx_msg_type_ext_no_ptp; unsigned long no_ptp_rx_msg_type_ext;
unsigned long rx_msg_type_sync; unsigned long ptp_rx_msg_type_sync;
unsigned long rx_msg_type_follow_up; unsigned long ptp_rx_msg_type_follow_up;
unsigned long rx_msg_type_delay_req; unsigned long ptp_rx_msg_type_delay_req;
unsigned long rx_msg_type_delay_resp; unsigned long ptp_rx_msg_type_delay_resp;
unsigned long rx_msg_type_pdelay_req; unsigned long ptp_rx_msg_type_pdelay_req;
unsigned long rx_msg_type_pdelay_resp; unsigned long ptp_rx_msg_type_pdelay_resp;
unsigned long rx_msg_type_pdelay_follow_up; unsigned long ptp_rx_msg_type_pdelay_follow_up;
unsigned long ptp_rx_msg_type_announce;
unsigned long ptp_rx_msg_type_management;
unsigned long ptp_rx_msg_pkt_reserved_type;
unsigned long ptp_frame_type; unsigned long ptp_frame_type;
unsigned long ptp_ver; unsigned long ptp_ver;
unsigned long timestamp_dropped; unsigned long timestamp_dropped;
...@@ -482,11 +485,12 @@ struct stmmac_ops { ...@@ -482,11 +485,12 @@ struct stmmac_ops {
/* PTP and HW Timer helpers */ /* PTP and HW Timer helpers */
struct stmmac_hwtimestamp { struct stmmac_hwtimestamp {
void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data); void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
u32 (*config_sub_second_increment) (void __iomem *ioaddr, u32 clk_rate); u32 (*config_sub_second_increment)(void __iomem *ioaddr, u32 ptp_clock,
int gmac4);
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec); int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
int (*config_addend) (void __iomem *ioaddr, u32 addend); int (*config_addend) (void __iomem *ioaddr, u32 addend);
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec, int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
int add_sub); int add_sub, int gmac4);
u64(*get_systime) (void __iomem *ioaddr); u64(*get_systime) (void __iomem *ioaddr);
}; };
......
...@@ -155,14 +155,18 @@ ...@@ -155,14 +155,18 @@
#define ERDES4_L3_L4_FILT_NO_MATCH_MASK GENMASK(27, 26) #define ERDES4_L3_L4_FILT_NO_MATCH_MASK GENMASK(27, 26)
/* Extended RDES4 message type definitions */ /* Extended RDES4 message type definitions */
#define RDES_EXT_NO_PTP 0 #define RDES_EXT_NO_PTP 0x0
#define RDES_EXT_SYNC 1 #define RDES_EXT_SYNC 0x1
#define RDES_EXT_FOLLOW_UP 2 #define RDES_EXT_FOLLOW_UP 0x2
#define RDES_EXT_DELAY_REQ 3 #define RDES_EXT_DELAY_REQ 0x3
#define RDES_EXT_DELAY_RESP 4 #define RDES_EXT_DELAY_RESP 0x4
#define RDES_EXT_PDELAY_REQ 5 #define RDES_EXT_PDELAY_REQ 0x5
#define RDES_EXT_PDELAY_RESP 6 #define RDES_EXT_PDELAY_RESP 0x6
#define RDES_EXT_PDELAY_FOLLOW_UP 7 #define RDES_EXT_PDELAY_FOLLOW_UP 0x7
#define RDES_PTP_ANNOUNCE 0x8
#define RDES_PTP_MANAGEMENT 0x9
#define RDES_PTP_SIGNALING 0xa
#define RDES_PTP_PKT_RESERVED_TYPE 0xf
/* Basic descriptor structure for normal and alternate descriptors */ /* Basic descriptor structure for normal and alternate descriptors */
struct dma_desc { struct dma_desc {
......
...@@ -123,22 +123,29 @@ static int dwmac4_wrback_get_rx_status(void *data, struct stmmac_extra_stats *x, ...@@ -123,22 +123,29 @@ static int dwmac4_wrback_get_rx_status(void *data, struct stmmac_extra_stats *x,
x->ipv4_pkt_rcvd++; x->ipv4_pkt_rcvd++;
if (rdes1 & RDES1_IPV6_HEADER) if (rdes1 & RDES1_IPV6_HEADER)
x->ipv6_pkt_rcvd++; x->ipv6_pkt_rcvd++;
if (message_type == RDES_EXT_SYNC)
x->rx_msg_type_sync++; if (message_type == RDES_EXT_NO_PTP)
x->no_ptp_rx_msg_type_ext++;
else if (message_type == RDES_EXT_SYNC)
x->ptp_rx_msg_type_sync++;
else if (message_type == RDES_EXT_FOLLOW_UP) else if (message_type == RDES_EXT_FOLLOW_UP)
x->rx_msg_type_follow_up++; x->ptp_rx_msg_type_follow_up++;
else if (message_type == RDES_EXT_DELAY_REQ) else if (message_type == RDES_EXT_DELAY_REQ)
x->rx_msg_type_delay_req++; x->ptp_rx_msg_type_delay_req++;
else if (message_type == RDES_EXT_DELAY_RESP) else if (message_type == RDES_EXT_DELAY_RESP)
x->rx_msg_type_delay_resp++; x->ptp_rx_msg_type_delay_resp++;
else if (message_type == RDES_EXT_PDELAY_REQ) else if (message_type == RDES_EXT_PDELAY_REQ)
x->rx_msg_type_pdelay_req++; x->ptp_rx_msg_type_pdelay_req++;
else if (message_type == RDES_EXT_PDELAY_RESP) else if (message_type == RDES_EXT_PDELAY_RESP)
x->rx_msg_type_pdelay_resp++; x->ptp_rx_msg_type_pdelay_resp++;
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP) else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
x->rx_msg_type_pdelay_follow_up++; x->ptp_rx_msg_type_pdelay_follow_up++;
else else if (message_type == RDES_PTP_ANNOUNCE)
x->rx_msg_type_ext_no_ptp++; x->ptp_rx_msg_type_announce++;
else if (message_type == RDES_PTP_MANAGEMENT)
x->ptp_rx_msg_type_management++;
else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
x->ptp_rx_msg_pkt_reserved_type++;
if (rdes1 & RDES1_PTP_PACKET_TYPE) if (rdes1 & RDES1_PTP_PACKET_TYPE)
x->ptp_frame_type++; x->ptp_frame_type++;
...@@ -204,14 +211,18 @@ static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p) ...@@ -204,14 +211,18 @@ static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p)
static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p) static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p)
{ {
return (p->des3 & TDES3_TIMESTAMP_STATUS) /* Context type from W/B descriptor must be zero */
>> TDES3_TIMESTAMP_STATUS_SHIFT; if (p->des3 & TDES3_CONTEXT_TYPE)
return -EINVAL;
/* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
if (p->des3 & TDES3_TIMESTAMP_STATUS)
return 0;
return 1;
} }
/* NOTE: For RX CTX bit has to be checked before static inline u64 dwmac4_get_timestamp(void *desc, u32 ats)
* HAVE a specific function for TX and another one for RX
*/
static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
{ {
struct dma_desc *p = (struct dma_desc *)desc; struct dma_desc *p = (struct dma_desc *)desc;
u64 ns; u64 ns;
...@@ -223,12 +234,54 @@ static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats) ...@@ -223,12 +234,54 @@ static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
return ns; return ns;
} }
static int dwmac4_context_get_rx_timestamp_status(void *desc, u32 ats) static int dwmac4_rx_check_timestamp(void *desc)
{ {
struct dma_desc *p = (struct dma_desc *)desc; struct dma_desc *p = (struct dma_desc *)desc;
u32 own, ctxt;
int ret = 1;
own = p->des3 & RDES3_OWN;
ctxt = ((p->des3 & RDES3_CONTEXT_DESCRIPTOR)
>> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
return (p->des1 & RDES1_TIMESTAMP_AVAILABLE) if (likely(!own && ctxt)) {
>> RDES1_TIMESTAMP_AVAILABLE_SHIFT; if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
/* Corrupted value */
ret = -EINVAL;
else
/* A valid Timestamp is ready to be read */
ret = 0;
}
/* Timestamp not ready */
return ret;
}
static int dwmac4_wrback_get_rx_timestamp_status(void *desc, u32 ats)
{
struct dma_desc *p = (struct dma_desc *)desc;
int ret = -EINVAL;
/* Get the status from normal w/b descriptor */
if (likely(p->des3 & TDES3_RS1V)) {
if (likely(p->des1 & RDES1_TIMESTAMP_AVAILABLE)) {
int i = 0;
/* Check if timestamp is OK from context descriptor */
do {
ret = dwmac4_rx_check_timestamp(desc);
if (ret < 0)
goto exit;
i++;
} while ((ret == 1) || (i < 10));
if (i == 10)
ret = -EBUSY;
}
}
exit:
return ret;
} }
static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic, static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
...@@ -373,8 +426,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = { ...@@ -373,8 +426,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
.get_rx_frame_len = dwmac4_wrback_get_rx_frame_len, .get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
.enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp, .enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
.get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status, .get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,
.get_timestamp = dwmac4_wrback_get_timestamp, .get_rx_timestamp_status = dwmac4_wrback_get_rx_timestamp_status,
.get_rx_timestamp_status = dwmac4_context_get_rx_timestamp_status, .get_timestamp = dwmac4_get_timestamp,
.set_tx_ic = dwmac4_rd_set_tx_ic, .set_tx_ic = dwmac4_rd_set_tx_ic,
.prepare_tx_desc = dwmac4_rd_prepare_tx_desc, .prepare_tx_desc = dwmac4_rd_prepare_tx_desc,
.prepare_tso_tx_desc = dwmac4_rd_prepare_tso_tx_desc, .prepare_tso_tx_desc = dwmac4_rd_prepare_tso_tx_desc,
......
...@@ -59,10 +59,13 @@ ...@@ -59,10 +59,13 @@
#define TDES3_CTXT_TCMSSV BIT(26) #define TDES3_CTXT_TCMSSV BIT(26)
/* TDES3 Common */ /* TDES3 Common */
#define TDES3_RS1V BIT(26)
#define TDES3_RS1V_SHIFT 26
#define TDES3_LAST_DESCRIPTOR BIT(28) #define TDES3_LAST_DESCRIPTOR BIT(28)
#define TDES3_LAST_DESCRIPTOR_SHIFT 28 #define TDES3_LAST_DESCRIPTOR_SHIFT 28
#define TDES3_FIRST_DESCRIPTOR BIT(29) #define TDES3_FIRST_DESCRIPTOR BIT(29)
#define TDES3_CONTEXT_TYPE BIT(30) #define TDES3_CONTEXT_TYPE BIT(30)
#define TDES3_CONTEXT_TYPE_SHIFT 30
/* TDS3 use for both format (read and write back) */ /* TDS3 use for both format (read and write back) */
#define TDES3_OWN BIT(31) #define TDES3_OWN BIT(31)
...@@ -117,6 +120,7 @@ ...@@ -117,6 +120,7 @@
#define RDES3_LAST_DESCRIPTOR BIT(28) #define RDES3_LAST_DESCRIPTOR BIT(28)
#define RDES3_FIRST_DESCRIPTOR BIT(29) #define RDES3_FIRST_DESCRIPTOR BIT(29)
#define RDES3_CONTEXT_DESCRIPTOR BIT(30) #define RDES3_CONTEXT_DESCRIPTOR BIT(30)
#define RDES3_CONTEXT_DESCRIPTOR_SHIFT 30
/* RDES3 (read format) */ /* RDES3 (read format) */
#define RDES3_BUFFER1_VALID_ADDR BIT(24) #define RDES3_BUFFER1_VALID_ADDR BIT(24)
......
...@@ -150,22 +150,30 @@ static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x, ...@@ -150,22 +150,30 @@ static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
x->ipv4_pkt_rcvd++; x->ipv4_pkt_rcvd++;
if (rdes4 & ERDES4_IPV6_PKT_RCVD) if (rdes4 & ERDES4_IPV6_PKT_RCVD)
x->ipv6_pkt_rcvd++; x->ipv6_pkt_rcvd++;
if (message_type == RDES_EXT_SYNC)
x->rx_msg_type_sync++; if (message_type == RDES_EXT_NO_PTP)
x->no_ptp_rx_msg_type_ext++;
else if (message_type == RDES_EXT_SYNC)
x->ptp_rx_msg_type_sync++;
else if (message_type == RDES_EXT_FOLLOW_UP) else if (message_type == RDES_EXT_FOLLOW_UP)
x->rx_msg_type_follow_up++; x->ptp_rx_msg_type_follow_up++;
else if (message_type == RDES_EXT_DELAY_REQ) else if (message_type == RDES_EXT_DELAY_REQ)
x->rx_msg_type_delay_req++; x->ptp_rx_msg_type_delay_req++;
else if (message_type == RDES_EXT_DELAY_RESP) else if (message_type == RDES_EXT_DELAY_RESP)
x->rx_msg_type_delay_resp++; x->ptp_rx_msg_type_delay_resp++;
else if (message_type == RDES_EXT_PDELAY_REQ) else if (message_type == RDES_EXT_PDELAY_REQ)
x->rx_msg_type_pdelay_req++; x->ptp_rx_msg_type_pdelay_req++;
else if (message_type == RDES_EXT_PDELAY_RESP) else if (message_type == RDES_EXT_PDELAY_RESP)
x->rx_msg_type_pdelay_resp++; x->ptp_rx_msg_type_pdelay_resp++;
else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP) else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
x->rx_msg_type_pdelay_follow_up++; x->ptp_rx_msg_type_pdelay_follow_up++;
else else if (message_type == RDES_PTP_ANNOUNCE)
x->rx_msg_type_ext_no_ptp++; x->ptp_rx_msg_type_announce++;
else if (message_type == RDES_PTP_MANAGEMENT)
x->ptp_rx_msg_type_management++;
else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
x->ptp_rx_msg_pkt_reserved_type++;
if (rdes4 & ERDES4_PTP_FRAME_TYPE) if (rdes4 & ERDES4_PTP_FRAME_TYPE)
x->ptp_frame_type++; x->ptp_frame_type++;
if (rdes4 & ERDES4_PTP_VER) if (rdes4 & ERDES4_PTP_VER)
......
...@@ -129,6 +129,7 @@ struct stmmac_priv { ...@@ -129,6 +129,7 @@ struct stmmac_priv {
int irq_wake; int irq_wake;
spinlock_t ptp_lock; spinlock_t ptp_lock;
void __iomem *mmcaddr; void __iomem *mmcaddr;
void __iomem *ptpaddr;
u32 rx_tail_addr; u32 rx_tail_addr;
u32 tx_tail_addr; u32 tx_tail_addr;
u32 mss; u32 mss;
......
...@@ -115,14 +115,17 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = { ...@@ -115,14 +115,17 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
STMMAC_STAT(ip_csum_bypassed), STMMAC_STAT(ip_csum_bypassed),
STMMAC_STAT(ipv4_pkt_rcvd), STMMAC_STAT(ipv4_pkt_rcvd),
STMMAC_STAT(ipv6_pkt_rcvd), STMMAC_STAT(ipv6_pkt_rcvd),
STMMAC_STAT(rx_msg_type_ext_no_ptp), STMMAC_STAT(no_ptp_rx_msg_type_ext),
STMMAC_STAT(rx_msg_type_sync), STMMAC_STAT(ptp_rx_msg_type_sync),
STMMAC_STAT(rx_msg_type_follow_up), STMMAC_STAT(ptp_rx_msg_type_follow_up),
STMMAC_STAT(rx_msg_type_delay_req), STMMAC_STAT(ptp_rx_msg_type_delay_req),
STMMAC_STAT(rx_msg_type_delay_resp), STMMAC_STAT(ptp_rx_msg_type_delay_resp),
STMMAC_STAT(rx_msg_type_pdelay_req), STMMAC_STAT(ptp_rx_msg_type_pdelay_req),
STMMAC_STAT(rx_msg_type_pdelay_resp), STMMAC_STAT(ptp_rx_msg_type_pdelay_resp),
STMMAC_STAT(rx_msg_type_pdelay_follow_up), STMMAC_STAT(ptp_rx_msg_type_pdelay_follow_up),
STMMAC_STAT(ptp_rx_msg_type_announce),
STMMAC_STAT(ptp_rx_msg_type_management),
STMMAC_STAT(ptp_rx_msg_pkt_reserved_type),
STMMAC_STAT(ptp_frame_type), STMMAC_STAT(ptp_frame_type),
STMMAC_STAT(ptp_ver), STMMAC_STAT(ptp_ver),
STMMAC_STAT(timestamp_dropped), STMMAC_STAT(timestamp_dropped),
......
...@@ -34,21 +34,29 @@ static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data) ...@@ -34,21 +34,29 @@ static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
} }
static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr,
u32 ptp_clock) u32 ptp_clock, int gmac4)
{ {
u32 value = readl(ioaddr + PTP_TCR); u32 value = readl(ioaddr + PTP_TCR);
unsigned long data; unsigned long data;
/* Convert the ptp_clock to nano second /* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second
* formula = (2/ptp_clock) * 1000000000 * formula = (1/ptp_clock) * 1000000000
* where, ptp_clock = 50MHz. * where ptp_clock is 50MHz if fine method is used to update system
*/ */
data = (2000000000ULL / ptp_clock); if (value & PTP_TCR_TSCFUPDT)
data = (1000000000ULL / 50000000);
else
data = (1000000000ULL / ptp_clock);
/* 0.465ns accuracy */ /* 0.465ns accuracy */
if (!(value & PTP_TCR_TSCTRLSSR)) if (!(value & PTP_TCR_TSCTRLSSR))
data = (data * 1000) / 465; data = (data * 1000) / 465;
data &= PTP_SSIR_SSINC_MASK;
if (gmac4)
data = data << GMAC4_PTP_SSIR_SSINC_SHIFT;
writel(data, ioaddr + PTP_SSIR); writel(data, ioaddr + PTP_SSIR);
return data; return data;
...@@ -104,14 +112,30 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend) ...@@ -104,14 +112,30 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
} }
static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec, static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
int add_sub) int add_sub, int gmac4)
{ {
u32 value; u32 value;
int limit; int limit;
if (add_sub) {
/* If the new sec value needs to be subtracted with
* the system time, then MAC_STSUR reg should be
* programmed with (2^32 – <new_sec_value>)
*/
if (gmac4)
sec = (100000000ULL - sec);
value = readl(ioaddr + PTP_TCR);
if (value & PTP_TCR_TSCTRLSSR)
nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
else
nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
}
writel(sec, ioaddr + PTP_STSUR); writel(sec, ioaddr + PTP_STSUR);
writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec), value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
ioaddr + PTP_STNSUR); writel(value, ioaddr + PTP_STNSUR);
/* issue command to initialize the system time value */ /* issue command to initialize the system time value */
value = readl(ioaddr + PTP_TCR); value = readl(ioaddr + PTP_TCR);
value |= PTP_TCR_TSUPDT; value |= PTP_TCR_TSUPDT;
...@@ -134,8 +158,9 @@ static u64 stmmac_get_systime(void __iomem *ioaddr) ...@@ -134,8 +158,9 @@ static u64 stmmac_get_systime(void __iomem *ioaddr)
{ {
u64 ns; u64 ns;
/* Get the TSSS value */
ns = readl(ioaddr + PTP_STNSR); ns = readl(ioaddr + PTP_STNSR);
/* convert sec time value to nanosecond */ /* Get the TSS and convert sec time value to nanosecond */
ns += readl(ioaddr + PTP_STSR) * 1000000000ULL; ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
return ns; return ns;
......
...@@ -340,18 +340,17 @@ bool stmmac_eee_init(struct stmmac_priv *priv) ...@@ -340,18 +340,17 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
/* stmmac_get_tx_hwtstamp - get HW TX timestamps /* stmmac_get_tx_hwtstamp - get HW TX timestamps
* @priv: driver private structure * @priv: driver private structure
* @entry : descriptor index to be used. * @p : descriptor pointer
* @skb : the socket buffer * @skb : the socket buffer
* Description : * Description :
* This function will read timestamp from the descriptor & pass it to stack. * This function will read timestamp from the descriptor & pass it to stack.
* and also perform some sanity checks. * and also perform some sanity checks.
*/ */
static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
unsigned int entry, struct sk_buff *skb) struct dma_desc *p, struct sk_buff *skb)
{ {
struct skb_shared_hwtstamps shhwtstamp; struct skb_shared_hwtstamps shhwtstamp;
u64 ns; u64 ns;
void *desc = NULL;
if (!priv->hwts_tx_en) if (!priv->hwts_tx_en)
return; return;
...@@ -360,58 +359,55 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv, ...@@ -360,58 +359,55 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
if (likely(!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS))) if (likely(!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
return; return;
if (priv->adv_ts)
desc = (priv->dma_etx + entry);
else
desc = (priv->dma_tx + entry);
/* check tx tstamp status */ /* check tx tstamp status */
if (!priv->hw->desc->get_tx_timestamp_status((struct dma_desc *)desc)) if (!priv->hw->desc->get_tx_timestamp_status(p)) {
return;
/* get the valid tstamp */ /* get the valid tstamp */
ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts); ns = priv->hw->desc->get_timestamp(p, priv->adv_ts);
memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps)); memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
shhwtstamp.hwtstamp = ns_to_ktime(ns); shhwtstamp.hwtstamp = ns_to_ktime(ns);
netdev_info(priv->dev, "get valid TX hw timestamp %llu\n", ns);
/* pass tstamp to stack */ /* pass tstamp to stack */
skb_tstamp_tx(skb, &shhwtstamp); skb_tstamp_tx(skb, &shhwtstamp);
}
return; return;
} }
/* stmmac_get_rx_hwtstamp - get HW RX timestamps /* stmmac_get_rx_hwtstamp - get HW RX timestamps
* @priv: driver private structure * @priv: driver private structure
* @entry : descriptor index to be used. * @p : descriptor pointer
* @np : next descriptor pointer
* @skb : the socket buffer * @skb : the socket buffer
* Description : * Description :
* This function will read received packet's timestamp from the descriptor * This function will read received packet's timestamp from the descriptor
* and pass it to stack. It also perform some sanity checks. * and pass it to stack. It also perform some sanity checks.
*/ */
static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p,
unsigned int entry, struct sk_buff *skb) struct dma_desc *np, struct sk_buff *skb)
{ {
struct skb_shared_hwtstamps *shhwtstamp = NULL; struct skb_shared_hwtstamps *shhwtstamp = NULL;
u64 ns; u64 ns;
void *desc = NULL;
if (!priv->hwts_rx_en) if (!priv->hwts_rx_en)
return; return;
if (priv->adv_ts) /* Check if timestamp is available */
desc = (priv->dma_erx + entry); if (!priv->hw->desc->get_rx_timestamp_status(p, priv->adv_ts)) {
/* For GMAC4, the valid timestamp is from CTX next desc. */
if (priv->plat->has_gmac4)
ns = priv->hw->desc->get_timestamp(np, priv->adv_ts);
else else
desc = (priv->dma_rx + entry); ns = priv->hw->desc->get_timestamp(p, priv->adv_ts);
/* exit if rx tstamp is not valid */
if (!priv->hw->desc->get_rx_timestamp_status(desc, priv->adv_ts))
return;
/* get valid tstamp */ netdev_info(priv->dev, "get valid RX hw timestamp %llu\n", ns);
ns = priv->hw->desc->get_timestamp(desc, priv->adv_ts);
shhwtstamp = skb_hwtstamps(skb); shhwtstamp = skb_hwtstamps(skb);
memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps)); memset(shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
shhwtstamp->hwtstamp = ns_to_ktime(ns); shhwtstamp->hwtstamp = ns_to_ktime(ns);
} else {
netdev_err(priv->dev, "cannot get RX hw timestamp\n");
}
} }
/** /**
...@@ -598,17 +594,18 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -598,17 +594,18 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON; priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON;
if (!priv->hwts_tx_en && !priv->hwts_rx_en) if (!priv->hwts_tx_en && !priv->hwts_rx_en)
priv->hw->ptp->config_hw_tstamping(priv->ioaddr, 0); priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, 0);
else { else {
value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR | value = (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | PTP_TCR_TSCTRLSSR |
tstamp_all | ptp_v2 | ptp_over_ethernet | tstamp_all | ptp_v2 | ptp_over_ethernet |
ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en | ptp_over_ipv6_udp | ptp_over_ipv4_udp | ts_event_en |
ts_master_en | snap_type_sel); ts_master_en | snap_type_sel);
priv->hw->ptp->config_hw_tstamping(priv->ioaddr, value); priv->hw->ptp->config_hw_tstamping(priv->ptpaddr, value);
/* program Sub Second Increment reg */ /* program Sub Second Increment reg */
sec_inc = priv->hw->ptp->config_sub_second_increment( sec_inc = priv->hw->ptp->config_sub_second_increment(
priv->ioaddr, priv->clk_ptp_rate); priv->ptpaddr, priv->clk_ptp_rate,
priv->plat->has_gmac4);
temp = div_u64(1000000000ULL, sec_inc); temp = div_u64(1000000000ULL, sec_inc);
/* calculate default added value: /* calculate default added value:
...@@ -618,14 +615,14 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -618,14 +615,14 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
*/ */
temp = (u64)(temp << 32); temp = (u64)(temp << 32);
priv->default_addend = div_u64(temp, priv->clk_ptp_rate); priv->default_addend = div_u64(temp, priv->clk_ptp_rate);
priv->hw->ptp->config_addend(priv->ioaddr, priv->hw->ptp->config_addend(priv->ptpaddr,
priv->default_addend); priv->default_addend);
/* initialize system time */ /* initialize system time */
ktime_get_real_ts64(&now); ktime_get_real_ts64(&now);
/* lower 32 bits of tv_sec are safe until y2106 */ /* lower 32 bits of tv_sec are safe until y2106 */
priv->hw->ptp->init_systime(priv->ioaddr, (u32)now.tv_sec, priv->hw->ptp->init_systime(priv->ptpaddr, (u32)now.tv_sec,
now.tv_nsec); now.tv_nsec);
} }
...@@ -1340,7 +1337,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv) ...@@ -1340,7 +1337,7 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
priv->dev->stats.tx_packets++; priv->dev->stats.tx_packets++;
priv->xstats.tx_pkt_n++; priv->xstats.tx_pkt_n++;
} }
stmmac_get_tx_hwtstamp(priv, entry, skb); stmmac_get_tx_hwtstamp(priv, p, skb);
} }
if (likely(priv->tx_skbuff_dma[entry].buf)) { if (likely(priv->tx_skbuff_dma[entry].buf)) {
...@@ -1486,10 +1483,13 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv) ...@@ -1486,10 +1483,13 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv)
unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET |
MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET;
if (priv->synopsys_id >= DWMAC_CORE_4_00) if (priv->synopsys_id >= DWMAC_CORE_4_00) {
priv->ptpaddr = priv->ioaddr + PTP_GMAC4_OFFSET;
priv->mmcaddr = priv->ioaddr + MMC_GMAC4_OFFSET; priv->mmcaddr = priv->ioaddr + MMC_GMAC4_OFFSET;
else } else {
priv->ptpaddr = priv->ioaddr + PTP_GMAC3_X_OFFSET;
priv->mmcaddr = priv->ioaddr + MMC_GMAC3_X_OFFSET; priv->mmcaddr = priv->ioaddr + MMC_GMAC3_X_OFFSET;
}
dwmac_mmc_intr_all_mask(priv->mmcaddr); dwmac_mmc_intr_all_mask(priv->mmcaddr);
...@@ -2484,7 +2484,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) ...@@ -2484,7 +2484,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
if (netif_msg_rx_status(priv)) { if (netif_msg_rx_status(priv)) {
void *rx_head; void *rx_head;
pr_debug("%s: descriptor ring:\n", __func__); pr_info(">>>>>> %s: descriptor ring:\n", __func__);
if (priv->extend_desc) if (priv->extend_desc)
rx_head = (void *)priv->dma_erx; rx_head = (void *)priv->dma_erx;
else else
...@@ -2495,6 +2495,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) ...@@ -2495,6 +2495,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
while (count < limit) { while (count < limit) {
int status; int status;
struct dma_desc *p; struct dma_desc *p;
struct dma_desc *np;
if (priv->extend_desc) if (priv->extend_desc)
p = (struct dma_desc *)(priv->dma_erx + entry); p = (struct dma_desc *)(priv->dma_erx + entry);
...@@ -2514,9 +2515,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) ...@@ -2514,9 +2515,11 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
next_entry = priv->cur_rx; next_entry = priv->cur_rx;
if (priv->extend_desc) if (priv->extend_desc)
prefetch(priv->dma_erx + next_entry); np = (struct dma_desc *)(priv->dma_erx + next_entry);
else else
prefetch(priv->dma_rx + next_entry); np = priv->dma_rx + next_entry;
prefetch(np);
if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status)) if ((priv->extend_desc) && (priv->hw->desc->rx_extended_status))
priv->hw->desc->rx_extended_status(&priv->dev->stats, priv->hw->desc->rx_extended_status(&priv->dev->stats,
...@@ -2568,7 +2571,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) ...@@ -2568,7 +2571,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
frame_len -= ETH_FCS_LEN; frame_len -= ETH_FCS_LEN;
if (netif_msg_rx_status(priv)) { if (netif_msg_rx_status(priv)) {
pr_debug("\tdesc: %p [entry %d] buff=0x%x\n", pr_info("\tdesc: %p [entry %d] buff=0x%x\n",
p, entry, des); p, entry, des);
if (frame_len > ETH_FRAME_LEN) if (frame_len > ETH_FRAME_LEN)
pr_debug("\tframe size %d, COE: %d\n", pr_debug("\tframe size %d, COE: %d\n",
...@@ -2625,13 +2628,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) ...@@ -2625,13 +2628,13 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
} }
stmmac_get_rx_hwtstamp(priv, entry, skb);
if (netif_msg_pktdata(priv)) { if (netif_msg_pktdata(priv)) {
pr_debug("frame received (%dbytes)", frame_len); pr_debug("frame received (%dbytes)", frame_len);
print_pkt(skb->data, frame_len); print_pkt(skb->data, frame_len);
} }
stmmac_get_rx_hwtstamp(priv, p, np, skb);
stmmac_rx_vlan(priv->dev, skb); stmmac_rx_vlan(priv->dev, skb);
skb->protocol = eth_type_trans(skb, priv->dev); skb->protocol = eth_type_trans(skb, priv->dev);
......
...@@ -54,7 +54,7 @@ static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb) ...@@ -54,7 +54,7 @@ static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
spin_lock_irqsave(&priv->ptp_lock, flags); spin_lock_irqsave(&priv->ptp_lock, flags);
priv->hw->ptp->config_addend(priv->ioaddr, addend); priv->hw->ptp->config_addend(priv->ptpaddr, addend);
spin_unlock_irqrestore(&priv->ptp_lock, flags); spin_unlock_irqrestore(&priv->ptp_lock, flags);
...@@ -89,7 +89,8 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) ...@@ -89,7 +89,8 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
spin_lock_irqsave(&priv->ptp_lock, flags); spin_lock_irqsave(&priv->ptp_lock, flags);
priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj); priv->hw->ptp->adjust_systime(priv->ptpaddr, sec, nsec, neg_adj,
priv->plat->has_gmac4);
spin_unlock_irqrestore(&priv->ptp_lock, flags); spin_unlock_irqrestore(&priv->ptp_lock, flags);
...@@ -114,7 +115,7 @@ static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts) ...@@ -114,7 +115,7 @@ static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts)
spin_lock_irqsave(&priv->ptp_lock, flags); spin_lock_irqsave(&priv->ptp_lock, flags);
ns = priv->hw->ptp->get_systime(priv->ioaddr); ns = priv->hw->ptp->get_systime(priv->ptpaddr);
spin_unlock_irqrestore(&priv->ptp_lock, flags); spin_unlock_irqrestore(&priv->ptp_lock, flags);
...@@ -141,7 +142,7 @@ static int stmmac_set_time(struct ptp_clock_info *ptp, ...@@ -141,7 +142,7 @@ static int stmmac_set_time(struct ptp_clock_info *ptp,
spin_lock_irqsave(&priv->ptp_lock, flags); spin_lock_irqsave(&priv->ptp_lock, flags);
priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec); priv->hw->ptp->init_systime(priv->ptpaddr, ts->tv_sec, ts->tv_nsec);
spin_unlock_irqrestore(&priv->ptp_lock, flags); spin_unlock_irqrestore(&priv->ptp_lock, flags);
......
...@@ -25,48 +25,50 @@ ...@@ -25,48 +25,50 @@
#ifndef __STMMAC_PTP_H__ #ifndef __STMMAC_PTP_H__
#define __STMMAC_PTP_H__ #define __STMMAC_PTP_H__
#define PTP_GMAC4_OFFSET 0xb00
#define PTP_GMAC3_X_OFFSET 0x700
/* IEEE 1588 PTP register offsets */ /* IEEE 1588 PTP register offsets */
#define PTP_TCR 0x0700 /* Timestamp Control Reg */ #define PTP_TCR 0x00 /* Timestamp Control Reg */
#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */ #define PTP_SSIR 0x04 /* Sub-Second Increment Reg */
#define PTP_STSR 0x0708 /* System Time – Seconds Regr */ #define PTP_STSR 0x08 /* System Time – Seconds Regr */
#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */ #define PTP_STNSR 0x0c /* System Time – Nanoseconds Reg */
#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */ #define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */
#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */ #define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */
#define PTP_TAR 0x0718 /* Timestamp Addend Reg */ #define PTP_TAR 0x18 /* 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 */
#define PTP_STNSUR_ADDSUB_SHIFT 31 #define PTP_STNSUR_ADDSUB_SHIFT 31
#define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */
#define PTP_BINARY_ROLLOVER_MODE 0x80000000 /* ~0.466 ns */
/* PTP TCR defines */ /* PTP Timestamp control register defines */
#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */ #define PTP_TCR_TSENA BIT(0) /* Timestamp Enable */
#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */ #define PTP_TCR_TSCFUPDT BIT(1) /* Timestamp Fine/Coarse Update */
#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */ #define PTP_TCR_TSINIT BIT(2) /* Timestamp Initialize */
#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */ #define PTP_TCR_TSUPDT BIT(3) /* Timestamp Update */
/* Timestamp Interrupt Trigger Enable */ #define PTP_TCR_TSTRIG BIT(4) /* Timestamp Interrupt Trigger Enable */
#define PTP_TCR_TSTRIG 0x00000010 #define PTP_TCR_TSADDREG BIT(5) /* Addend Reg Update */
#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */ #define PTP_TCR_TSENALL BIT(8) /* Enable Timestamp for All Frames */
#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */ #define PTP_TCR_TSCTRLSSR BIT(9) /* Digital or Binary Rollover Control */
/* Timestamp Digital or Binary Rollover Control */
#define PTP_TCR_TSCTRLSSR 0x00000200
/* Enable PTP packet Processing for Version 2 Format */ /* Enable PTP packet Processing for Version 2 Format */
#define PTP_TCR_TSVER2ENA 0x00000400 #define PTP_TCR_TSVER2ENA BIT(10)
/* Enable Processing of PTP over Ethernet Frames */ /* Enable Processing of PTP over Ethernet Frames */
#define PTP_TCR_TSIPENA 0x00000800 #define PTP_TCR_TSIPENA BIT(11)
/* Enable Processing of PTP Frames Sent over IPv6-UDP */ /* Enable Processing of PTP Frames Sent over IPv6-UDP */
#define PTP_TCR_TSIPV6ENA 0x00001000 #define PTP_TCR_TSIPV6ENA BIT(12)
/* Enable Processing of PTP Frames Sent over IPv4-UDP */ /* Enable Processing of PTP Frames Sent over IPv4-UDP */
#define PTP_TCR_TSIPV4ENA 0x00002000 #define PTP_TCR_TSIPV4ENA BIT(13)
/* Enable Timestamp Snapshot for Event Messages */ /* Enable Timestamp Snapshot for Event Messages */
#define PTP_TCR_TSEVNTENA 0x00004000 #define PTP_TCR_TSEVNTENA BIT(14)
/* Enable Snapshot for Messages Relevant to Master */ /* Enable Snapshot for Messages Relevant to Master */
#define PTP_TCR_TSMSTRENA 0x00008000 #define PTP_TCR_TSMSTRENA BIT(15)
/* Select PTP packets for Taking Snapshots */ /* Select PTP packets for Taking Snapshots */
#define PTP_TCR_SNAPTYPSEL_1 0x00010000 #define PTP_TCR_SNAPTYPSEL_1 GENMASK(17, 16)
/* Enable MAC address for PTP Frame Filtering */ /* Enable MAC address for PTP Frame Filtering */
#define PTP_TCR_TSENMACADDR 0x00040000 #define PTP_TCR_TSENMACADDR BIT(18)
/* SSIR defines */
#define PTP_SSIR_SSINC_MASK 0xff
#define GMAC4_PTP_SSIR_SSINC_SHIFT 16
#endif /* __STMMAC_PTP_H__ */ #endif /* __STMMAC_PTP_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment