Skip to content

Commit 32c5449

Browse files
committed
Merge branch 'fix-broken-ptp-over-ip-on-ocelot-switches'
Vladimir Oltean says: ==================== Fix broken PTP over IP on Ocelot switches Changes in v2: added patch 5, added Richard's ack for the whole series sans patch 5 which is new. Po Liu reported recently that timestamping PTP over IPv4 is broken using the felix driver on NXP LS1028A. This has been known for a while, of course, since it has always been broken. The reason is because IP PTP packets are currently treated as unknown IP multicast, which is not flooded to the CPU port in the ocelot driver design, so packets don't reach the ptp4l program. The series solves the problem by installing packet traps per port when the timestamping ioctl is called, depending on the RX filter selected (L2, L4 or both). ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents b32e521 + c49a35e commit 32c5449

File tree

4 files changed

+263
-8
lines changed

4 files changed

+263
-8
lines changed

drivers/net/ethernet/mscc/ocelot.c

Lines changed: 244 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,225 @@ int ocelot_fdb_dump(struct ocelot *ocelot, int port,
12781278
}
12791279
EXPORT_SYMBOL(ocelot_fdb_dump);
12801280

1281+
static void ocelot_populate_l2_ptp_trap_key(struct ocelot_vcap_filter *trap)
1282+
{
1283+
trap->key_type = OCELOT_VCAP_KEY_ETYPE;
1284+
*(__be16 *)trap->key.etype.etype.value = htons(ETH_P_1588);
1285+
*(__be16 *)trap->key.etype.etype.mask = htons(0xffff);
1286+
}
1287+
1288+
static void
1289+
ocelot_populate_ipv4_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
1290+
{
1291+
trap->key_type = OCELOT_VCAP_KEY_IPV4;
1292+
trap->key.ipv4.dport.value = PTP_EV_PORT;
1293+
trap->key.ipv4.dport.mask = 0xffff;
1294+
}
1295+
1296+
static void
1297+
ocelot_populate_ipv6_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
1298+
{
1299+
trap->key_type = OCELOT_VCAP_KEY_IPV6;
1300+
trap->key.ipv6.dport.value = PTP_EV_PORT;
1301+
trap->key.ipv6.dport.mask = 0xffff;
1302+
}
1303+
1304+
static void
1305+
ocelot_populate_ipv4_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
1306+
{
1307+
trap->key_type = OCELOT_VCAP_KEY_IPV4;
1308+
trap->key.ipv4.dport.value = PTP_GEN_PORT;
1309+
trap->key.ipv4.dport.mask = 0xffff;
1310+
}
1311+
1312+
static void
1313+
ocelot_populate_ipv6_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
1314+
{
1315+
trap->key_type = OCELOT_VCAP_KEY_IPV6;
1316+
trap->key.ipv6.dport.value = PTP_GEN_PORT;
1317+
trap->key.ipv6.dport.mask = 0xffff;
1318+
}
1319+
1320+
static int ocelot_trap_add(struct ocelot *ocelot, int port,
1321+
unsigned long cookie,
1322+
void (*populate)(struct ocelot_vcap_filter *f))
1323+
{
1324+
struct ocelot_vcap_block *block_vcap_is2;
1325+
struct ocelot_vcap_filter *trap;
1326+
bool new = false;
1327+
int err;
1328+
1329+
block_vcap_is2 = &ocelot->block[VCAP_IS2];
1330+
1331+
trap = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, cookie,
1332+
false);
1333+
if (!trap) {
1334+
trap = kzalloc(sizeof(*trap), GFP_KERNEL);
1335+
if (!trap)
1336+
return -ENOMEM;
1337+
1338+
populate(trap);
1339+
trap->prio = 1;
1340+
trap->id.cookie = cookie;
1341+
trap->id.tc_offload = false;
1342+
trap->block_id = VCAP_IS2;
1343+
trap->type = OCELOT_VCAP_FILTER_OFFLOAD;
1344+
trap->lookup = 0;
1345+
trap->action.cpu_copy_ena = true;
1346+
trap->action.mask_mode = OCELOT_MASK_MODE_PERMIT_DENY;
1347+
trap->action.port_mask = 0;
1348+
new = true;
1349+
}
1350+
1351+
trap->ingress_port_mask |= BIT(port);
1352+
1353+
if (new)
1354+
err = ocelot_vcap_filter_add(ocelot, trap, NULL);
1355+
else
1356+
err = ocelot_vcap_filter_replace(ocelot, trap);
1357+
if (err) {
1358+
trap->ingress_port_mask &= ~BIT(port);
1359+
if (!trap->ingress_port_mask)
1360+
kfree(trap);
1361+
return err;
1362+
}
1363+
1364+
return 0;
1365+
}
1366+
1367+
static int ocelot_trap_del(struct ocelot *ocelot, int port,
1368+
unsigned long cookie)
1369+
{
1370+
struct ocelot_vcap_block *block_vcap_is2;
1371+
struct ocelot_vcap_filter *trap;
1372+
1373+
block_vcap_is2 = &ocelot->block[VCAP_IS2];
1374+
1375+
trap = ocelot_vcap_block_find_filter_by_id(block_vcap_is2, cookie,
1376+
false);
1377+
if (!trap)
1378+
return 0;
1379+
1380+
trap->ingress_port_mask &= ~BIT(port);
1381+
if (!trap->ingress_port_mask)
1382+
return ocelot_vcap_filter_del(ocelot, trap);
1383+
1384+
return ocelot_vcap_filter_replace(ocelot, trap);
1385+
}
1386+
1387+
static int ocelot_l2_ptp_trap_add(struct ocelot *ocelot, int port)
1388+
{
1389+
unsigned long l2_cookie = ocelot->num_phys_ports + 1;
1390+
1391+
return ocelot_trap_add(ocelot, port, l2_cookie,
1392+
ocelot_populate_l2_ptp_trap_key);
1393+
}
1394+
1395+
static int ocelot_l2_ptp_trap_del(struct ocelot *ocelot, int port)
1396+
{
1397+
unsigned long l2_cookie = ocelot->num_phys_ports + 1;
1398+
1399+
return ocelot_trap_del(ocelot, port, l2_cookie);
1400+
}
1401+
1402+
static int ocelot_ipv4_ptp_trap_add(struct ocelot *ocelot, int port)
1403+
{
1404+
unsigned long ipv4_gen_cookie = ocelot->num_phys_ports + 2;
1405+
unsigned long ipv4_ev_cookie = ocelot->num_phys_ports + 3;
1406+
int err;
1407+
1408+
err = ocelot_trap_add(ocelot, port, ipv4_ev_cookie,
1409+
ocelot_populate_ipv4_ptp_event_trap_key);
1410+
if (err)
1411+
return err;
1412+
1413+
err = ocelot_trap_add(ocelot, port, ipv4_gen_cookie,
1414+
ocelot_populate_ipv4_ptp_general_trap_key);
1415+
if (err)
1416+
ocelot_trap_del(ocelot, port, ipv4_ev_cookie);
1417+
1418+
return err;
1419+
}
1420+
1421+
static int ocelot_ipv4_ptp_trap_del(struct ocelot *ocelot, int port)
1422+
{
1423+
unsigned long ipv4_gen_cookie = ocelot->num_phys_ports + 2;
1424+
unsigned long ipv4_ev_cookie = ocelot->num_phys_ports + 3;
1425+
int err;
1426+
1427+
err = ocelot_trap_del(ocelot, port, ipv4_ev_cookie);
1428+
err |= ocelot_trap_del(ocelot, port, ipv4_gen_cookie);
1429+
return err;
1430+
}
1431+
1432+
static int ocelot_ipv6_ptp_trap_add(struct ocelot *ocelot, int port)
1433+
{
1434+
unsigned long ipv6_gen_cookie = ocelot->num_phys_ports + 4;
1435+
unsigned long ipv6_ev_cookie = ocelot->num_phys_ports + 5;
1436+
int err;
1437+
1438+
err = ocelot_trap_add(ocelot, port, ipv6_ev_cookie,
1439+
ocelot_populate_ipv6_ptp_event_trap_key);
1440+
if (err)
1441+
return err;
1442+
1443+
err = ocelot_trap_add(ocelot, port, ipv6_gen_cookie,
1444+
ocelot_populate_ipv6_ptp_general_trap_key);
1445+
if (err)
1446+
ocelot_trap_del(ocelot, port, ipv6_ev_cookie);
1447+
1448+
return err;
1449+
}
1450+
1451+
static int ocelot_ipv6_ptp_trap_del(struct ocelot *ocelot, int port)
1452+
{
1453+
unsigned long ipv6_gen_cookie = ocelot->num_phys_ports + 4;
1454+
unsigned long ipv6_ev_cookie = ocelot->num_phys_ports + 5;
1455+
int err;
1456+
1457+
err = ocelot_trap_del(ocelot, port, ipv6_ev_cookie);
1458+
err |= ocelot_trap_del(ocelot, port, ipv6_gen_cookie);
1459+
return err;
1460+
}
1461+
1462+
static int ocelot_setup_ptp_traps(struct ocelot *ocelot, int port,
1463+
bool l2, bool l4)
1464+
{
1465+
int err;
1466+
1467+
if (l2)
1468+
err = ocelot_l2_ptp_trap_add(ocelot, port);
1469+
else
1470+
err = ocelot_l2_ptp_trap_del(ocelot, port);
1471+
if (err)
1472+
return err;
1473+
1474+
if (l4) {
1475+
err = ocelot_ipv4_ptp_trap_add(ocelot, port);
1476+
if (err)
1477+
goto err_ipv4;
1478+
1479+
err = ocelot_ipv6_ptp_trap_add(ocelot, port);
1480+
if (err)
1481+
goto err_ipv6;
1482+
} else {
1483+
err = ocelot_ipv4_ptp_trap_del(ocelot, port);
1484+
1485+
err |= ocelot_ipv6_ptp_trap_del(ocelot, port);
1486+
}
1487+
if (err)
1488+
return err;
1489+
1490+
return 0;
1491+
1492+
err_ipv6:
1493+
ocelot_ipv4_ptp_trap_del(ocelot, port);
1494+
err_ipv4:
1495+
if (l2)
1496+
ocelot_l2_ptp_trap_del(ocelot, port);
1497+
return err;
1498+
}
1499+
12811500
int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr)
12821501
{
12831502
return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config,
@@ -1288,7 +1507,9 @@ EXPORT_SYMBOL(ocelot_hwstamp_get);
12881507
int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
12891508
{
12901509
struct ocelot_port *ocelot_port = ocelot->ports[port];
1510+
bool l2 = false, l4 = false;
12911511
struct hwtstamp_config cfg;
1512+
int err;
12921513

12931514
if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
12941515
return -EFAULT;
@@ -1320,28 +1541,40 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
13201541
switch (cfg.rx_filter) {
13211542
case HWTSTAMP_FILTER_NONE:
13221543
break;
1323-
case HWTSTAMP_FILTER_ALL:
1324-
case HWTSTAMP_FILTER_SOME:
1325-
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
1326-
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
1327-
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
1328-
case HWTSTAMP_FILTER_NTP_ALL:
13291544
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
13301545
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
13311546
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
1547+
l4 = true;
1548+
break;
13321549
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
13331550
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
13341551
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
1552+
l2 = true;
1553+
break;
13351554
case HWTSTAMP_FILTER_PTP_V2_EVENT:
13361555
case HWTSTAMP_FILTER_PTP_V2_SYNC:
13371556
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
1338-
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
1557+
l2 = true;
1558+
l4 = true;
13391559
break;
13401560
default:
13411561
mutex_unlock(&ocelot->ptp_lock);
13421562
return -ERANGE;
13431563
}
13441564

1565+
err = ocelot_setup_ptp_traps(ocelot, port, l2, l4);
1566+
if (err)
1567+
return err;
1568+
1569+
if (l2 && l4)
1570+
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
1571+
else if (l2)
1572+
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
1573+
else if (l4)
1574+
cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
1575+
else
1576+
cfg.rx_filter = HWTSTAMP_FILTER_NONE;
1577+
13451578
/* Commit back the result & save it */
13461579
memcpy(&ocelot->hwtstamp_config, &cfg, sizeof(cfg));
13471580
mutex_unlock(&ocelot->ptp_lock);
@@ -1444,7 +1677,10 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
14441677
SOF_TIMESTAMPING_RAW_HARDWARE;
14451678
info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON) |
14461679
BIT(HWTSTAMP_TX_ONESTEP_SYNC);
1447-
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
1680+
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
1681+
BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
1682+
BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
1683+
BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
14481684

14491685
return 0;
14501686
}

drivers/net/ethernet/mscc/ocelot_vcap.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,22 @@ int ocelot_vcap_filter_del(struct ocelot *ocelot,
12171217
}
12181218
EXPORT_SYMBOL(ocelot_vcap_filter_del);
12191219

1220+
int ocelot_vcap_filter_replace(struct ocelot *ocelot,
1221+
struct ocelot_vcap_filter *filter)
1222+
{
1223+
struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
1224+
int index;
1225+
1226+
index = ocelot_vcap_block_get_filter_index(block, filter);
1227+
if (index < 0)
1228+
return index;
1229+
1230+
vcap_entry_set(ocelot, index, filter);
1231+
1232+
return 0;
1233+
}
1234+
EXPORT_SYMBOL(ocelot_vcap_filter_replace);
1235+
12201236
int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
12211237
struct ocelot_vcap_filter *filter)
12221238
{

include/linux/ptp_classify.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#define PTP_MSGTYPE_PDELAY_RESP 0x3
3838

3939
#define PTP_EV_PORT 319
40+
#define PTP_GEN_PORT 320
4041
#define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */
4142

4243
#define OFF_PTP_SOURCE_UUID 22 /* PTPv1 only */

include/soc/mscc/ocelot_vcap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
703703
struct netlink_ext_ack *extack);
704704
int ocelot_vcap_filter_del(struct ocelot *ocelot,
705705
struct ocelot_vcap_filter *rule);
706+
int ocelot_vcap_filter_replace(struct ocelot *ocelot,
707+
struct ocelot_vcap_filter *filter);
706708
struct ocelot_vcap_filter *
707709
ocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block *block,
708710
unsigned long cookie, bool tc_offload);

0 commit comments

Comments
 (0)