Skip to content

Commit ba1ffd7

Browse files
cavagiudavem330
authored andcommitted
stmmac: fix PTP support for GMAC4
Due to bad management of the descriptors, when use ptp4l, kernel panics as shown below: ----------------------------------------------------------- Unable to handle kernel NULL pointer dereference at virtual address 000001ac ... Internal error: Oops: 17 [#1] SMP ARM ... Hardware name: STi SoC with Flattened Device Tree task: c0c05e80 task.stack: c0c00000 PC is at dwmac4_wrback_get_tx_timestamp_status+0x0/0xc LR is at stmmac_tx_clean+0x2f8/0x4d4 ----------------------------------------------------------- In case of GMAC4 the extended descriptor pointers were used for getting the timestamp. These are NULL for this HW, and the normal ones must be used. The PTP also had problems on this chip due to the bad register management and issues on the algo adopted to setup the PTP and getting the timestamp values from the descriptors. Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Acked-by: Rayagond Kokatanur <rayagond@vayavyalabs.com> Acked-by: Alexandre TORGUE <alexandre.torgue@st.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d204205 commit ba1ffd7

File tree

7 files changed

+154
-73
lines changed

7 files changed

+154
-73
lines changed

drivers/net/ethernet/stmicro/stmmac/common.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,11 +482,12 @@ struct stmmac_ops {
482482
/* PTP and HW Timer helpers */
483483
struct stmmac_hwtimestamp {
484484
void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
485-
u32 (*config_sub_second_increment) (void __iomem *ioaddr, u32 clk_rate);
485+
u32 (*config_sub_second_increment)(void __iomem *ioaddr, u32 ptp_clock,
486+
int gmac4);
486487
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
487488
int (*config_addend) (void __iomem *ioaddr, u32 addend);
488489
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
489-
int add_sub);
490+
int add_sub, int gmac4);
490491
u64(*get_systime) (void __iomem *ioaddr);
491492
};
492493

drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,18 @@ static void dwmac4_rd_enable_tx_timestamp(struct dma_desc *p)
204204

205205
static int dwmac4_wrback_get_tx_timestamp_status(struct dma_desc *p)
206206
{
207-
return (p->des3 & TDES3_TIMESTAMP_STATUS)
208-
>> TDES3_TIMESTAMP_STATUS_SHIFT;
207+
/* Context type from W/B descriptor must be zero */
208+
if (p->des3 & TDES3_CONTEXT_TYPE)
209+
return -EINVAL;
210+
211+
/* Tx Timestamp Status is 1 so des0 and des1'll have valid values */
212+
if (p->des3 & TDES3_TIMESTAMP_STATUS)
213+
return 0;
214+
215+
return 1;
209216
}
210217

211-
/* NOTE: For RX CTX bit has to be checked before
212-
* HAVE a specific function for TX and another one for RX
213-
*/
214-
static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
218+
static inline u64 dwmac4_get_timestamp(void *desc, u32 ats)
215219
{
216220
struct dma_desc *p = (struct dma_desc *)desc;
217221
u64 ns;
@@ -223,12 +227,54 @@ static u64 dwmac4_wrback_get_timestamp(void *desc, u32 ats)
223227
return ns;
224228
}
225229

226-
static int dwmac4_context_get_rx_timestamp_status(void *desc, u32 ats)
230+
static int dwmac4_rx_check_timestamp(void *desc)
231+
{
232+
struct dma_desc *p = (struct dma_desc *)desc;
233+
u32 own, ctxt;
234+
int ret = 1;
235+
236+
own = p->des3 & RDES3_OWN;
237+
ctxt = ((p->des3 & RDES3_CONTEXT_DESCRIPTOR)
238+
>> RDES3_CONTEXT_DESCRIPTOR_SHIFT);
239+
240+
if (likely(!own && ctxt)) {
241+
if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
242+
/* Corrupted value */
243+
ret = -EINVAL;
244+
else
245+
/* A valid Timestamp is ready to be read */
246+
ret = 0;
247+
}
248+
249+
/* Timestamp not ready */
250+
return ret;
251+
}
252+
253+
static int dwmac4_wrback_get_rx_timestamp_status(void *desc, u32 ats)
227254
{
228255
struct dma_desc *p = (struct dma_desc *)desc;
256+
int ret = -EINVAL;
257+
258+
/* Get the status from normal w/b descriptor */
259+
if (likely(p->des3 & TDES3_RS1V)) {
260+
if (likely(p->des1 & RDES1_TIMESTAMP_AVAILABLE)) {
261+
int i = 0;
262+
263+
/* Check if timestamp is OK from context descriptor */
264+
do {
265+
ret = dwmac4_rx_check_timestamp(desc);
266+
if (ret < 0)
267+
goto exit;
268+
i++;
229269

230-
return (p->des1 & RDES1_TIMESTAMP_AVAILABLE)
231-
>> RDES1_TIMESTAMP_AVAILABLE_SHIFT;
270+
} while ((ret == 1) || (i < 10));
271+
272+
if (i == 10)
273+
ret = -EBUSY;
274+
}
275+
}
276+
exit:
277+
return ret;
232278
}
233279

234280
static void dwmac4_rd_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
@@ -373,8 +419,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
373419
.get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
374420
.enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
375421
.get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,
376-
.get_timestamp = dwmac4_wrback_get_timestamp,
377-
.get_rx_timestamp_status = dwmac4_context_get_rx_timestamp_status,
422+
.get_rx_timestamp_status = dwmac4_wrback_get_rx_timestamp_status,
423+
.get_timestamp = dwmac4_get_timestamp,
378424
.set_tx_ic = dwmac4_rd_set_tx_ic,
379425
.prepare_tx_desc = dwmac4_rd_prepare_tx_desc,
380426
.prepare_tso_tx_desc = dwmac4_rd_prepare_tso_tx_desc,

drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,13 @@
5959
#define TDES3_CTXT_TCMSSV BIT(26)
6060

6161
/* TDES3 Common */
62+
#define TDES3_RS1V BIT(26)
63+
#define TDES3_RS1V_SHIFT 26
6264
#define TDES3_LAST_DESCRIPTOR BIT(28)
6365
#define TDES3_LAST_DESCRIPTOR_SHIFT 28
6466
#define TDES3_FIRST_DESCRIPTOR BIT(29)
6567
#define TDES3_CONTEXT_TYPE BIT(30)
68+
#define TDES3_CONTEXT_TYPE_SHIFT 30
6669

6770
/* TDS3 use for both format (read and write back) */
6871
#define TDES3_OWN BIT(31)
@@ -117,6 +120,7 @@
117120
#define RDES3_LAST_DESCRIPTOR BIT(28)
118121
#define RDES3_FIRST_DESCRIPTOR BIT(29)
119122
#define RDES3_CONTEXT_DESCRIPTOR BIT(30)
123+
#define RDES3_CONTEXT_DESCRIPTOR_SHIFT 30
120124

121125
/* RDES3 (read format) */
122126
#define RDES3_BUFFER1_VALID_ADDR BIT(24)

drivers/net/ethernet/stmicro/stmmac/stmmac.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ struct stmmac_priv {
129129
int irq_wake;
130130
spinlock_t ptp_lock;
131131
void __iomem *mmcaddr;
132+
void __iomem *ptpaddr;
132133
u32 rx_tail_addr;
133134
u32 tx_tail_addr;
134135
u32 mss;

drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,29 @@ static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
3434
}
3535

3636
static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr,
37-
u32 ptp_clock)
37+
u32 ptp_clock, int gmac4)
3838
{
3939
u32 value = readl(ioaddr + PTP_TCR);
4040
unsigned long data;
4141

42-
/* Convert the ptp_clock to nano second
43-
* formula = (2/ptp_clock) * 1000000000
44-
* where, ptp_clock = 50MHz.
42+
/* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second
43+
* formula = (1/ptp_clock) * 1000000000
44+
* where ptp_clock is 50MHz if fine method is used to update system
4545
*/
46-
data = (2000000000ULL / ptp_clock);
46+
if (value & PTP_TCR_TSCFUPDT)
47+
data = (1000000000ULL / 50000000);
48+
else
49+
data = (1000000000ULL / ptp_clock);
4750

4851
/* 0.465ns accuracy */
4952
if (!(value & PTP_TCR_TSCTRLSSR))
5053
data = (data * 1000) / 465;
5154

55+
data &= PTP_SSIR_SSINC_MASK;
56+
57+
if (gmac4)
58+
data = data << GMAC4_PTP_SSIR_SSINC_SHIFT;
59+
5260
writel(data, ioaddr + PTP_SSIR);
5361

5462
return data;
@@ -104,14 +112,30 @@ static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
104112
}
105113

106114
static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
107-
int add_sub)
115+
int add_sub, int gmac4)
108116
{
109117
u32 value;
110118
int limit;
111119

120+
if (add_sub) {
121+
/* If the new sec value needs to be subtracted with
122+
* the system time, then MAC_STSUR reg should be
123+
* programmed with (2^32 – <new_sec_value>)
124+
*/
125+
if (gmac4)
126+
sec = (100000000ULL - sec);
127+
128+
value = readl(ioaddr + PTP_TCR);
129+
if (value & PTP_TCR_TSCTRLSSR)
130+
nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
131+
else
132+
nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
133+
}
134+
112135
writel(sec, ioaddr + PTP_STSUR);
113-
writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
114-
ioaddr + PTP_STNSUR);
136+
value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
137+
writel(value, ioaddr + PTP_STNSUR);
138+
115139
/* issue command to initialize the system time value */
116140
value = readl(ioaddr + PTP_TCR);
117141
value |= PTP_TCR_TSUPDT;
@@ -134,8 +158,9 @@ static u64 stmmac_get_systime(void __iomem *ioaddr)
134158
{
135159
u64 ns;
136160

161+
/* Get the TSSS value */
137162
ns = readl(ioaddr + PTP_STNSR);
138-
/* convert sec time value to nanosecond */
163+
/* Get the TSS and convert sec time value to nanosecond */
139164
ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
140165

141166
return ns;

0 commit comments

Comments
 (0)