summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2023-06-29 12:40:29 +0200
committerPaolo Abeni <pabeni@redhat.com>2023-06-29 12:40:30 +0200
commite999c897cd626c05f5d68ab02028a210ceca3545 (patch)
tree05d56d6e379d136731aba8dfe3a81c42169284d4
parent3c4bb45ab29303265a8c6d7099e00c824503c586 (diff)
parent2edcfcbb3c5946609be1d8875473a240b170673b (diff)
Merge branch 'fix-ptp-packet-drops-with-ocelot-8021q-dsa-tag-protocol'
Vladimir Oltean says: ==================== Fix PTP packet drops with ocelot-8021q DSA tag protocol Changes in v2: - Distinguish between L2 and L4 PTP packets v1 at: https://lore.kernel.org/netdev/20230626154003.3153076-1-vladimir.oltean@nxp.com/ Patch 3/3 fixes an issue with the ocelot/felix driver, where it would drop PTP traffic on RX unless hardware timestamping for that packet type was enabled. Fixing that requires the driver to know whether it had previously configured the hardware to timestamp PTP packets on that port. But it cannot correctly determine that today using the existing code structure, so patches 1/3 and 2/3 fix the control path of the code such that ocelot->ports[port]->trap_proto faithfully reflects whether that configuration took place. ==================== Link: https://lore.kernel.org/r/20230627163114.3561597-1-vladimir.oltean@nxp.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--drivers/net/dsa/ocelot/felix.c12
-rw-r--r--drivers/net/ethernet/mscc/ocelot.c1
-rw-r--r--drivers/net/ethernet/mscc/ocelot_ptp.c66
-rw-r--r--include/soc/mscc/ocelot.h10
4 files changed, 60 insertions, 29 deletions
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 80861ac090ae..70c0e2b1936b 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -1725,6 +1725,18 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port,
u32 tstamp_hi;
u64 tstamp;
+ switch (type & PTP_CLASS_PMASK) {
+ case PTP_CLASS_L2:
+ if (!(ocelot->ports[port]->trap_proto & OCELOT_PROTO_PTP_L2))
+ return false;
+ break;
+ case PTP_CLASS_IPV4:
+ case PTP_CLASS_IPV6:
+ if (!(ocelot->ports[port]->trap_proto & OCELOT_PROTO_PTP_L4))
+ return false;
+ break;
+ }
+
/* If the "no XTR IRQ" workaround is in use, tell DSA to defer this skb
* for RX timestamping. Then free it, and poll for its copy through
* MMIO in the CPU port module, and inject that into the stack from
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
index 1f5f00b30441..2fa833d041ba 100644
--- a/drivers/net/ethernet/mscc/ocelot.c
+++ b/drivers/net/ethernet/mscc/ocelot.c
@@ -2925,7 +2925,6 @@ int ocelot_init(struct ocelot *ocelot)
}
}
- mutex_init(&ocelot->ptp_lock);
mutex_init(&ocelot->mact_lock);
mutex_init(&ocelot->fwd_domain_lock);
mutex_init(&ocelot->tas_lock);
diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c
index 2180ae94c744..cb32234a5bf1 100644
--- a/drivers/net/ethernet/mscc/ocelot_ptp.c
+++ b/drivers/net/ethernet/mscc/ocelot_ptp.c
@@ -439,8 +439,12 @@ static int ocelot_ipv6_ptp_trap_del(struct ocelot *ocelot, int port)
static int ocelot_setup_ptp_traps(struct ocelot *ocelot, int port,
bool l2, bool l4)
{
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
int err;
+ ocelot_port->trap_proto &= ~(OCELOT_PROTO_PTP_L2 |
+ OCELOT_PROTO_PTP_L4);
+
if (l2)
err = ocelot_l2_ptp_trap_add(ocelot, port);
else
@@ -464,6 +468,11 @@ static int ocelot_setup_ptp_traps(struct ocelot *ocelot, int port,
if (err)
return err;
+ if (l2)
+ ocelot_port->trap_proto |= OCELOT_PROTO_PTP_L2;
+ if (l4)
+ ocelot_port->trap_proto |= OCELOT_PROTO_PTP_L4;
+
return 0;
err_ipv6:
@@ -474,10 +483,38 @@ err_ipv4:
return err;
}
+static int ocelot_traps_to_ptp_rx_filter(unsigned int proto)
+{
+ if ((proto & OCELOT_PROTO_PTP_L2) && (proto & OCELOT_PROTO_PTP_L4))
+ return HWTSTAMP_FILTER_PTP_V2_EVENT;
+ else if (proto & OCELOT_PROTO_PTP_L2)
+ return HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+ else if (proto & OCELOT_PROTO_PTP_L4)
+ return HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+
+ return HWTSTAMP_FILTER_NONE;
+}
+
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
{
- return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
- sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0;
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
+ struct hwtstamp_config cfg = {};
+
+ switch (ocelot_port->ptp_cmd) {
+ case IFH_REW_OP_TWO_STEP_PTP:
+ cfg.tx_type = HWTSTAMP_TX_ON;
+ break;
+ case IFH_REW_OP_ORIGIN_PTP:
+ cfg.tx_type = HWTSTAMP_TX_ONESTEP_SYNC;
+ break;
+ default:
+ cfg.tx_type = HWTSTAMP_TX_OFF;
+ break;
+ }
+
+ cfg.rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto);
+
+ return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
EXPORT_SYMBOL(ocelot_hwstamp_get);
@@ -509,8 +546,6 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
return -ERANGE;
}
- mutex_lock(&ocelot->ptp_lock);
-
switch (cfg.rx_filter) {
case HWTSTAMP_FILTER_NONE:
break;
@@ -531,28 +566,14 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
l4 = true;
break;
default:
- mutex_unlock(&ocelot->ptp_lock);
return -ERANGE;
}
err = ocelot_setup_ptp_traps(ocelot, port, l2, l4);
- if (err) {
- mutex_unlock(&ocelot->ptp_lock);
+ if (err)
return err;
- }
- if (l2 && l4)
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
- else if (l2)
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
- else if (l4)
- cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
- else
- cfg.rx_filter = HWTSTAMP_FILTER_NONE;
-
- /* Commit back the result & save it */
- memcpy(&ocelot->hwtstamp_config, &cfg, sizeof(cfg));
- mutex_unlock(&ocelot->ptp_lock);
+ cfg.rx_filter = ocelot_traps_to_ptp_rx_filter(ocelot_port->trap_proto);
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
@@ -824,11 +845,6 @@ int ocelot_init_timestamp(struct ocelot *ocelot,
ocelot_write(ocelot, PTP_CFG_MISC_PTP_EN, PTP_CFG_MISC);
- /* There is no device reconfiguration, PTP Rx stamping is always
- * enabled.
- */
- ocelot->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
-
return 0;
}
EXPORT_SYMBOL(ocelot_init_timestamp);
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index cb8fbb241879..22aae505c813 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -730,6 +730,11 @@ enum macaccess_entry_type {
ENTRYTYPE_MACv6,
};
+enum ocelot_proto {
+ OCELOT_PROTO_PTP_L2 = BIT(0),
+ OCELOT_PROTO_PTP_L4 = BIT(1),
+};
+
#define OCELOT_QUIRK_PCS_PERFORMS_RATE_ADAPTATION BIT(0)
#define OCELOT_QUIRK_QSGMII_PORTS_MUST_BE_UP BIT(1)
@@ -775,6 +780,8 @@ struct ocelot_port {
unsigned int ptp_skbs_in_flight;
struct sk_buff_head tx_skbs;
+ unsigned int trap_proto;
+
u16 mrp_ring_id;
u8 ptp_cmd;
@@ -868,12 +875,9 @@ struct ocelot {
u8 mm_supported:1;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_info;
- struct hwtstamp_config hwtstamp_config;
unsigned int ptp_skbs_in_flight;
/* Protects the 2-step TX timestamp ID logic */
spinlock_t ts_id_lock;
- /* Protects the PTP interface state */
- struct mutex ptp_lock;
/* Protects the PTP clock */
spinlock_t ptp_clock_lock;
struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM];