From: Martin Kaistra <hidden> Date: 2021-11-04 13:32:43
Hi,
this series adds PTP support to the b53 DSA driver for the BCM53128
switch using the BroadSync HD feature.
As there seems to be only one filter (either by Ethertype or DA) for
timestamping incoming packets, only L2 is supported.
To be able to use the timecounter infrastructure with a counter that
wraps around at a non-power of two point, patch 2 adds support for such
a custom point. Alternatively I could fix up the delta every time a
wrap-around occurs in the driver itself, but this way it can also be
useful for other hardware.
Thanks,
Martin
Kurt Kanzenbach (1):
net: dsa: b53: Add BroadSync HD register definitions
Martin Kaistra (6):
net: dsa: b53: Move struct b53_device to include/linux/dsa/b53.h
timecounter: allow for non-power of two overflow
net: dsa: b53: Add PHC clock support
net: dsa: b53: Add logic for RX timestamping
net: dsa: b53: Add logic for TX timestamping
net: dsa: b53: Expose PTP timestamping ioctls to userspace
drivers/net/dsa/b53/Kconfig | 7 +
drivers/net/dsa/b53/Makefile | 1 +
drivers/net/dsa/b53/b53_common.c | 21 ++
drivers/net/dsa/b53/b53_priv.h | 90 +-------
drivers/net/dsa/b53/b53_ptp.c | 366 +++++++++++++++++++++++++++++++
drivers/net/dsa/b53/b53_ptp.h | 68 ++++++
drivers/net/dsa/b53/b53_regs.h | 38 ++++
include/linux/dsa/b53.h | 144 ++++++++++++
include/linux/timecounter.h | 3 +
kernel/time/timecounter.c | 3 +
net/dsa/tag_brcm.c | 85 ++++++-
11 files changed, 727 insertions(+), 99 deletions(-)
create mode 100644 drivers/net/dsa/b53/b53_ptp.c
create mode 100644 drivers/net/dsa/b53/b53_ptp.h
create mode 100644 include/linux/dsa/b53.h
--
2.20.1
From: Martin Kaistra <hidden> Date: 2021-11-04 13:32:53
From: Kurt Kanzenbach <kurt@linutronix.de>
Add register definitions for the BroadSync HD features of
BCM53128. These will be used to enable PTP support.
Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
Signed-off-by: Martin Kaistra <redacted>
---
drivers/net/dsa/b53/b53_regs.h | 38 ++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
From: Martin Kaistra <hidden> Date: 2021-11-04 13:32:58
In order to access the b53 structs from net/dsa/tag_brcm.c move the
definitions from drivers/net/dsa/b53/b53_priv.h to the new file
include/linux/dsa/b53.h.
Signed-off-by: Martin Kaistra <redacted>
---
drivers/net/dsa/b53/b53_priv.h | 90 +----------------------------
include/linux/dsa/b53.h | 100 +++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+), 89 deletions(-)
create mode 100644 include/linux/dsa/b53.h
@@ -89,63 +58,6 @@ enum {#define B53_N_PORTS 9#define B53_N_PORTS_25 6-structb53_port{-u16vlan_ctl_mask;-structethtool_eeeeee;-};--structb53_vlan{-u16members;-u16untag;-boolvalid;-};--structb53_device{-structdsa_switch*ds;-structb53_platform_data*pdata;-constchar*name;--structmutexreg_mutex;-structmutexstats_mutex;-structmutexarl_mutex;-conststructb53_io_ops*ops;--/* chip specific data */-u32chip_id;-u8core_rev;-u8vta_regs[3];-u8duplex_reg;-u8jumbo_pm_reg;-u8jumbo_size_reg;-intreset_gpio;-u8num_arl_bins;-u16num_arl_buckets;-enumdsa_tag_protocoltag_protocol;--/* used ports mask */-u16enabled_ports;-unsignedintimp_port;--/* connect specific data */-u8current_page;-structdevice*dev;-u8serdes_lane;--/* Master MDIO bus we got probed from */-structmii_bus*bus;--void*priv;--/* run time configuration */-boolenable_jumbo;--unsignedintnum_vlans;-structb53_vlan*vlans;-boolvlan_enabled;-unsignedintnum_ports;-structb53_port*ports;-};-#define b53_for_each_port(dev, i) \for(i=0;i<B53_N_PORTS;i++)\if(dev->enabled_ports&BIT(i))
@@ -0,0 +1,100 @@+/* SPDX-License-Identifier: ISC */+/*+*Copyright(C)2011-2013JonasGorski<jogo@openwrt.org>+*+*Includedbydrivers/net/dsa/b53/b53_priv.handnet/dsa/tag_brcm.c+*/++#include<net/dsa.h>++structb53_device;+structphylink_link_state;++structb53_io_ops{+int(*read8)(structb53_device*dev,u8page,u8reg,u8*value);+int(*read16)(structb53_device*dev,u8page,u8reg,u16*value);+int(*read32)(structb53_device*dev,u8page,u8reg,u32*value);+int(*read48)(structb53_device*dev,u8page,u8reg,u64*value);+int(*read64)(structb53_device*dev,u8page,u8reg,u64*value);+int(*write8)(structb53_device*dev,u8page,u8reg,u8value);+int(*write16)(structb53_device*dev,u8page,u8reg,u16value);+int(*write32)(structb53_device*dev,u8page,u8reg,u32value);+int(*write48)(structb53_device*dev,u8page,u8reg,u64value);+int(*write64)(structb53_device*dev,u8page,u8reg,u64value);+int(*phy_read16)(structb53_device*dev,intaddr,intreg,+u16*value);+int(*phy_write16)(structb53_device*dev,intaddr,intreg,+u16value);+int(*irq_enable)(structb53_device*dev,intport);+void(*irq_disable)(structb53_device*dev,intport);+u8(*serdes_map_lane)(structb53_device*dev,intport);+int(*serdes_link_state)(structb53_device*dev,intport,+structphylink_link_state*state);+void(*serdes_config)(structb53_device*dev,intport,+unsignedintmode,+conststructphylink_link_state*state);+void(*serdes_an_restart)(structb53_device*dev,intport);+void(*serdes_link_set)(structb53_device*dev,intport,+unsignedintmode,phy_interface_tinterface,+boollink_up);+void(*serdes_phylink_validate)(structb53_device*dev,intport,+unsignedlong*supported,+structphylink_link_state*state);+};++structb53_port{+u16vlan_ctl_mask;+structethtool_eeeeee;+};++structb53_vlan{+u16members;+u16untag;+boolvalid;+};++structb53_device{+structdsa_switch*ds;+structb53_platform_data*pdata;+constchar*name;++structmutexreg_mutex;+structmutexstats_mutex;+structmutexarl_mutex;+conststructb53_io_ops*ops;++/* chip specific data */+u32chip_id;+u8core_rev;+u8vta_regs[3];+u8duplex_reg;+u8jumbo_pm_reg;+u8jumbo_size_reg;+intreset_gpio;+u8num_arl_bins;+u16num_arl_buckets;+enumdsa_tag_protocoltag_protocol;++/* used ports mask */+u16enabled_ports;+unsignedintimp_port;++/* connect specific data */+u8current_page;+structdevice*dev;+u8serdes_lane;++/* Master MDIO bus we got probed from */+structmii_bus*bus;++void*priv;++/* run time configuration */+boolenable_jumbo;++unsignedintnum_vlans;+structb53_vlan*vlans;+boolvlan_enabled;+unsignedintnum_ports;+structb53_port*ports;+};
From: Martin Kaistra <hidden> Date: 2021-11-04 13:33:06
Some hardware counters which are used as clocks have an overflow point
which is not a power of two. In order to be able to use the cycle
counter infrastructure with such hardware, add support for more generic
overflow logic.
Signed-off-by: Martin Kaistra <redacted>
---
include/linux/timecounter.h | 3 +++
kernel/time/timecounter.c | 3 +++
2 files changed, 6 insertions(+)
@@ -39,6 +39,9 @@ static u64 timecounter_read_delta(struct timecounter *tc)/* calculate the delta since the last timecounter_read_delta(): */cycle_delta=(cycle_now-tc->cycle_last)&tc->cc->mask;+if(tc->cc->overflow_point&&(cycle_now-tc->cycle_last)>tc->cc->mask)+cycle_delta-=tc->cc->mask-tc->cc->overflow_point;+/* convert to nanoseconds: */ns_offset=cyclecounter_cyc2ns(tc->cc,cycle_delta,tc->mask,&tc->frac);
From: Martin Kaistra <hidden> Date: 2021-11-04 13:33:42
The BCM53128 switch has an internal clock, which can be used for
timestamping. Add support for it.
The 32-bit free running clock counts nanoseconds. In order to account
for the wrap-around at 999999999 (0x3B9AC9FF) while using the cycle
counter infrastructure, we need to set a 30bit mask and use the
overflow_point property.
Enable the Broadsync HD timestamping feature in b53_ptp_init() for PTPv2
Ethertype (0x88f7).
Signed-off-by: Martin Kaistra <redacted>
---
drivers/net/dsa/b53/Kconfig | 7 ++
drivers/net/dsa/b53/Makefile | 1 +
drivers/net/dsa/b53/b53_common.c | 17 +++
drivers/net/dsa/b53/b53_ptp.c | 191 +++++++++++++++++++++++++++++++
drivers/net/dsa/b53/b53_ptp.h | 35 ++++++
include/linux/dsa/b53.h | 14 +++
6 files changed, 265 insertions(+)
create mode 100644 drivers/net/dsa/b53/b53_ptp.c
create mode 100644 drivers/net/dsa/b53/b53_ptp.h
@@ -0,0 +1,191 @@+// SPDX-License-Identifier: ISC+/*+*B53switchPTPsupport+*+*Author:MartinKaistra<martin.kaistra@linutronix.de>+*Copyright(C)2021LinutronixGmbH+*/++#include"b53_priv.h"+#include"b53_ptp.h"++staticintb53_ptp_gettime(structptp_clock_info*ptp,structtimespec64*ts)+{+structb53_device*dev=+container_of(ptp,structb53_device,ptp_clock_info);+u64ns;++mutex_lock(&dev->ptp_mutex);+ns=timecounter_read(&dev->tc);+mutex_unlock(&dev->ptp_mutex);++*ts=ns_to_timespec64(ns);++return0;+}++staticintb53_ptp_settime(structptp_clock_info*ptp,+conststructtimespec64*ts)+{+structb53_device*dev=+container_of(ptp,structb53_device,ptp_clock_info);+u64ns;++ns=timespec64_to_ns(ts);++mutex_lock(&dev->ptp_mutex);+timecounter_init(&dev->tc,&dev->cc,ns);+mutex_unlock(&dev->ptp_mutex);++return0;+}++staticintb53_ptp_adjfine(structptp_clock_info*ptp,longscaled_ppm)+{+structb53_device*dev=+container_of(ptp,structb53_device,ptp_clock_info);+u64adj,diff;+u32mult;+boolneg_adj=false;++if(scaled_ppm<0){+neg_adj=true;+scaled_ppm=-scaled_ppm;+}++mult=(1<<28);+adj=64;+adj*=(u64)scaled_ppm;+diff=div_u64(adj,15625ULL);++mutex_lock(&dev->ptp_mutex);+timecounter_read(&dev->tc);+dev->cc.mult=neg_adj?mult-diff:mult+diff;+mutex_unlock(&dev->ptp_mutex);++return0;+}++staticintb53_ptp_adjtime(structptp_clock_info*ptp,s64delta)+{+structb53_device*dev=+container_of(ptp,structb53_device,ptp_clock_info);++mutex_lock(&dev->ptp_mutex);+timecounter_adjtime(&dev->tc,delta);+mutex_unlock(&dev->ptp_mutex);++return0;+}++staticu64b53_ptp_read(conststructcyclecounter*cc)+{+structb53_device*dev=container_of(cc,structb53_device,cc);+u32ts;++b53_read32(dev,B53_BROADSYNC_PAGE,B53_BROADSYNC_TIMEBASE1,&ts);++returnts;+}++staticintb53_ptp_enable(structptp_clock_info*ptp,+structptp_clock_request*rq,inton)+{+return-EOPNOTSUPP;+}++staticvoidb53_ptp_overflow_check(structwork_struct*work)+{+structdelayed_work*dw=to_delayed_work(work);+structb53_device*dev=+container_of(dw,structb53_device,overflow_work);++mutex_lock(&dev->ptp_mutex);+timecounter_read(&dev->tc);+mutex_unlock(&dev->ptp_mutex);++schedule_delayed_work(&dev->overflow_work,B53_PTP_OVERFLOW_PERIOD);+}++intb53_ptp_init(structb53_device*dev)+{+mutex_init(&dev->ptp_mutex);++INIT_DELAYED_WORK(&dev->overflow_work,b53_ptp_overflow_check);++/* Enable BroadSync HD for all ports */+b53_write16(dev,B53_BROADSYNC_PAGE,B53_BROADSYNC_EN_CTRL1,0x00ff);++/* Enable BroadSync HD Time Stamping Reporting (Egress) */+b53_write8(dev,B53_BROADSYNC_PAGE,B53_BROADSYNC_TS_REPORT_CTRL,0x01);++/* Enable BroadSync HD Time Stamping for PTPv2 ingress */++/* MPORT_CTRL0 | MPORT0_TS_EN */+b53_write16(dev,B53_ARLCTRL_PAGE,0x0e,(1<<15)|0x01);+/* Forward to IMP port 8 */+b53_write64(dev,B53_ARLCTRL_PAGE,0x18,(1<<8));+/* PTPv2 Ether Type */+b53_write64(dev,B53_ARLCTRL_PAGE,0x10,(u64)0x88f7<<48);++/* Setup PTP clock */+dev->ptp_clock_info.owner=THIS_MODULE;+snprintf(dev->ptp_clock_info.name,sizeof(dev->ptp_clock_info.name),+dev_name(dev->dev));++dev->ptp_clock_info.max_adj=1000000000ULL;+dev->ptp_clock_info.n_alarm=0;+dev->ptp_clock_info.n_pins=0;+dev->ptp_clock_info.n_ext_ts=0;+dev->ptp_clock_info.n_per_out=0;+dev->ptp_clock_info.pps=0;+dev->ptp_clock_info.adjfine=b53_ptp_adjfine;+dev->ptp_clock_info.adjtime=b53_ptp_adjtime;+dev->ptp_clock_info.gettime64=b53_ptp_gettime;+dev->ptp_clock_info.settime64=b53_ptp_settime;+dev->ptp_clock_info.enable=b53_ptp_enable;++dev->ptp_clock=ptp_clock_register(&dev->ptp_clock_info,dev->dev);+if(IS_ERR(dev->ptp_clock))+returnPTR_ERR(dev->ptp_clock);++/* The switch provides a 32 bit free running counter. Use the Linux+*cyclecounterinfrastructurewhichissuitedforsuchscenarios.+*/+dev->cc.read=b53_ptp_read;+dev->cc.mask=CYCLECOUNTER_MASK(30);+dev->cc.overflow_point=999999999;+dev->cc.mult=(1<<28);+dev->cc.shift=28;++b53_write32(dev,B53_BROADSYNC_PAGE,B53_BROADSYNC_TIMEBASE_ADJ1,40);++timecounter_init(&dev->tc,&dev->cc,ktime_to_ns(ktime_get_real()));++schedule_delayed_work(&dev->overflow_work,B53_PTP_OVERFLOW_PERIOD);++return0;+}++intb53_get_ts_info(structdsa_switch*ds,intport,+structethtool_ts_info*info)+{+structb53_device*dev=ds->priv;++info->phc_index=dev->ptp_clock?ptp_clock_index(dev->ptp_clock):-1;+info->so_timestamping=SOF_TIMESTAMPING_TX_HARDWARE|+SOF_TIMESTAMPING_RX_HARDWARE|+SOF_TIMESTAMPING_RAW_HARDWARE;+info->tx_types=BIT(HWTSTAMP_TX_OFF);+info->rx_filters=BIT(HWTSTAMP_FILTER_NONE);++return0;+}++voidb53_ptp_exit(structb53_device*dev)+{+cancel_delayed_work_sync(&dev->overflow_work);+if(dev->ptp_clock)+ptp_clock_unregister(dev->ptp_clock);+dev->ptp_clock=NULL;+}
From: Martin Kaistra <hidden> Date: 2021-11-04 13:33:46
In order to get the switch to generate a timestamp for a transmitted
packet, we need to set the TS bit in the BRCM tag. The switch will then
create a status frame, which gets send back to the cpu.
In b53_port_txtstamp() we put the skb into a waiting position.
When a status frame is received, we extract the timestamp and put the time
according to our timecounter into the waiting skb. When
TX_TSTAMP_TIMEOUT is reached and we have no means to correctly get back
a full timestamp, we cancel the process.
As the status frame doesn't contain a reference to the original packet,
only one packet with timestamp request can be sent at a time.
Signed-off-by: Martin Kaistra <redacted>
---
drivers/net/dsa/b53/b53_common.c | 1 +
drivers/net/dsa/b53/b53_ptp.c | 59 ++++++++++++++++++++++++++++++++
drivers/net/dsa/b53/b53_ptp.h | 9 +++++
net/dsa/tag_brcm.c | 51 +++++++++++++++++++++++++++
4 files changed, 120 insertions(+)
@@ -85,9 +86,14 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,unsignedintoffset){structdsa_port*dp=dsa_slave_to_port(dev);+structb53_device*b53_dev=dp->ds->priv;+unsignedinttype=ptp_classify_raw(skb);u16queue=skb_get_queue_mapping(skb);+structb53_port_hwtstamp*ps;u8*brcm_tag;+ps=&b53_dev->ports[dp->index].port_hwtstamp;+/* The Ethernet switch we are interfaced with needs packets to be at*least64bytes(includingFCS)otherwisetheywillbediscardedwhen*theyentertheswitchportlogic.WhenBroadcomtagsareenabled,we
@@ -126,6 +138,32 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,returnskb;}+staticintset_txtstamp(structb53_device*dev,+structb53_port_hwtstamp*ps,+intport,+u64ns)+{+structskb_shared_hwtstampsshhwtstamps;+structsk_buff*tmp_skb;++if(!ps->tx_skb)+return0;++mutex_lock(&dev->ptp_mutex);+ns=timecounter_cyc2time(&dev->tc,ns);+mutex_unlock(&dev->ptp_mutex);++memset(&shhwtstamps,0,sizeof(shhwtstamps));+shhwtstamps.hwtstamp=ns_to_ktime(ns);+tmp_skb=ps->tx_skb;+ps->tx_skb=NULL;++clear_bit_unlock(B53_HWTSTAMP_TX_IN_PROGRESS,&ps->state);+skb_complete_tx_timestamp(tmp_skb,&shhwtstamps);++return0;+}+/* Frames with this tag have one of these two layouts:*-----------------------------------*|MACDA|MACSA|4btag|Type|DSA_TAG_PROTO_BRCM
@@ -174,6 +215,16 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,if(!skb->dev)returnNULL;+/* Check whether this is a status frame */+if(*tag_len==8&&brcm_tag[3]&0x20){+dp=dsa_slave_to_port(skb->dev);+b53_dev=dp->ds->priv;+ps=&b53_dev->ports[source_port].port_hwtstamp;++set_txtstamp(b53_dev,ps,source_port,tstamp);+returnNULL;+}+/* Remove Broadcom tag and update checksum */skb_pull_rcsum(skb,*tag_len);
From: Martin Kaistra <hidden> Date: 2021-11-04 13:33:55
Packets received by the tagger with opcode=1 contain the 32-bit timestamp
according to the timebase register. This timestamp is saved in
BRCM_SKB_CB(skb)->meta_tstamp. b53_port_rxtstamp() takes this
and puts the full time information from the timecounter into
shwt->hwtstamp.
Signed-off-by: Martin Kaistra <redacted>
---
drivers/net/dsa/b53/b53_common.c | 1 +
drivers/net/dsa/b53/b53_ptp.c | 28 ++++++++++++++++++++++++++
drivers/net/dsa/b53/b53_ptp.h | 10 ++++++++++
include/linux/dsa/b53.h | 30 ++++++++++++++++++++++++++++
net/dsa/tag_brcm.c | 34 ++++++++++++++++++++++----------
5 files changed, 93 insertions(+), 10 deletions(-)
@@ -46,9 +46,32 @@ struct b53_io_ops {structphylink_link_state*state);};+/* state flags for b53_port_hwtstamp::state */+enum{+B53_HWTSTAMP_ENABLED,+B53_HWTSTAMP_TX_IN_PROGRESS,+};++structb53_port_hwtstamp{+/* Port index */+intport_id;++/* Timestamping state */+unsignedlongstate;++/* Resources for transmit timestamping */+unsignedlongtx_tstamp_start;+structsk_buff*tx_skb;++/* Current timestamp configuration */+structhwtstamp_configtstamp_config;+};+structb53_port{u16vlan_ctl_mask;structethtool_eeeeee;+/* Per-port timestamping resources */+structb53_port_hwtstampport_hwtstamp;};structb53_vlan{
@@ -31,7 +32,10 @@/* 6th byte in the tag */#define BRCM_LEG_PORT_ID (0xf)-/* Newer Broadcom tag (4 bytes) */+/* Newer Broadcom tag (4 bytes)+*Foregress,whenopcode=0001,additional4bytesareusedfor+*thetimestamp.+*/#define BRCM_TAG_LEN 4/* Tag is constructed and desconstructed using byte by byte access
@@ -136,19 +140,26 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,*/staticstructsk_buff*brcm_tag_rcv_ll(structsk_buff*skb,structnet_device*dev,-unsignedintoffset)+unsignedintoffset,+int*tag_len){intsource_port;u8*brcm_tag;+u32tstamp;++*tag_len=8;-if(unlikely(!pskb_may_pull(skb,BRCM_TAG_LEN)))+if(unlikely(!pskb_may_pull(skb,*tag_len)))returnNULL;brcm_tag=skb->data-offset;-/* The opcode should never be different than 0b000 */-if(unlikely((brcm_tag[0]>>BRCM_OPCODE_SHIFT)&BRCM_OPCODE_MASK))-returnNULL;+if((brcm_tag[0]>>BRCM_OPCODE_SHIFT)&BRCM_OPCODE_MASK){+tstamp=brcm_tag[4]<<24|brcm_tag[5]<<16|brcm_tag[6]<<8|brcm_tag[7];+BRCM_SKB_CB(skb)->meta_tstamp=tstamp;+}else{+*tag_len=BRCM_TAG_LEN;+}/* We should never see a reserved reason code without knowing how to*handleit
@@ -164,7 +175,7 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,returnNULL;/* Remove Broadcom tag and update checksum */-skb_pull_rcsum(skb,BRCM_TAG_LEN);+skb_pull_rcsum(skb,*tag_len);dsa_default_offload_fwd_mark(skb);
@@ -184,13 +195,14 @@ static struct sk_buff *brcm_tag_xmit(struct sk_buff *skb,staticstructsk_buff*brcm_tag_rcv(structsk_buff*skb,structnet_device*dev){structsk_buff*nskb;+inttag_len;/* skb->data points to the EtherType, the tag is right before it */-nskb=brcm_tag_rcv_ll(skb,dev,2);+nskb=brcm_tag_rcv_ll(skb,dev,2,&tag_len);if(!nskb)returnnskb;-dsa_strip_etype_header(skb,BRCM_TAG_LEN);+dsa_strip_etype_header(skb,tag_len);returnnskb;}
@@ -295,8 +307,10 @@ static struct sk_buff *brcm_tag_xmit_prepend(struct sk_buff *skb,staticstructsk_buff*brcm_tag_rcv_prepend(structsk_buff*skb,structnet_device*dev){+inttag_len;+/* tag is prepended to the packet */-returnbrcm_tag_rcv_ll(skb,dev,ETH_HLEN);+returnbrcm_tag_rcv_ll(skb,dev,ETH_HLEN,&tag_len);}staticconststructdsa_device_opsbrcm_prepend_netdev_ops={
From: Martin Kaistra <hidden> Date: 2021-11-04 13:34:01
Allow userspace to use the PTP support. Currently only L2 is supported.
Signed-off-by: Martin Kaistra <redacted>
Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
---
drivers/net/dsa/b53/b53_common.c | 2 +
drivers/net/dsa/b53/b53_ptp.c | 92 +++++++++++++++++++++++++++++++-
drivers/net/dsa/b53/b53_ptp.h | 14 +++++
3 files changed, 106 insertions(+), 2 deletions(-)
@@ -263,12 +263,100 @@ int b53_get_ts_info(struct dsa_switch *ds, int port,info->so_timestamping=SOF_TIMESTAMPING_TX_HARDWARE|SOF_TIMESTAMPING_RX_HARDWARE|SOF_TIMESTAMPING_RAW_HARDWARE;-info->tx_types=BIT(HWTSTAMP_TX_OFF);-info->rx_filters=BIT(HWTSTAMP_FILTER_NONE);+info->tx_types=BIT(HWTSTAMP_TX_ON);+info->rx_filters=BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT);return0;}+staticintb53_set_hwtstamp_config(structb53_device*dev,intport,+structhwtstamp_config*config)+{+structb53_port_hwtstamp*ps=&dev->ports[port].port_hwtstamp;+booltstamp_enable=false;++clear_bit_unlock(B53_HWTSTAMP_ENABLED,&ps->state);++/* Reserved for future extensions */+if(config->flags)+return-EINVAL;++switch(config->tx_type){+caseHWTSTAMP_TX_ON:+tstamp_enable=true;+break;+caseHWTSTAMP_TX_OFF:+tstamp_enable=false;+break;+default:+return-ERANGE;+}++switch(config->rx_filter){+caseHWTSTAMP_FILTER_NONE:+tstamp_enable=false;+break;+caseHWTSTAMP_FILTER_PTP_V2_L2_EVENT:+caseHWTSTAMP_FILTER_PTP_V2_L2_SYNC:+caseHWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:+caseHWTSTAMP_FILTER_PTP_V2_EVENT:+caseHWTSTAMP_FILTER_PTP_V2_SYNC:+caseHWTSTAMP_FILTER_PTP_V2_DELAY_REQ:+caseHWTSTAMP_FILTER_ALL:+config->rx_filter=HWTSTAMP_FILTER_PTP_V2_L2_EVENT;+break;+default:+return-ERANGE;+}++if(ps->tx_skb){+dev_kfree_skb_any(ps->tx_skb);+ps->tx_skb=NULL;+}+clear_bit(B53_HWTSTAMP_TX_IN_PROGRESS,&ps->state);++if(tstamp_enable)+set_bit(B53_HWTSTAMP_ENABLED,&ps->state);++return0;+}++intb53_port_hwtstamp_set(structdsa_switch*ds,intport,structifreq*ifr)+{+structb53_device*dev=ds->priv;+structb53_port_hwtstamp*ps;+structhwtstamp_configconfig;+interr;++ps=&dev->ports[port].port_hwtstamp;++if(copy_from_user(&config,ifr->ifr_data,sizeof(config)))+return-EFAULT;++err=b53_set_hwtstamp_config(dev,port,&config);+if(err)+returnerr;++/* Save the chosen configuration to be returned later */+memcpy(&ps->tstamp_config,&config,sizeof(config));++returncopy_to_user(ifr->ifr_data,&config,sizeof(config))?-EFAULT:+0;+}++intb53_port_hwtstamp_get(structdsa_switch*ds,intport,structifreq*ifr)+{+structb53_device*dev=ds->priv;+structb53_port_hwtstamp*ps;+structhwtstamp_config*config;++ps=&dev->ports[port].port_hwtstamp;+config=&ps->tstamp_config;++returncopy_to_user(ifr->ifr_data,config,sizeof(*config))?-EFAULT:+0;+}+voidb53_ptp_exit(structb53_device*dev){cancel_delayed_work_sync(&dev->overflow_work);
Instead of generic work, consider implementing
ptp_clock_info::do_aux_work instead.
The advantage is that you get a named kernel thread that can be given
scheduling priority administratively.
Thanks,
Richard
From: Jakub Kicinski <kuba@kernel.org> Date: 2021-11-04 17:29:39
On Thu, 4 Nov 2021 14:31:54 +0100 Martin Kaistra wrote:
this series adds PTP support to the b53 DSA driver for the BCM53128
switch using the BroadSync HD feature.
As there seems to be only one filter (either by Ethertype or DA) for
timestamping incoming packets, only L2 is supported.
To be able to use the timecounter infrastructure with a counter that
wraps around at a non-power of two point, patch 2 adds support for such
a custom point. Alternatively I could fix up the delta every time a
wrap-around occurs in the driver itself, but this way it can also be
useful for other hardware.
Please make sure that the code builds as a module and that each patch
compiles cleanly with W=1 C=1 flags set - build the entire tree first
with W=1 C=1 cause there will be extra warning noise, then apply your
patches one by one and recompile, there should be no warnings since b53
itself builds cleanly.
From: Richard Cochran <richardcochran@gmail.com> Date: 2021-11-04 17:49:49
On Thu, Nov 04, 2021 at 10:28:43AM -0700, Richard Cochran wrote:
Instead of generic work, consider implementing
ptp_clock_info::do_aux_work instead.
The advantage is that you get a named kernel thread that can be given
scheduling priority administratively.
I see you are using do_aux_work in Patch 6. You could use the kthread
for both overflow avoidance and transmit time stamps.
From: Martin Kaistra <hidden> Date: 2021-11-05 13:08:20
Am 04.11.21 um 18:29 schrieb Jakub Kicinski:
On Thu, 4 Nov 2021 14:31:54 +0100 Martin Kaistra wrote:
quoted
this series adds PTP support to the b53 DSA driver for the BCM53128
switch using the BroadSync HD feature.
As there seems to be only one filter (either by Ethertype or DA) for
timestamping incoming packets, only L2 is supported.
To be able to use the timecounter infrastructure with a counter that
wraps around at a non-power of two point, patch 2 adds support for such
a custom point. Alternatively I could fix up the delta every time a
wrap-around occurs in the driver itself, but this way it can also be
useful for other hardware.
Please make sure that the code builds as a module and that each patch
compiles cleanly with W=1 C=1 flags set - build the entire tree first
with W=1 C=1 cause there will be extra warning noise, then apply your
patches one by one and recompile, there should be no warnings since b53
itself builds cleanly.
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-11-05 14:28:40
On Fri, Nov 05, 2021 at 07:13:19AM -0700, Richard Cochran wrote:
On Fri, Nov 05, 2021 at 02:38:01PM +0100, Martin Kaistra wrote:
quoted
Ok, then I will remove HWTSTAMP_FILTER_PTP_V2_(EVENT|SYNC|DELAY_REQ) from
this list, what about HWTSTAMP_FILTER_ALL?
AKK means time stamp every received frame, so your driver should
return an error in this case as well.
What is the expected convention exactly? There are other drivers that
downgrade the user application's request to what they support, and at
least ptp4l does not error out, it just prints a warning.
From: Jakub Kicinski <kuba@kernel.org> Date: 2021-11-05 15:09:43
On Fri, 5 Nov 2021 16:28:33 +0200 Vladimir Oltean wrote:
On Fri, Nov 05, 2021 at 07:13:19AM -0700, Richard Cochran wrote:
quoted
On Fri, Nov 05, 2021 at 02:38:01PM +0100, Martin Kaistra wrote:
quoted
Ok, then I will remove HWTSTAMP_FILTER_PTP_V2_(EVENT|SYNC|DELAY_REQ) from
this list, what about HWTSTAMP_FILTER_ALL?
AKK means time stamp every received frame, so your driver should
return an error in this case as well.
What is the expected convention exactly? There are other drivers that
downgrade the user application's request to what they support, and at
least ptp4l does not error out, it just prints a warning.
Which is sad because that's one of the best documented parts of our API:
Desired behavior is passed into the kernel and to a specific device by
calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose
ifr_data points to a struct hwtstamp_config. The tx_type and
rx_filter are hints to the driver what it is expected to do. If
the requested fine-grained filtering for incoming packets is not
supported, the driver may time stamp more than just the requested types
of packets.
Drivers are free to use a more permissive configuration than the requested
configuration. It is expected that drivers should only implement directly the
most generic mode that can be supported. For example if the hardware can
support HWTSTAMP_FILTER_V2_EVENT, then it should generally always upscale
HWTSTAMP_FILTER_V2_L2_SYNC_MESSAGE, and so forth, as HWTSTAMP_FILTER_V2_EVENT
is more generic (and more useful to applications).
A driver which supports hardware time stamping shall update the struct
with the actual, possibly more permissive configuration. If the
requested packets cannot be time stamped, then nothing should be
changed and ERANGE shall be returned (in contrast to EINVAL, which
indicates that SIOCSHWTSTAMP is not supported at all).
https://www.kernel.org/doc/html/latest/networking/timestamping.html#hardware-timestamping-configuration-siocshwtstamp-and-siocghwtstamp
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-11-05 17:25:46
On Fri, Nov 05, 2021 at 08:09:39AM -0700, Jakub Kicinski wrote:
On Fri, 5 Nov 2021 16:28:33 +0200 Vladimir Oltean wrote:
quoted
On Fri, Nov 05, 2021 at 07:13:19AM -0700, Richard Cochran wrote:
quoted
On Fri, Nov 05, 2021 at 02:38:01PM +0100, Martin Kaistra wrote:
quoted
Ok, then I will remove HWTSTAMP_FILTER_PTP_V2_(EVENT|SYNC|DELAY_REQ) from
this list, what about HWTSTAMP_FILTER_ALL?
AKK means time stamp every received frame, so your driver should
return an error in this case as well.
What is the expected convention exactly? There are other drivers that
downgrade the user application's request to what they support, and at
least ptp4l does not error out, it just prints a warning.
Which is sad because that's one of the best documented parts of our API:
Desired behavior is passed into the kernel and to a specific device by
calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose
ifr_data points to a struct hwtstamp_config. The tx_type and
rx_filter are hints to the driver what it is expected to do. If
the requested fine-grained filtering for incoming packets is not
supported, the driver may time stamp more than just the requested types
of packets.
Drivers are free to use a more permissive configuration than the requested
configuration. It is expected that drivers should only implement directly the
most generic mode that can be supported. For example if the hardware can
support HWTSTAMP_FILTER_V2_EVENT, then it should generally always upscale
HWTSTAMP_FILTER_V2_L2_SYNC_MESSAGE, and so forth, as HWTSTAMP_FILTER_V2_EVENT
is more generic (and more useful to applications).
A driver which supports hardware time stamping shall update the struct
with the actual, possibly more permissive configuration. If the
requested packets cannot be time stamped, then nothing should be
changed and ERANGE shall be returned (in contrast to EINVAL, which
indicates that SIOCSHWTSTAMP is not supported at all).
https://www.kernel.org/doc/html/latest/networking/timestamping.html#hardware-timestamping-configuration-siocshwtstamp-and-siocghwtstamp
Yeah, sorry, I've been all over that documentation file for the past few
days, but I missed that section. "that's one of the best documented
parts of our API" is a nice euphemism for all the SO_TIMESTAMPING flags :)
From: Richard Cochran <richardcochran@gmail.com> Date: 2021-11-06 00:18:12
On Fri, Nov 05, 2021 at 04:28:33PM +0200, Vladimir Oltean wrote:
What is the expected convention exactly? There are other drivers that
downgrade the user application's request to what they support, and at
least ptp4l does not error out, it just prints a warning.
Drivers may upgrade, but they may not downgrade.
Which drivers downgrade? We need to fix those buggy drivers.
Thanks,
Richard
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-11-06 00:37:12
On Fri, Nov 05, 2021 at 05:18:04PM -0700, Richard Cochran wrote:
On Fri, Nov 05, 2021 at 04:28:33PM +0200, Vladimir Oltean wrote:
quoted
What is the expected convention exactly? There are other drivers that
downgrade the user application's request to what they support, and at
least ptp4l does not error out, it just prints a warning.
Drivers may upgrade, but they may not downgrade.
Which drivers downgrade? We need to fix those buggy drivers.
Thanks,
Richard
From: Kurt Kanzenbach <kurt@linutronix.de>
Add register definitions for the BroadSync HD features of
BCM53128. These will be used to enable PTP support.
Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
Signed-off-by: Martin Kaistra <redacted>
---
drivers/net/dsa/b53/b53_regs.h | 38 ++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
The BCM53128 switch has an internal clock, which can be used for
timestamping. Add support for it.
The 32-bit free running clock counts nanoseconds. In order to account
for the wrap-around at 999999999 (0x3B9AC9FF) while using the cycle
counter infrastructure, we need to set a 30bit mask and use the
overflow_point property.
Enable the Broadsync HD timestamping feature in b53_ptp_init() for PTPv2
Ethertype (0x88f7).
Signed-off-by: Martin Kaistra <redacted>
---
[snip]
+int b53_ptp_init(struct b53_device *dev)
+{
+ mutex_init(&dev->ptp_mutex);
+
+ INIT_DELAYED_WORK(&dev->overflow_work, b53_ptp_overflow_check);
+
+ /* Enable BroadSync HD for all ports */
+ b53_write16(dev, B53_BROADSYNC_PAGE, B53_BROADSYNC_EN_CTRL1, 0x00ff);
Can you do this for all enabled user ports instead of each port, that
way it is clera that this register is supposed to be a bitmask of ports
for which you desire PTP timestamping to be enabled?
+
+ /* Enable BroadSync HD Time Stamping Reporting (Egress) */
+ b53_write8(dev, B53_BROADSYNC_PAGE, B53_BROADSYNC_TS_REPORT_CTRL, 0x01);
Can you add a define for this bit in b53_regs.h and name it:
#define TSRPT_PKT_EN BIT(0)
which will enable timestamp reporting towards the IMP port.
+
+ /* Enable BroadSync HD Time Stamping for PTPv2 ingress */
+
+ /* MPORT_CTRL0 | MPORT0_TS_EN */
+ b53_write16(dev, B53_ARLCTRL_PAGE, 0x0e, (1 << 15) | 0x01);
Please add a definition for 0x0e which is the multi-port control
register and is 16-bit wide.
Bit 15 is MPORT0_TS_EN and it will ensure that packets matching
multiport 0 (address or ethertype) will be timestamped.
and then add a macro or generic definitions that are applicable to all
multiport control registers, something like:
#define MPORT_CTRL_DIS_FORWARD 0
#define MPORT_CTRL_CMP_ADDR 1
#define MPORT_CTRL_CMP_ETYPE 2
#define MPORT_CTRL_CMP_ADDR_ETYPE 3
#define MPORT_CTRL_SHIFT(x) ((x) << 2)
#define MPORT_CTRL_MASK 0x3
+ /* Forward to IMP port 8 */
+ b53_write64(dev, B53_ARLCTRL_PAGE, 0x18, (1 << 8));
0x18 is the multiport vector N register so we would want a macro to
define the multiprot vector being used (up to 6 of them), and this is a
32-bit register, not a 64-bit register. The 8 here should be checked
against the actual CPU port index number, it is 8 for you, it could be 5
for someone else, or 7, even.
Use ETH_P_1588 here and 0x10 deserves a define which is the multiport
address N register. Likewise, we need a base offset of 0x10 and then a
macro to address the 6 multiports that exists.
Packets received by the tagger with opcode=1 contain the 32-bit timestamp
according to the timebase register. This timestamp is saved in
BRCM_SKB_CB(skb)->meta_tstamp. b53_port_rxtstamp() takes this
and puts the full time information from the timecounter into
shwt->hwtstamp.
Signed-off-by: Martin Kaistra <redacted>
---
drivers/net/dsa/b53/b53_common.c | 1 +
drivers/net/dsa/b53/b53_ptp.c | 28 ++++++++++++++++++++++++++
drivers/net/dsa/b53/b53_ptp.h | 10 ++++++++++
include/linux/dsa/b53.h | 30 ++++++++++++++++++++++++++++
net/dsa/tag_brcm.c | 34 ++++++++++++++++++++++----------
5 files changed, 93 insertions(+), 10 deletions(-)
@@ -46,9 +46,32 @@ struct b53_io_ops {structphylink_link_state*state);};+/* state flags for b53_port_hwtstamp::state */+enum{+B53_HWTSTAMP_ENABLED,+B53_HWTSTAMP_TX_IN_PROGRESS,+};++structb53_port_hwtstamp{+/* Port index */+intport_id;++/* Timestamping state */+unsignedlongstate;++/* Resources for transmit timestamping */+unsignedlongtx_tstamp_start;+structsk_buff*tx_skb;++/* Current timestamp configuration */+structhwtstamp_configtstamp_config;+};+structb53_port{u16vlan_ctl_mask;structethtool_eeeeee;+/* Per-port timestamping resources */+structb53_port_hwtstampport_hwtstamp;};structb53_vlan{
@@ -31,7 +32,10 @@/* 6th byte in the tag */#define BRCM_LEG_PORT_ID (0xf)-/* Newer Broadcom tag (4 bytes) */+/* Newer Broadcom tag (4 bytes)+*Foregress,whenopcode=0001,additional4bytesareusedfor+*thetimestamp.+*/#define BRCM_TAG_LEN 4/* Tag is constructed and desconstructed using byte by byte access
I believe you have to do this in a two step process, first check that
you can pull 4 bytes, read the Broadcom tag's opcode, then pull the
additional 4 bytes if the opcode is 1.
quoted hunk
- if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
+ if (unlikely(!pskb_may_pull(skb, *tag_len)))
return NULL;
brcm_tag = skb->data - offset;
- /* The opcode should never be different than 0b000 */
- if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
- return NULL;
+ if ((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK) {
+ tstamp = brcm_tag[4] << 24 | brcm_tag[5] << 16 | brcm_tag[6] << 8 | brcm_tag[7];
+ BRCM_SKB_CB(skb)->meta_tstamp = tstamp;
+ } else {
+ *tag_len = BRCM_TAG_LEN;
+ }
/* We should never see a reserved reason code without knowing how to
* handle it
In order to get the switch to generate a timestamp for a transmitted
packet, we need to set the TS bit in the BRCM tag. The switch will then
create a status frame, which gets send back to the cpu.
In b53_port_txtstamp() we put the skb into a waiting position.
When a status frame is received, we extract the timestamp and put the time
according to our timecounter into the waiting skb. When
TX_TSTAMP_TIMEOUT is reached and we have no means to correctly get back
a full timestamp, we cancel the process.
As the status frame doesn't contain a reference to the original packet,
only one packet with timestamp request can be sent at a time.
Signed-off-by: Martin Kaistra <redacted>
---
[snip]
+static long b53_hwtstamp_work(struct ptp_clock_info *ptp)
+{
+ struct b53_device *dev =
+ container_of(ptp, struct b53_device, ptp_clock_info);
+ struct dsa_switch *ds = dev->ds;
+ int i;
+
+ for (i = 0; i < ds->num_ports; i++) {
+ struct b53_port_hwtstamp *ps;
+
+ if (!dsa_is_user_port(ds, i))
+ continue;
Can you also check on !dsa_port_is_unused()?
[snip]
The dsa_port structure as a priv member which would be well suited to
store &b53_dev->ports[dp->index].port_hwtstamp and avoid traversing
multiple layers of objects here. You don't need to need b53_device at
all, and even if you did, you could easily add a back pointer to it in
port_hwstamp.
This applies below as well in brcm_tag_rcv_ll
[snip]
quoted hunk
+
/* Frames with this tag have one of these two layouts:
* -----------------------------------
* | MAC DA | MAC SA | 4b tag | Type | DSA_TAG_PROTO_BRCM
@@ -174,6 +215,16 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb, if (!skb->dev) return NULL;+ /* Check whether this is a status frame */+ if (*tag_len == 8 && brcm_tag[3] & 0x20) {
Can we have an unlikely() here, because this is unlikely to happen
except for switches that do support PTP, and we only have 53128 so far.
Also a define for this 0x20 would be nice, it is the timestamp bit for
the packet.
--
Florian
From: Richard Cochran <richardcochran@gmail.com> Date: 2021-11-07 14:05:42
On Sat, Nov 06, 2021 at 02:36:06AM +0200, Vladimir Oltean wrote:
On Fri, Nov 05, 2021 at 05:18:04PM -0700, Richard Cochran wrote:
quoted
On Fri, Nov 05, 2021 at 04:28:33PM +0200, Vladimir Oltean wrote:
quoted
What is the expected convention exactly? There are other drivers that
downgrade the user application's request to what they support, and at
least ptp4l does not error out, it just prints a warning.
Drivers may upgrade, but they may not downgrade.
Which drivers downgrade? We need to fix those buggy drivers.
Thanks,
Richard
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_NTP_ALL:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
mutex_unlock(&ocelot->ptp_lock);
return -ERANGE;
}
That is essentially an upgrade to HWTSTAMP_FILTER_PTP_V2_EVENT. The
change from ALL to HWTSTAMP_FILTER_PTP_V2_EVENT is probably a simple
oversight, and the driver can be easily fixed.
Thanks,
Richard
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-11-07 14:29:22
On Sun, Nov 07, 2021 at 06:05:34AM -0800, Richard Cochran wrote:
On Sat, Nov 06, 2021 at 02:36:06AM +0200, Vladimir Oltean wrote:
quoted
On Fri, Nov 05, 2021 at 05:18:04PM -0700, Richard Cochran wrote:
quoted
On Fri, Nov 05, 2021 at 04:28:33PM +0200, Vladimir Oltean wrote:
quoted
What is the expected convention exactly? There are other drivers that
downgrade the user application's request to what they support, and at
least ptp4l does not error out, it just prints a warning.
Drivers may upgrade, but they may not downgrade.
Which drivers downgrade? We need to fix those buggy drivers.
Thanks,
Richard
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_NTP_ALL:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
mutex_unlock(&ocelot->ptp_lock);
return -ERANGE;
}
That is essentially an upgrade to HWTSTAMP_FILTER_PTP_V2_EVENT. The
change from ALL to HWTSTAMP_FILTER_PTP_V2_EVENT is probably a simple
oversight, and the driver can be easily fixed.
Thanks,
Richard
It's essentially the same pattern as what Martin is introducing for b53.
From: Martin Kaistra <hidden> Date: 2021-11-08 09:57:54
Am 06.11.21 um 03:50 schrieb Florian Fainelli:
On 11/4/2021 6:32 AM, Martin Kaistra wrote:
quoted
In order to get the switch to generate a timestamp for a transmitted
packet, we need to set the TS bit in the BRCM tag. The switch will then
create a status frame, which gets send back to the cpu.
In b53_port_txtstamp() we put the skb into a waiting position.
When a status frame is received, we extract the timestamp and put the
time
according to our timecounter into the waiting skb. When
TX_TSTAMP_TIMEOUT is reached and we have no means to correctly get back
a full timestamp, we cancel the process.
As the status frame doesn't contain a reference to the original packet,
only one packet with timestamp request can be sent at a time.
Signed-off-by: Martin Kaistra <redacted>
---
[snip]
quoted
+static long b53_hwtstamp_work(struct ptp_clock_info *ptp)
+{
+ struct b53_device *dev =
+ container_of(ptp, struct b53_device, ptp_clock_info);
+ struct dsa_switch *ds = dev->ds;
+ int i;
+
+ for (i = 0; i < ds->num_ports; i++) {
+ struct b53_port_hwtstamp *ps;
+
+ if (!dsa_is_user_port(ds, i))
+ continue;
Can you also check on !dsa_port_is_unused()?
After the currently implemented check, dp->type should be
DSA_PORT_TYPE_USER, so it can't be DSA_PORT_TYPE_UNUSED, right?
Thanks,
Martin
From: Richard Cochran <richardcochran@gmail.com> Date: 2021-11-08 14:48:32
On Sun, Nov 07, 2021 at 04:27:03PM +0200, Vladimir Oltean wrote:
On Sun, Nov 07, 2021 at 06:05:34AM -0800, Richard Cochran wrote:
quoted
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_NTP_ALL:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
mutex_unlock(&ocelot->ptp_lock);
return -ERANGE;
}
That is essentially an upgrade to HWTSTAMP_FILTER_PTP_V2_EVENT. The
change from ALL to HWTSTAMP_FILTER_PTP_V2_EVENT is probably a simple
oversight, and the driver can be easily fixed.
Thanks,
Richard
It's essentially the same pattern as what Martin is introducing for b53.
Uh, no it isn't. The present patch has:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_ALL:
+ config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
There is an important difference between
HWTSTAMP_FILTER_PTP_V2_L2_EVENT and HWTSTAMP_FILTER_PTP_V2_EVENT
Notice the "L2" in there.
Thanks,
Richard
From: Martin Kaistra <hidden> Date: 2021-11-08 15:00:54
Am 06.11.21 um 03:32 schrieb Florian Fainelli:
On 11/4/2021 6:31 AM, Martin Kaistra wrote:
quoted
The BCM53128 switch has an internal clock, which can be used for
timestamping. Add support for it.
The 32-bit free running clock counts nanoseconds. In order to account
for the wrap-around at 999999999 (0x3B9AC9FF) while using the cycle
counter infrastructure, we need to set a 30bit mask and use the
overflow_point property.
Enable the Broadsync HD timestamping feature in b53_ptp_init() for PTPv2
Ethertype (0x88f7).
Signed-off-by: Martin Kaistra <redacted>
---
[snip]
quoted
+int b53_ptp_init(struct b53_device *dev)
+{
+ mutex_init(&dev->ptp_mutex);
+
+ INIT_DELAYED_WORK(&dev->overflow_work, b53_ptp_overflow_check);
+
+ /* Enable BroadSync HD for all ports */
+ b53_write16(dev, B53_BROADSYNC_PAGE, B53_BROADSYNC_EN_CTRL1,
0x00ff);
Can you do this for all enabled user ports instead of each port, that
way it is clera that this register is supposed to be a bitmask of ports
for which you desire PTP timestamping to be enabled?
quoted
+
+ /* Enable BroadSync HD Time Stamping Reporting (Egress) */
+ b53_write8(dev, B53_BROADSYNC_PAGE, B53_BROADSYNC_TS_REPORT_CTRL,
0x01);
Can you add a define for this bit in b53_regs.h and name it:
#define TSRPT_PKT_EN BIT(0)
which will enable timestamp reporting towards the IMP port.
quoted
+
+ /* Enable BroadSync HD Time Stamping for PTPv2 ingress */
+
+ /* MPORT_CTRL0 | MPORT0_TS_EN */
+ b53_write16(dev, B53_ARLCTRL_PAGE, 0x0e, (1 << 15) | 0x01);
Please add a definition for 0x0e which is the multi-port control
register and is 16-bit wide.
Bit 15 is MPORT0_TS_EN and it will ensure that packets matching
multiport 0 (address or ethertype) will be timestamped.
and then add a macro or generic definitions that are applicable to all
multiport control registers, something like:
#define MPORT_CTRL_DIS_FORWARD 0
#define MPORT_CTRL_CMP_ADDR 1
#define MPORT_CTRL_CMP_ETYPE 2
#define MPORT_CTRL_CMP_ADDR_ETYPE 3
#define MPORT_CTRL_SHIFT(x) ((x) << 2)
#define MPORT_CTRL_MASK 0x3
quoted
+ /* Forward to IMP port 8 */
+ b53_write64(dev, B53_ARLCTRL_PAGE, 0x18, (1 << 8));
0x18 is the multiport vector N register so we would want a macro to
define the multiprot vector being used (up to 6 of them), and this is a
32-bit register, not a 64-bit register. The 8 here should be checked
against the actual CPU port index number, it is 8 for you, it could be 5
for someone else, or 7, even.
Use ETH_P_1588 here and 0x10 deserves a define which is the multiport
address N register. Likewise, we need a base offset of 0x10 and then a
macro to address the 6 multiports that exists.
memset the structure ahead of time so you only need explicit
initialization where needed?
quoted
+ dev->ptp_clock_info.adjfine = b53_ptp_adjfine;
+ dev->ptp_clock_info.adjtime = b53_ptp_adjtime;
+ dev->ptp_clock_info.gettime64 = b53_ptp_gettime;
+ dev->ptp_clock_info.settime64 = b53_ptp_settime;
+ dev->ptp_clock_info.enable = b53_ptp_enable;
+
+ dev->ptp_clock = ptp_clock_register(&dev->ptp_clock_info, dev->dev);
+ if (IS_ERR(dev->ptp_clock))
+ return PTR_ERR(dev->ptp_clock);
+
+ /* The switch provides a 32 bit free running counter. Use the Linux
+ * cycle counter infrastructure which is suited for such scenarios.
+ */
+ dev->cc.read = b53_ptp_read;
+ dev->cc.mask = CYCLECOUNTER_MASK(30);
+ dev->cc.overflow_point = 999999999;
+ dev->cc.mult = (1 << 28);
+ dev->cc.shift = 28;
+
+ b53_write32(dev, B53_BROADSYNC_PAGE, B53_BROADSYNC_TIMEBASE_ADJ1,
40);
You are writing the default value of the register, is that of any use?
Appearently not, I just tested it without this line and it seems to work
fine.
It just seemed strange to me, that while the datasheet mentions 40 as
the default value, when reading the register without writing this
initial value, I just get back 0.
I'll remove the line for v2.
Thanks,
Martin
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-11-25 17:19:16
On Mon, Nov 08, 2021 at 06:48:24AM -0800, Richard Cochran wrote:
On Sun, Nov 07, 2021 at 04:27:03PM +0200, Vladimir Oltean wrote:
quoted
On Sun, Nov 07, 2021 at 06:05:34AM -0800, Richard Cochran wrote:
quoted
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_NTP_ALL:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
mutex_unlock(&ocelot->ptp_lock);
return -ERANGE;
}
That is essentially an upgrade to HWTSTAMP_FILTER_PTP_V2_EVENT. The
change from ALL to HWTSTAMP_FILTER_PTP_V2_EVENT is probably a simple
oversight, and the driver can be easily fixed.
Thanks,
Richard
It's essentially the same pattern as what Martin is introducing for b53.
Uh, no it isn't. The present patch has:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_ALL:
+ config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
There is an important difference between
HWTSTAMP_FILTER_PTP_V2_L2_EVENT and HWTSTAMP_FILTER_PTP_V2_EVENT
Notice the "L2" in there.
Richard, when the request is PTP_V2_EVENT and the response is
PTP_V2_L2_EVENT, is that an upgrade or a downgrade? PTP_V2_EVENT also
includes PTP_V2_L4_EVENT.
From: Kurt Kanzenbach <kurt@linutronix.de> Date: 2021-11-26 08:48:27
On Thu Nov 25 2021, Vladimir Oltean wrote:
On Mon, Nov 08, 2021 at 06:48:24AM -0800, Richard Cochran wrote:
quoted
On Sun, Nov 07, 2021 at 04:27:03PM +0200, Vladimir Oltean wrote:
quoted
On Sun, Nov 07, 2021 at 06:05:34AM -0800, Richard Cochran wrote:
quoted
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
case HWTSTAMP_FILTER_ALL:
case HWTSTAMP_FILTER_SOME:
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_NTP_ALL:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
default:
mutex_unlock(&ocelot->ptp_lock);
return -ERANGE;
}
That is essentially an upgrade to HWTSTAMP_FILTER_PTP_V2_EVENT. The
change from ALL to HWTSTAMP_FILTER_PTP_V2_EVENT is probably a simple
oversight, and the driver can be easily fixed.
Thanks,
Richard
It's essentially the same pattern as what Martin is introducing for b53.
Uh, no it isn't. The present patch has:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_ALL:
+ config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
There is an important difference between
HWTSTAMP_FILTER_PTP_V2_L2_EVENT and HWTSTAMP_FILTER_PTP_V2_EVENT
Notice the "L2" in there.
Richard, when the request is PTP_V2_EVENT and the response is
PTP_V2_L2_EVENT, is that an upgrade or a downgrade?
From: Richard Cochran <richardcochran@gmail.com> Date: 2021-11-26 16:42:43
On Fri, Nov 26, 2021 at 09:42:32AM +0100, Kurt Kanzenbach wrote:
On Thu Nov 25 2021, Vladimir Oltean wrote:
quoted
Richard, when the request is PTP_V2_EVENT and the response is
PTP_V2_L2_EVENT, is that an upgrade or a downgrade?
It is a downgrade, isn't it?
Yes. "Any kind of PTP Event" is a superset of "Any Layer-2 Event".
When userland asks for "any kind", then it wants to run PTP over IPv4,
IPv6, or Layer2, maybe even more than one at the same time. If the
driver changes that to Layer2 only, then the PTP possibilities have
been downgraded.
Thanks,
Richard
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-11-26 17:11:29
On Fri, 26 Nov 2021 at 18:31, Richard Cochran [off-list ref] wrote:
On Fri, Nov 26, 2021 at 09:42:32AM +0100, Kurt Kanzenbach wrote:
quoted
On Thu Nov 25 2021, Vladimir Oltean wrote:
quoted
Richard, when the request is PTP_V2_EVENT and the response is
PTP_V2_L2_EVENT, is that an upgrade or a downgrade?
It is a downgrade, isn't it?
Yes. "Any kind of PTP Event" is a superset of "Any Layer-2 Event".
When userland asks for "any kind", then it wants to run PTP over IPv4,
IPv6, or Layer2, maybe even more than one at the same time. If the
driver changes that to Layer2 only, then the PTP possibilities have
been downgraded.
Well, when I said that it's essentially the same pattern, this is what
I was talking about. The b53 driver downgrades everything and the
kitchen sink to HWTSTAMP_FILTER_PTP_V2_L2_EVENT, the ocelot driver to
HWTSTAMP_FILTER_PTP_V2_EVENT, and both are buggy for the same reason.
I don't see why you mention that there is an important difference
between HWTSTAMP_FILTER_PTP_V2_L2_EVENT and
HWTSTAMP_FILTER_PTP_V2_EVENT. I know there is, but the _pattern_ is
the same.
I'm still missing something obvious, aren't I?
From: Richard Cochran <richardcochran@gmail.com> Date: 2021-11-26 17:29:41
On Fri, Nov 26, 2021 at 06:42:57PM +0200, Vladimir Oltean wrote:
I'm still missing something obvious, aren't I?
You said there are "many more" drivers with this bug, but I'm saying
that most drivers correctly upgrade the ioctl request.
So far we have b53 and ocelot doing the buggy downgrade. I guess it
will require a tree wide audit to discover the "many more"...
Thanks,
Richard
From: Vladimir Oltean <olteanv@gmail.com> Date: 2021-11-26 17:40:51
On Fri, Nov 26, 2021 at 09:03:48AM -0800, Richard Cochran wrote:
On Fri, Nov 26, 2021 at 06:42:57PM +0200, Vladimir Oltean wrote:
quoted
I'm still missing something obvious, aren't I?
You said there are "many more" drivers with this bug, but I'm saying
that most drivers correctly upgrade the ioctl request.
So far we have b53 and ocelot doing the buggy downgrade. I guess it
will require a tree wide audit to discover the "many more"...
Ah, yes, I assure you that there are many more drivers doing wacky
stuff, for example sja1105 will take any RX filter that isn't NONE, and
then reports it back as PTP_V2_L2_EVENT.
https://elixir.bootlin.com/linux/latest/source/drivers/net/dsa/sja1105/sja1105_ptp.c#L89
Somehow at this stage I don't even want to know about any other drivers,
since I might feel the urge to patch them and I don't really have the
necessary free time for that right now :D