Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'Peer-to-Peer-One-Step-time-stamping'

Richard Cochran says:

====================
Peer to Peer One-Step time stamping

This series adds support for PTP (IEEE 1588) P2P one-step time
stamping along with a driver for a hardware device that supports this.

If the hardware supports p2p one-step, it subtracts the ingress time
stamp value from the Pdelay_Request correction field. The user space
software stack then simply copies the correction field into the
Pdelay_Response, and on transmission the hardware adds the egress time
stamp into the correction field.

This new functionality extends CONFIG_NETWORK_PHY_TIMESTAMPING to
cover MII snooping devices, but it still depends on phylib, just as
that option does. Expanding beyond phylib is not within the scope of
the this series.

User space support is available in the current linuxptp master branch.

- Patch 1 adds phy_device methods for existing time stamping fields.
- Patches 2-5 convert the stack and drivers to the new methods.
- Patch 6 moves code around the dp83640 driver.
- Patches 7-10 add support for MII time stamping in non-PHY devices.
- Patch 11 adds the new P2P 1-step option.
- Patch 12 adds a driver implementing the new option.

Thanks,
Richard

Changed in v9:
~~~~~~~~~~~~~~

- Fix two more drivers' switch/case blocks WRT the new HWTSTAMP ioctl.
- Picked up two more review tags from Andrew.

Changed in v8:
~~~~~~~~~~~~~~

- Avoided adding forward functional declarations in the dp83640 driver.
- Picked up Florian's new review tags and another one from Andrew.

Changed in v7:
~~~~~~~~~~~~~~

- Converted pr_debug|err to dev_ variants in new driver.
- Fixed device tree documentation per Rob's v6 review.
- Picked up Andrew's and Rob's review tags.
- Silenced sparse warnings in new driver.

Changed in v6:
~~~~~~~~~~~~~~

- Added methods for accessing the phy_device time stamping fields.
- Adjust the device tree documentation per Rob's v5 review.
- Fixed the build failures due to missing exports.

Changed in v5:
~~~~~~~~~~~~~~

- Fixed build failure in macvlan.
- Fixed latent bug with its gcc warning in the driver.

Changed in v4:
~~~~~~~~~~~~~~

- Correct error paths and PTR_ERR return values in the framework.
- Expanded KernelDoc comments WRT PHY locking.
- Pick up Andrew's review tag.

Changed in v3:
~~~~~~~~~~~~~~

- Simplify the device tree binding and document the time stamping
phandle by itself.

Changed in v2:
~~~~~~~~~~~~~~

- Per the v1 review, changed the modeling of MII time stamping
devices. They are no longer a kind of mdio device.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1437 -154
+35
Documentation/devicetree/bindings/ptp/ptp-ines.txt
··· 1 + ZHAW InES PTP time stamping IP core 2 + 3 + The IP core needs two different kinds of nodes. The control node 4 + lives somewhere in the memory map and specifies the address of the 5 + control registers. There can be up to three port handles placed as 6 + attributes of PHY nodes. These associate a particular MII bus with a 7 + port index within the IP core. 8 + 9 + Required properties of the control node: 10 + 11 + - compatible: "ines,ptp-ctrl" 12 + - reg: physical address and size of the register bank 13 + 14 + Required format of the port handle within the PHY node: 15 + 16 + - timestamper: provides control node reference and 17 + the port channel within the IP core 18 + 19 + Example: 20 + 21 + tstamper: timestamper@60000000 { 22 + compatible = "ines,ptp-ctrl"; 23 + reg = <0x60000000 0x80>; 24 + }; 25 + 26 + ethernet@80000000 { 27 + ... 28 + mdio { 29 + ... 30 + ethernet-phy@3 { 31 + ... 32 + timestamper = <&tstamper 0>; 33 + }; 34 + }; 35 + };
+42
Documentation/devicetree/bindings/ptp/timestamper.txt
··· 1 + Time stamps from MII bus snooping devices 2 + 3 + This binding supports non-PHY devices that snoop the MII bus and 4 + provide time stamps. In contrast to PHY time stamping drivers (which 5 + can simply attach their interface directly to the PHY instance), stand 6 + alone MII time stamping drivers use this binding to specify the 7 + connection between the snooping device and a given network interface. 8 + 9 + Non-PHY MII time stamping drivers typically talk to the control 10 + interface over another bus like I2C, SPI, UART, or via a memory mapped 11 + peripheral. This controller device is associated with one or more 12 + time stamping channels, each of which snoops on a MII bus. 13 + 14 + The "timestamper" property lives in a phy node and links a time 15 + stamping channel from the controller device to that phy's MII bus. 16 + 17 + Example: 18 + 19 + tstamper: timestamper@10000000 { 20 + compatible = "ines,ptp-ctrl"; 21 + reg = <0x10000000 0x80>; 22 + }; 23 + 24 + ethernet@20000000 { 25 + mdio { 26 + ethernet-phy@1 { 27 + timestamper = <&tstamper 0>; 28 + }; 29 + }; 30 + }; 31 + 32 + ethernet@30000000 { 33 + mdio { 34 + ethernet-phy@2 { 35 + timestamper = <&tstamper 1>; 36 + }; 37 + }; 38 + }; 39 + 40 + In this example, time stamps from the MII bus attached to phy@1 will 41 + appear on time stamp channel 0 (zero), and those from phy@2 appear on 42 + channel 1.
+1
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
··· 15410 15410 REG_WR(bp, rule, BNX2X_PTP_TX_ON_RULE_MASK); 15411 15411 break; 15412 15412 case HWTSTAMP_TX_ONESTEP_SYNC: 15413 + case HWTSTAMP_TX_ONESTEP_P2P: 15413 15414 BNX2X_ERR("One-step timestamping is not supported\n"); 15414 15415 return -ERANGE; 15415 15416 }
+1
drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
··· 920 920 egr_types = 0xff; 921 921 break; 922 922 case HWTSTAMP_TX_ONESTEP_SYNC: 923 + case HWTSTAMP_TX_ONESTEP_P2P: 923 924 return -ERANGE; 924 925 } 925 926
+3
drivers/net/ethernet/microchip/lan743x_ptp.c
··· 1265 1265 1266 1266 lan743x_ptp_set_sync_ts_insert(adapter, true); 1267 1267 break; 1268 + case HWTSTAMP_TX_ONESTEP_P2P: 1269 + ret = -ERANGE; 1270 + break; 1268 1271 default: 1269 1272 netif_warn(adapter, drv, adapter->netdev, 1270 1273 " tx_type = %d, UNKNOWN\n", config.tx_type);
+1
drivers/net/ethernet/qlogic/qede/qede_ptp.c
··· 247 247 break; 248 248 249 249 case HWTSTAMP_TX_ONESTEP_SYNC: 250 + case HWTSTAMP_TX_ONESTEP_P2P: 250 251 DP_ERR(edev, "One-step timestamping is not supported\n"); 251 252 return -ERANGE; 252 253 }
+3 -5
drivers/net/ethernet/ti/netcp_ethss.c
··· 2533 2533 } 2534 2534 2535 2535 #if IS_ENABLED(CONFIG_TI_CPTS) 2536 - #define HAS_PHY_TXTSTAMP(p) ((p)->drv && (p)->drv->txtstamp) 2537 - #define HAS_PHY_RXTSTAMP(p) ((p)->drv && (p)->drv->rxtstamp) 2538 2536 2539 2537 static void gbe_txtstamp(void *context, struct sk_buff *skb) 2540 2538 { ··· 2564 2566 * We mark it here because skb_tx_timestamp() is called 2565 2567 * after all the txhooks are called. 2566 2568 */ 2567 - if (phydev && HAS_PHY_TXTSTAMP(phydev)) { 2569 + if (phy_has_txtstamp(phydev)) { 2568 2570 skb_shinfo(p_info->skb)->tx_flags |= SKBTX_IN_PROGRESS; 2569 2571 return 0; 2570 2572 } ··· 2586 2588 if (p_info->rxtstamp_complete) 2587 2589 return 0; 2588 2590 2589 - if (phydev && HAS_PHY_RXTSTAMP(phydev)) { 2591 + if (phy_has_rxtstamp(phydev)) { 2590 2592 p_info->rxtstamp_complete = true; 2591 2593 return 0; 2592 2594 } ··· 2828 2830 struct gbe_intf *gbe_intf = intf_priv; 2829 2831 struct phy_device *phy = gbe_intf->slave->phy; 2830 2832 2831 - if (!phy || !phy->drv->hwtstamp) { 2833 + if (!phy_has_hwtstamp(phy)) { 2832 2834 switch (cmd) { 2833 2835 case SIOCGHWTSTAMP: 2834 2836 return gbe_hwtstamp_get(gbe_intf, req);
+2 -2
drivers/net/macvlan.c
··· 1036 1036 const struct ethtool_ops *ops = real_dev->ethtool_ops; 1037 1037 struct phy_device *phydev = real_dev->phydev; 1038 1038 1039 - if (phydev && phydev->drv && phydev->drv->ts_info) { 1040 - return phydev->drv->ts_info(phydev, info); 1039 + if (phy_has_tsinfo(phydev)) { 1040 + return phy_ts_info(phydev, info); 1041 1041 } else if (ops->get_ts_info) { 1042 1042 return ops->get_ts_info(real_dev, info); 1043 1043 } else {
+2
drivers/net/phy/Makefile
··· 43 43 obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o 44 44 obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o 45 45 46 + obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o 47 + 46 48 obj-$(CONFIG_SFP) += sfp.o 47 49 sfp-obj-$(CONFIG_SFP) += sfp-bus.o 48 50 obj-y += $(sfp-obj-y) $(sfp-obj-m)
+113 -104
drivers/net/phy/dp83640.c
··· 98 98 struct list_head list; 99 99 struct dp83640_clock *clock; 100 100 struct phy_device *phydev; 101 + struct mii_timestamper mii_ts; 101 102 struct delayed_work ts_work; 102 103 int hwts_tx_en; 103 104 int hwts_rx_en; ··· 1132 1131 mutex_unlock(&clock->clock_lock); 1133 1132 } 1134 1133 1135 - static int dp83640_probe(struct phy_device *phydev) 1136 - { 1137 - struct dp83640_clock *clock; 1138 - struct dp83640_private *dp83640; 1139 - int err = -ENOMEM, i; 1140 - 1141 - if (phydev->mdio.addr == BROADCAST_ADDR) 1142 - return 0; 1143 - 1144 - clock = dp83640_clock_get_bus(phydev->mdio.bus); 1145 - if (!clock) 1146 - goto no_clock; 1147 - 1148 - dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL); 1149 - if (!dp83640) 1150 - goto no_memory; 1151 - 1152 - dp83640->phydev = phydev; 1153 - INIT_DELAYED_WORK(&dp83640->ts_work, rx_timestamp_work); 1154 - 1155 - INIT_LIST_HEAD(&dp83640->rxts); 1156 - INIT_LIST_HEAD(&dp83640->rxpool); 1157 - for (i = 0; i < MAX_RXTS; i++) 1158 - list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool); 1159 - 1160 - phydev->priv = dp83640; 1161 - 1162 - spin_lock_init(&dp83640->rx_lock); 1163 - skb_queue_head_init(&dp83640->rx_queue); 1164 - skb_queue_head_init(&dp83640->tx_queue); 1165 - 1166 - dp83640->clock = clock; 1167 - 1168 - if (choose_this_phy(clock, phydev)) { 1169 - clock->chosen = dp83640; 1170 - clock->ptp_clock = ptp_clock_register(&clock->caps, 1171 - &phydev->mdio.dev); 1172 - if (IS_ERR(clock->ptp_clock)) { 1173 - err = PTR_ERR(clock->ptp_clock); 1174 - goto no_register; 1175 - } 1176 - } else 1177 - list_add_tail(&dp83640->list, &clock->phylist); 1178 - 1179 - dp83640_clock_put(clock); 1180 - return 0; 1181 - 1182 - no_register: 1183 - clock->chosen = NULL; 1184 - kfree(dp83640); 1185 - no_memory: 1186 - dp83640_clock_put(clock); 1187 - no_clock: 1188 - return err; 1189 - } 1190 - 1191 - static void dp83640_remove(struct phy_device *phydev) 1192 - { 1193 - struct dp83640_clock *clock; 1194 - struct list_head *this, *next; 1195 - struct dp83640_private *tmp, *dp83640 = phydev->priv; 1196 - 1197 - if (phydev->mdio.addr == BROADCAST_ADDR) 1198 - return; 1199 - 1200 - enable_status_frames(phydev, false); 1201 - cancel_delayed_work_sync(&dp83640->ts_work); 1202 - 1203 - skb_queue_purge(&dp83640->rx_queue); 1204 - skb_queue_purge(&dp83640->tx_queue); 1205 - 1206 - clock = dp83640_clock_get(dp83640->clock); 1207 - 1208 - if (dp83640 == clock->chosen) { 1209 - ptp_clock_unregister(clock->ptp_clock); 1210 - clock->chosen = NULL; 1211 - } else { 1212 - list_for_each_safe(this, next, &clock->phylist) { 1213 - tmp = list_entry(this, struct dp83640_private, list); 1214 - if (tmp == dp83640) { 1215 - list_del_init(&tmp->list); 1216 - break; 1217 - } 1218 - } 1219 - } 1220 - 1221 - dp83640_clock_put(clock); 1222 - kfree(dp83640); 1223 - } 1224 - 1225 1134 static int dp83640_soft_reset(struct phy_device *phydev) 1226 1135 { 1227 1136 int ret; ··· 1230 1319 } 1231 1320 } 1232 1321 1233 - static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) 1322 + static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) 1234 1323 { 1235 - struct dp83640_private *dp83640 = phydev->priv; 1324 + struct dp83640_private *dp83640 = 1325 + container_of(mii_ts, struct dp83640_private, mii_ts); 1236 1326 struct hwtstamp_config cfg; 1237 1327 u16 txcfg0, rxcfg0; 1238 1328 ··· 1309 1397 1310 1398 mutex_lock(&dp83640->clock->extreg_lock); 1311 1399 1312 - ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0); 1313 - ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0); 1400 + ext_write(0, dp83640->phydev, PAGE5, PTP_TXCFG0, txcfg0); 1401 + ext_write(0, dp83640->phydev, PAGE5, PTP_RXCFG0, rxcfg0); 1314 1402 1315 1403 mutex_unlock(&dp83640->clock->extreg_lock); 1316 1404 ··· 1340 1428 schedule_delayed_work(&dp83640->ts_work, SKB_TIMESTAMP_TIMEOUT); 1341 1429 } 1342 1430 1343 - static bool dp83640_rxtstamp(struct phy_device *phydev, 1431 + static bool dp83640_rxtstamp(struct mii_timestamper *mii_ts, 1344 1432 struct sk_buff *skb, int type) 1345 1433 { 1346 - struct dp83640_private *dp83640 = phydev->priv; 1434 + struct dp83640_private *dp83640 = 1435 + container_of(mii_ts, struct dp83640_private, mii_ts); 1347 1436 struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb; 1348 1437 struct list_head *this, *next; 1349 1438 struct rxts *rxts; ··· 1390 1477 return true; 1391 1478 } 1392 1479 1393 - static void dp83640_txtstamp(struct phy_device *phydev, 1480 + static void dp83640_txtstamp(struct mii_timestamper *mii_ts, 1394 1481 struct sk_buff *skb, int type) 1395 1482 { 1396 1483 struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb; 1397 - struct dp83640_private *dp83640 = phydev->priv; 1484 + struct dp83640_private *dp83640 = 1485 + container_of(mii_ts, struct dp83640_private, mii_ts); 1398 1486 1399 1487 switch (dp83640->hwts_tx_en) { 1400 1488 ··· 1418 1504 } 1419 1505 } 1420 1506 1421 - static int dp83640_ts_info(struct phy_device *dev, struct ethtool_ts_info *info) 1507 + static int dp83640_ts_info(struct mii_timestamper *mii_ts, 1508 + struct ethtool_ts_info *info) 1422 1509 { 1423 - struct dp83640_private *dp83640 = dev->priv; 1510 + struct dp83640_private *dp83640 = 1511 + container_of(mii_ts, struct dp83640_private, mii_ts); 1424 1512 1425 1513 info->so_timestamping = 1426 1514 SOF_TIMESTAMPING_TX_HARDWARE | ··· 1442 1526 return 0; 1443 1527 } 1444 1528 1529 + static int dp83640_probe(struct phy_device *phydev) 1530 + { 1531 + struct dp83640_clock *clock; 1532 + struct dp83640_private *dp83640; 1533 + int err = -ENOMEM, i; 1534 + 1535 + if (phydev->mdio.addr == BROADCAST_ADDR) 1536 + return 0; 1537 + 1538 + clock = dp83640_clock_get_bus(phydev->mdio.bus); 1539 + if (!clock) 1540 + goto no_clock; 1541 + 1542 + dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL); 1543 + if (!dp83640) 1544 + goto no_memory; 1545 + 1546 + dp83640->phydev = phydev; 1547 + dp83640->mii_ts.rxtstamp = dp83640_rxtstamp; 1548 + dp83640->mii_ts.txtstamp = dp83640_txtstamp; 1549 + dp83640->mii_ts.hwtstamp = dp83640_hwtstamp; 1550 + dp83640->mii_ts.ts_info = dp83640_ts_info; 1551 + 1552 + INIT_DELAYED_WORK(&dp83640->ts_work, rx_timestamp_work); 1553 + INIT_LIST_HEAD(&dp83640->rxts); 1554 + INIT_LIST_HEAD(&dp83640->rxpool); 1555 + for (i = 0; i < MAX_RXTS; i++) 1556 + list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool); 1557 + 1558 + phydev->mii_ts = &dp83640->mii_ts; 1559 + phydev->priv = dp83640; 1560 + 1561 + spin_lock_init(&dp83640->rx_lock); 1562 + skb_queue_head_init(&dp83640->rx_queue); 1563 + skb_queue_head_init(&dp83640->tx_queue); 1564 + 1565 + dp83640->clock = clock; 1566 + 1567 + if (choose_this_phy(clock, phydev)) { 1568 + clock->chosen = dp83640; 1569 + clock->ptp_clock = ptp_clock_register(&clock->caps, 1570 + &phydev->mdio.dev); 1571 + if (IS_ERR(clock->ptp_clock)) { 1572 + err = PTR_ERR(clock->ptp_clock); 1573 + goto no_register; 1574 + } 1575 + } else 1576 + list_add_tail(&dp83640->list, &clock->phylist); 1577 + 1578 + dp83640_clock_put(clock); 1579 + return 0; 1580 + 1581 + no_register: 1582 + clock->chosen = NULL; 1583 + kfree(dp83640); 1584 + no_memory: 1585 + dp83640_clock_put(clock); 1586 + no_clock: 1587 + return err; 1588 + } 1589 + 1590 + static void dp83640_remove(struct phy_device *phydev) 1591 + { 1592 + struct dp83640_clock *clock; 1593 + struct list_head *this, *next; 1594 + struct dp83640_private *tmp, *dp83640 = phydev->priv; 1595 + 1596 + if (phydev->mdio.addr == BROADCAST_ADDR) 1597 + return; 1598 + 1599 + phydev->mii_ts = NULL; 1600 + 1601 + enable_status_frames(phydev, false); 1602 + cancel_delayed_work_sync(&dp83640->ts_work); 1603 + 1604 + skb_queue_purge(&dp83640->rx_queue); 1605 + skb_queue_purge(&dp83640->tx_queue); 1606 + 1607 + clock = dp83640_clock_get(dp83640->clock); 1608 + 1609 + if (dp83640 == clock->chosen) { 1610 + ptp_clock_unregister(clock->ptp_clock); 1611 + clock->chosen = NULL; 1612 + } else { 1613 + list_for_each_safe(this, next, &clock->phylist) { 1614 + tmp = list_entry(this, struct dp83640_private, list); 1615 + if (tmp == dp83640) { 1616 + list_del_init(&tmp->list); 1617 + break; 1618 + } 1619 + } 1620 + } 1621 + 1622 + dp83640_clock_put(clock); 1623 + kfree(dp83640); 1624 + } 1625 + 1445 1626 static struct phy_driver dp83640_driver = { 1446 1627 .phy_id = DP83640_PHY_ID, 1447 1628 .phy_id_mask = 0xfffffff0, ··· 1550 1537 .config_init = dp83640_config_init, 1551 1538 .ack_interrupt = dp83640_ack_interrupt, 1552 1539 .config_intr = dp83640_config_intr, 1553 - .ts_info = dp83640_ts_info, 1554 - .hwtstamp = dp83640_hwtstamp, 1555 - .rxtstamp = dp83640_rxtstamp, 1556 - .txtstamp = dp83640_txtstamp, 1557 1540 }; 1558 1541 1559 1542 static int __init dp83640_init(void)
+125
drivers/net/phy/mii_timestamper.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // Support for generic time stamping devices on MII buses. 4 + // Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com> 5 + // 6 + 7 + #include <linux/mii_timestamper.h> 8 + 9 + static LIST_HEAD(mii_timestamping_devices); 10 + static DEFINE_MUTEX(tstamping_devices_lock); 11 + 12 + struct mii_timestamping_desc { 13 + struct list_head list; 14 + struct mii_timestamping_ctrl *ctrl; 15 + struct device *device; 16 + }; 17 + 18 + /** 19 + * register_mii_tstamp_controller() - registers an MII time stamping device. 20 + * 21 + * @device: The device to be registered. 22 + * @ctrl: Pointer to device's control interface. 23 + * 24 + * Returns zero on success or non-zero on failure. 25 + */ 26 + int register_mii_tstamp_controller(struct device *device, 27 + struct mii_timestamping_ctrl *ctrl) 28 + { 29 + struct mii_timestamping_desc *desc; 30 + 31 + desc = kzalloc(sizeof(*desc), GFP_KERNEL); 32 + if (!desc) 33 + return -ENOMEM; 34 + 35 + INIT_LIST_HEAD(&desc->list); 36 + desc->ctrl = ctrl; 37 + desc->device = device; 38 + 39 + mutex_lock(&tstamping_devices_lock); 40 + list_add_tail(&mii_timestamping_devices, &desc->list); 41 + mutex_unlock(&tstamping_devices_lock); 42 + 43 + return 0; 44 + } 45 + EXPORT_SYMBOL(register_mii_tstamp_controller); 46 + 47 + /** 48 + * unregister_mii_tstamp_controller() - unregisters an MII time stamping device. 49 + * 50 + * @device: A device previously passed to register_mii_tstamp_controller(). 51 + */ 52 + void unregister_mii_tstamp_controller(struct device *device) 53 + { 54 + struct mii_timestamping_desc *desc; 55 + struct list_head *this, *next; 56 + 57 + mutex_lock(&tstamping_devices_lock); 58 + list_for_each_safe(this, next, &mii_timestamping_devices) { 59 + desc = list_entry(this, struct mii_timestamping_desc, list); 60 + if (desc->device == device) { 61 + list_del_init(&desc->list); 62 + kfree(desc); 63 + break; 64 + } 65 + } 66 + mutex_unlock(&tstamping_devices_lock); 67 + } 68 + EXPORT_SYMBOL(unregister_mii_tstamp_controller); 69 + 70 + /** 71 + * register_mii_timestamper - Enables a given port of an MII time stamper. 72 + * 73 + * @node: The device tree node of the MII time stamp controller. 74 + * @port: The index of the port to be enabled. 75 + * 76 + * Returns a valid interface on success or ERR_PTR otherwise. 77 + */ 78 + struct mii_timestamper *register_mii_timestamper(struct device_node *node, 79 + unsigned int port) 80 + { 81 + struct mii_timestamper *mii_ts = NULL; 82 + struct mii_timestamping_desc *desc; 83 + struct list_head *this; 84 + 85 + mutex_lock(&tstamping_devices_lock); 86 + list_for_each(this, &mii_timestamping_devices) { 87 + desc = list_entry(this, struct mii_timestamping_desc, list); 88 + if (desc->device->of_node == node) { 89 + mii_ts = desc->ctrl->probe_channel(desc->device, port); 90 + if (!IS_ERR(mii_ts)) { 91 + mii_ts->device = desc->device; 92 + get_device(desc->device); 93 + } 94 + break; 95 + } 96 + } 97 + mutex_unlock(&tstamping_devices_lock); 98 + 99 + return mii_ts ? mii_ts : ERR_PTR(-EPROBE_DEFER); 100 + } 101 + EXPORT_SYMBOL(register_mii_timestamper); 102 + 103 + /** 104 + * unregister_mii_timestamper - Disables a given MII time stamper. 105 + * 106 + * @mii_ts: An interface obtained via register_mii_timestamper(). 107 + * 108 + */ 109 + void unregister_mii_timestamper(struct mii_timestamper *mii_ts) 110 + { 111 + struct mii_timestamping_desc *desc; 112 + struct list_head *this; 113 + 114 + mutex_lock(&tstamping_devices_lock); 115 + list_for_each(this, &mii_timestamping_devices) { 116 + desc = list_entry(this, struct mii_timestamping_desc, list); 117 + if (desc->device == mii_ts->device) { 118 + desc->ctrl->release_channel(desc->device, mii_ts); 119 + put_device(desc->device); 120 + break; 121 + } 122 + } 123 + mutex_unlock(&tstamping_devices_lock); 124 + } 125 + EXPORT_SYMBOL(unregister_mii_timestamper);
+2 -2
drivers/net/phy/phy.c
··· 422 422 return 0; 423 423 424 424 case SIOCSHWTSTAMP: 425 - if (phydev->drv && phydev->drv->hwtstamp) 426 - return phydev->drv->hwtstamp(phydev, ifr); 425 + if (phydev->mii_ts && phydev->mii_ts->hwtstamp) 426 + return phydev->mii_ts->hwtstamp(phydev->mii_ts, ifr); 427 427 /* fall through */ 428 428 429 429 default:
+5
drivers/net/phy/phy_device.c
··· 881 881 */ 882 882 void phy_device_remove(struct phy_device *phydev) 883 883 { 884 + if (phydev->mii_ts) 885 + unregister_mii_timestamper(phydev->mii_ts); 886 + 884 887 device_del(&phydev->mdio.dev); 885 888 886 889 /* Assert the reset signal */ ··· 922 919 netif_carrier_off(netdev); 923 920 } 924 921 phydev->adjust_link(netdev); 922 + if (phydev->mii_ts && phydev->mii_ts->link_state) 923 + phydev->mii_ts->link_state(phydev->mii_ts, phydev); 925 924 } 926 925 927 926 /**
+29 -1
drivers/of/of_mdio.c
··· 42 42 return -EINVAL; 43 43 } 44 44 45 + static struct mii_timestamper *of_find_mii_timestamper(struct device_node *node) 46 + { 47 + struct of_phandle_args arg; 48 + int err; 49 + 50 + err = of_parse_phandle_with_fixed_args(node, "timestamper", 1, 0, &arg); 51 + 52 + if (err == -ENOENT) 53 + return NULL; 54 + else if (err) 55 + return ERR_PTR(err); 56 + 57 + if (arg.args_count != 1) 58 + return ERR_PTR(-EINVAL); 59 + 60 + return register_mii_timestamper(arg.np, arg.args[0]); 61 + } 62 + 45 63 static int of_mdiobus_register_phy(struct mii_bus *mdio, 46 64 struct device_node *child, u32 addr) 47 65 { 66 + struct mii_timestamper *mii_ts; 48 67 struct phy_device *phy; 49 68 bool is_c45; 50 69 int rc; 51 70 u32 phy_id; 71 + 72 + mii_ts = of_find_mii_timestamper(child); 73 + if (IS_ERR(mii_ts)) 74 + return PTR_ERR(mii_ts); 52 75 53 76 is_c45 = of_device_is_compatible(child, 54 77 "ethernet-phy-ieee802.3-c45"); ··· 80 57 phy = phy_device_create(mdio, addr, phy_id, 0, NULL); 81 58 else 82 59 phy = get_phy_device(mdio, addr, is_c45); 83 - if (IS_ERR(phy)) 60 + if (IS_ERR(phy)) { 61 + unregister_mii_timestamper(mii_ts); 84 62 return PTR_ERR(phy); 63 + } 85 64 86 65 rc = of_irq_get(child, 0); 87 66 if (rc == -EPROBE_DEFER) { 67 + unregister_mii_timestamper(mii_ts); 88 68 phy_device_free(phy); 89 69 return rc; 90 70 } ··· 116 90 * register it */ 117 91 rc = phy_device_register(phy); 118 92 if (rc) { 93 + unregister_mii_timestamper(mii_ts); 119 94 phy_device_free(phy); 120 95 of_node_put(child); 121 96 return rc; 122 97 } 98 + phy->mii_ts = mii_ts; 123 99 124 100 dev_dbg(&mdio->dev, "registered phy %pOFn at address %i\n", 125 101 child, addr);
+10
drivers/ptp/Kconfig
··· 89 89 In order for this to work, your MAC driver must also 90 90 implement the skb_tx_timestamp() function. 91 91 92 + config PTP_1588_CLOCK_INES 93 + tristate "ZHAW InES PTP time stamping IP core" 94 + depends on NETWORK_PHY_TIMESTAMPING 95 + depends on PHYLIB 96 + depends on PTP_1588_CLOCK 97 + help 98 + This driver adds support for using the ZHAW InES 1588 IP 99 + core. This clock is only useful if the MII bus of your MAC 100 + is wired up to the core. 101 + 92 102 config PTP_1588_CLOCK_PCH 93 103 tristate "Intel PCH EG20T as PTP clock" 94 104 depends on X86_32 || COMPILE_TEST
+1
drivers/ptp/Makefile
··· 6 6 ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o 7 7 obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o 8 8 obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o 9 + obj-$(CONFIG_PTP_1588_CLOCK_INES) += ptp_ines.o 9 10 obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o 10 11 obj-$(CONFIG_PTP_1588_CLOCK_PCH) += ptp_pch.o 11 12 obj-$(CONFIG_PTP_1588_CLOCK_KVM) += ptp_kvm.o
+852
drivers/ptp/ptp_ines.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // Copyright (C) 2018 MOSER-BAER AG 4 + // 5 + 6 + #define pr_fmt(fmt) "InES_PTP: " fmt 7 + 8 + #include <linux/ethtool.h> 9 + #include <linux/export.h> 10 + #include <linux/if_vlan.h> 11 + #include <linux/mii_timestamper.h> 12 + #include <linux/module.h> 13 + #include <linux/net_tstamp.h> 14 + #include <linux/of.h> 15 + #include <linux/of_address.h> 16 + #include <linux/of_irq.h> 17 + #include <linux/phy.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/ptp_classify.h> 20 + #include <linux/ptp_clock_kernel.h> 21 + #include <linux/stddef.h> 22 + 23 + MODULE_DESCRIPTION("Driver for the ZHAW InES PTP time stamping IP core"); 24 + MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>"); 25 + MODULE_VERSION("1.0"); 26 + MODULE_LICENSE("GPL"); 27 + 28 + /* GLOBAL register */ 29 + #define MCAST_MAC_SELECT_SHIFT 2 30 + #define MCAST_MAC_SELECT_MASK 0x3 31 + #define IO_RESET BIT(1) 32 + #define PTP_RESET BIT(0) 33 + 34 + /* VERSION register */ 35 + #define IF_MAJOR_VER_SHIFT 12 36 + #define IF_MAJOR_VER_MASK 0xf 37 + #define IF_MINOR_VER_SHIFT 8 38 + #define IF_MINOR_VER_MASK 0xf 39 + #define FPGA_MAJOR_VER_SHIFT 4 40 + #define FPGA_MAJOR_VER_MASK 0xf 41 + #define FPGA_MINOR_VER_SHIFT 0 42 + #define FPGA_MINOR_VER_MASK 0xf 43 + 44 + /* INT_STAT register */ 45 + #define RX_INTR_STATUS_3 BIT(5) 46 + #define RX_INTR_STATUS_2 BIT(4) 47 + #define RX_INTR_STATUS_1 BIT(3) 48 + #define TX_INTR_STATUS_3 BIT(2) 49 + #define TX_INTR_STATUS_2 BIT(1) 50 + #define TX_INTR_STATUS_1 BIT(0) 51 + 52 + /* INT_MSK register */ 53 + #define RX_INTR_MASK_3 BIT(5) 54 + #define RX_INTR_MASK_2 BIT(4) 55 + #define RX_INTR_MASK_1 BIT(3) 56 + #define TX_INTR_MASK_3 BIT(2) 57 + #define TX_INTR_MASK_2 BIT(1) 58 + #define TX_INTR_MASK_1 BIT(0) 59 + 60 + /* BUF_STAT register */ 61 + #define RX_FIFO_NE_3 BIT(5) 62 + #define RX_FIFO_NE_2 BIT(4) 63 + #define RX_FIFO_NE_1 BIT(3) 64 + #define TX_FIFO_NE_3 BIT(2) 65 + #define TX_FIFO_NE_2 BIT(1) 66 + #define TX_FIFO_NE_1 BIT(0) 67 + 68 + /* PORT_CONF register */ 69 + #define CM_ONE_STEP BIT(6) 70 + #define PHY_SPEED_SHIFT 4 71 + #define PHY_SPEED_MASK 0x3 72 + #define P2P_DELAY_WR_POS_SHIFT 2 73 + #define P2P_DELAY_WR_POS_MASK 0x3 74 + #define PTP_MODE_SHIFT 0 75 + #define PTP_MODE_MASK 0x3 76 + 77 + /* TS_STAT_TX register */ 78 + #define TS_ENABLE BIT(15) 79 + #define DATA_READ_POS_SHIFT 8 80 + #define DATA_READ_POS_MASK 0x1f 81 + #define DISCARDED_EVENTS_SHIFT 4 82 + #define DISCARDED_EVENTS_MASK 0xf 83 + 84 + #define INES_N_PORTS 3 85 + #define INES_REGISTER_SIZE 0x80 86 + #define INES_PORT_OFFSET 0x20 87 + #define INES_PORT_SIZE 0x20 88 + #define INES_FIFO_DEPTH 90 89 + #define INES_MAX_EVENTS 100 90 + 91 + #define BC_PTP_V1 0 92 + #define BC_PTP_V2 1 93 + #define TC_E2E_PTP_V2 2 94 + #define TC_P2P_PTP_V2 3 95 + 96 + #define OFF_PTP_CLOCK_ID 20 97 + #define OFF_PTP_PORT_NUM 28 98 + 99 + #define PHY_SPEED_10 0 100 + #define PHY_SPEED_100 1 101 + #define PHY_SPEED_1000 2 102 + 103 + #define PORT_CONF \ 104 + ((PHY_SPEED_1000 << PHY_SPEED_SHIFT) | (BC_PTP_V2 << PTP_MODE_SHIFT)) 105 + 106 + #define ines_read32(s, r) __raw_readl((void __iomem *)&s->regs->r) 107 + #define ines_write32(s, v, r) __raw_writel(v, (void __iomem *)&s->regs->r) 108 + 109 + #define MESSAGE_TYPE_SYNC 1 110 + #define MESSAGE_TYPE_P_DELAY_REQ 2 111 + #define MESSAGE_TYPE_P_DELAY_RESP 3 112 + #define MESSAGE_TYPE_DELAY_REQ 4 113 + 114 + #define SYNC 0x0 115 + #define DELAY_REQ 0x1 116 + #define PDELAY_REQ 0x2 117 + #define PDELAY_RESP 0x3 118 + 119 + static LIST_HEAD(ines_clocks); 120 + static DEFINE_MUTEX(ines_clocks_lock); 121 + 122 + struct ines_global_regs { 123 + u32 id; 124 + u32 test; 125 + u32 global; 126 + u32 version; 127 + u32 test2; 128 + u32 int_stat; 129 + u32 int_msk; 130 + u32 buf_stat; 131 + }; 132 + 133 + struct ines_port_registers { 134 + u32 port_conf; 135 + u32 p_delay; 136 + u32 ts_stat_tx; 137 + u32 ts_stat_rx; 138 + u32 ts_tx; 139 + u32 ts_rx; 140 + }; 141 + 142 + struct ines_timestamp { 143 + struct list_head list; 144 + unsigned long tmo; 145 + u16 tag; 146 + u64 sec; 147 + u64 nsec; 148 + u64 clkid; 149 + u16 portnum; 150 + u16 seqid; 151 + }; 152 + 153 + struct ines_port { 154 + struct ines_port_registers *regs; 155 + struct mii_timestamper mii_ts; 156 + struct ines_clock *clock; 157 + bool rxts_enabled; 158 + bool txts_enabled; 159 + unsigned int index; 160 + struct delayed_work ts_work; 161 + /* lock protects event list and tx_skb */ 162 + spinlock_t lock; 163 + struct sk_buff *tx_skb; 164 + struct list_head events; 165 + struct list_head pool; 166 + struct ines_timestamp pool_data[INES_MAX_EVENTS]; 167 + }; 168 + 169 + struct ines_clock { 170 + struct ines_port port[INES_N_PORTS]; 171 + struct ines_global_regs __iomem *regs; 172 + void __iomem *base; 173 + struct device_node *node; 174 + struct device *dev; 175 + struct list_head list; 176 + }; 177 + 178 + static bool ines_match(struct sk_buff *skb, unsigned int ptp_class, 179 + struct ines_timestamp *ts, struct device *dev); 180 + static int ines_rxfifo_read(struct ines_port *port); 181 + static u64 ines_rxts64(struct ines_port *port, unsigned int words); 182 + static bool ines_timestamp_expired(struct ines_timestamp *ts); 183 + static u64 ines_txts64(struct ines_port *port, unsigned int words); 184 + static void ines_txtstamp_work(struct work_struct *work); 185 + static bool is_sync_pdelay_resp(struct sk_buff *skb, int type); 186 + static u8 tag_to_msgtype(u8 tag); 187 + 188 + static void ines_clock_cleanup(struct ines_clock *clock) 189 + { 190 + struct ines_port *port; 191 + int i; 192 + 193 + for (i = 0; i < INES_N_PORTS; i++) { 194 + port = &clock->port[i]; 195 + cancel_delayed_work_sync(&port->ts_work); 196 + } 197 + } 198 + 199 + static int ines_clock_init(struct ines_clock *clock, struct device *device, 200 + void __iomem *addr) 201 + { 202 + struct device_node *node = device->of_node; 203 + unsigned long port_addr; 204 + struct ines_port *port; 205 + int i, j; 206 + 207 + INIT_LIST_HEAD(&clock->list); 208 + clock->node = node; 209 + clock->dev = device; 210 + clock->base = addr; 211 + clock->regs = clock->base; 212 + 213 + for (i = 0; i < INES_N_PORTS; i++) { 214 + port = &clock->port[i]; 215 + port_addr = (unsigned long) clock->base + 216 + INES_PORT_OFFSET + i * INES_PORT_SIZE; 217 + port->regs = (struct ines_port_registers *) port_addr; 218 + port->clock = clock; 219 + port->index = i; 220 + INIT_DELAYED_WORK(&port->ts_work, ines_txtstamp_work); 221 + spin_lock_init(&port->lock); 222 + INIT_LIST_HEAD(&port->events); 223 + INIT_LIST_HEAD(&port->pool); 224 + for (j = 0; j < INES_MAX_EVENTS; j++) 225 + list_add(&port->pool_data[j].list, &port->pool); 226 + } 227 + 228 + ines_write32(clock, 0xBEEF, test); 229 + ines_write32(clock, 0xBEEF, test2); 230 + 231 + dev_dbg(device, "ID 0x%x\n", ines_read32(clock, id)); 232 + dev_dbg(device, "TEST 0x%x\n", ines_read32(clock, test)); 233 + dev_dbg(device, "VERSION 0x%x\n", ines_read32(clock, version)); 234 + dev_dbg(device, "TEST2 0x%x\n", ines_read32(clock, test2)); 235 + 236 + for (i = 0; i < INES_N_PORTS; i++) { 237 + port = &clock->port[i]; 238 + ines_write32(port, PORT_CONF, port_conf); 239 + } 240 + 241 + return 0; 242 + } 243 + 244 + static struct ines_port *ines_find_port(struct device_node *node, u32 index) 245 + { 246 + struct ines_port *port = NULL; 247 + struct ines_clock *clock; 248 + struct list_head *this; 249 + 250 + mutex_lock(&ines_clocks_lock); 251 + list_for_each(this, &ines_clocks) { 252 + clock = list_entry(this, struct ines_clock, list); 253 + if (clock->node == node) { 254 + port = &clock->port[index]; 255 + break; 256 + } 257 + } 258 + mutex_unlock(&ines_clocks_lock); 259 + return port; 260 + } 261 + 262 + static u64 ines_find_rxts(struct ines_port *port, struct sk_buff *skb, int type) 263 + { 264 + struct list_head *this, *next; 265 + struct ines_timestamp *ts; 266 + unsigned long flags; 267 + u64 ns = 0; 268 + 269 + if (type == PTP_CLASS_NONE) 270 + return 0; 271 + 272 + spin_lock_irqsave(&port->lock, flags); 273 + ines_rxfifo_read(port); 274 + list_for_each_safe(this, next, &port->events) { 275 + ts = list_entry(this, struct ines_timestamp, list); 276 + if (ines_timestamp_expired(ts)) { 277 + list_del_init(&ts->list); 278 + list_add(&ts->list, &port->pool); 279 + continue; 280 + } 281 + if (ines_match(skb, type, ts, port->clock->dev)) { 282 + ns = ts->sec * 1000000000ULL + ts->nsec; 283 + list_del_init(&ts->list); 284 + list_add(&ts->list, &port->pool); 285 + break; 286 + } 287 + } 288 + spin_unlock_irqrestore(&port->lock, flags); 289 + 290 + return ns; 291 + } 292 + 293 + static u64 ines_find_txts(struct ines_port *port, struct sk_buff *skb) 294 + { 295 + unsigned int class = ptp_classify_raw(skb), i; 296 + u32 data_rd_pos, buf_stat, mask, ts_stat_tx; 297 + struct ines_timestamp ts; 298 + unsigned long flags; 299 + u64 ns = 0; 300 + 301 + mask = TX_FIFO_NE_1 << port->index; 302 + 303 + spin_lock_irqsave(&port->lock, flags); 304 + 305 + for (i = 0; i < INES_FIFO_DEPTH; i++) { 306 + 307 + buf_stat = ines_read32(port->clock, buf_stat); 308 + if (!(buf_stat & mask)) { 309 + dev_dbg(port->clock->dev, 310 + "Tx timestamp FIFO unexpectedly empty\n"); 311 + break; 312 + } 313 + ts_stat_tx = ines_read32(port, ts_stat_tx); 314 + data_rd_pos = (ts_stat_tx >> DATA_READ_POS_SHIFT) & 315 + DATA_READ_POS_MASK; 316 + if (data_rd_pos) { 317 + dev_err(port->clock->dev, 318 + "unexpected Tx read pos %u\n", data_rd_pos); 319 + break; 320 + } 321 + 322 + ts.tag = ines_read32(port, ts_tx); 323 + ts.sec = ines_txts64(port, 3); 324 + ts.nsec = ines_txts64(port, 2); 325 + ts.clkid = ines_txts64(port, 4); 326 + ts.portnum = ines_read32(port, ts_tx); 327 + ts.seqid = ines_read32(port, ts_tx); 328 + 329 + if (ines_match(skb, class, &ts, port->clock->dev)) { 330 + ns = ts.sec * 1000000000ULL + ts.nsec; 331 + break; 332 + } 333 + } 334 + 335 + spin_unlock_irqrestore(&port->lock, flags); 336 + return ns; 337 + } 338 + 339 + static int ines_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) 340 + { 341 + struct ines_port *port = container_of(mii_ts, struct ines_port, mii_ts); 342 + u32 cm_one_step = 0, port_conf, ts_stat_rx, ts_stat_tx; 343 + struct hwtstamp_config cfg; 344 + unsigned long flags; 345 + 346 + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 347 + return -EFAULT; 348 + 349 + /* reserved for future extensions */ 350 + if (cfg.flags) 351 + return -EINVAL; 352 + 353 + switch (cfg.tx_type) { 354 + case HWTSTAMP_TX_OFF: 355 + ts_stat_tx = 0; 356 + break; 357 + case HWTSTAMP_TX_ON: 358 + ts_stat_tx = TS_ENABLE; 359 + break; 360 + case HWTSTAMP_TX_ONESTEP_P2P: 361 + ts_stat_tx = TS_ENABLE; 362 + cm_one_step = CM_ONE_STEP; 363 + break; 364 + default: 365 + return -ERANGE; 366 + } 367 + 368 + switch (cfg.rx_filter) { 369 + case HWTSTAMP_FILTER_NONE: 370 + ts_stat_rx = 0; 371 + break; 372 + case HWTSTAMP_FILTER_ALL: 373 + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 374 + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 375 + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 376 + return -ERANGE; 377 + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 378 + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 379 + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 380 + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 381 + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 382 + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 383 + case HWTSTAMP_FILTER_PTP_V2_EVENT: 384 + case HWTSTAMP_FILTER_PTP_V2_SYNC: 385 + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 386 + ts_stat_rx = TS_ENABLE; 387 + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; 388 + break; 389 + default: 390 + return -ERANGE; 391 + } 392 + 393 + spin_lock_irqsave(&port->lock, flags); 394 + 395 + port_conf = ines_read32(port, port_conf); 396 + port_conf &= ~CM_ONE_STEP; 397 + port_conf |= cm_one_step; 398 + 399 + ines_write32(port, port_conf, port_conf); 400 + ines_write32(port, ts_stat_rx, ts_stat_rx); 401 + ines_write32(port, ts_stat_tx, ts_stat_tx); 402 + 403 + port->rxts_enabled = ts_stat_rx == TS_ENABLE ? true : false; 404 + port->txts_enabled = ts_stat_tx == TS_ENABLE ? true : false; 405 + 406 + spin_unlock_irqrestore(&port->lock, flags); 407 + 408 + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; 409 + } 410 + 411 + static void ines_link_state(struct mii_timestamper *mii_ts, 412 + struct phy_device *phydev) 413 + { 414 + struct ines_port *port = container_of(mii_ts, struct ines_port, mii_ts); 415 + u32 port_conf, speed_conf; 416 + unsigned long flags; 417 + 418 + switch (phydev->speed) { 419 + case SPEED_10: 420 + speed_conf = PHY_SPEED_10 << PHY_SPEED_SHIFT; 421 + break; 422 + case SPEED_100: 423 + speed_conf = PHY_SPEED_100 << PHY_SPEED_SHIFT; 424 + break; 425 + case SPEED_1000: 426 + speed_conf = PHY_SPEED_1000 << PHY_SPEED_SHIFT; 427 + break; 428 + default: 429 + dev_err(port->clock->dev, "bad speed: %d\n", phydev->speed); 430 + return; 431 + } 432 + spin_lock_irqsave(&port->lock, flags); 433 + 434 + port_conf = ines_read32(port, port_conf); 435 + port_conf &= ~(0x3 << PHY_SPEED_SHIFT); 436 + port_conf |= speed_conf; 437 + 438 + ines_write32(port, port_conf, port_conf); 439 + 440 + spin_unlock_irqrestore(&port->lock, flags); 441 + } 442 + 443 + static bool ines_match(struct sk_buff *skb, unsigned int ptp_class, 444 + struct ines_timestamp *ts, struct device *dev) 445 + { 446 + u8 *msgtype, *data = skb_mac_header(skb); 447 + unsigned int offset = 0; 448 + __be16 *portn, *seqid; 449 + __be64 *clkid; 450 + 451 + if (unlikely(ptp_class & PTP_CLASS_V1)) 452 + return false; 453 + 454 + if (ptp_class & PTP_CLASS_VLAN) 455 + offset += VLAN_HLEN; 456 + 457 + switch (ptp_class & PTP_CLASS_PMASK) { 458 + case PTP_CLASS_IPV4: 459 + offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; 460 + break; 461 + case PTP_CLASS_IPV6: 462 + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; 463 + break; 464 + case PTP_CLASS_L2: 465 + offset += ETH_HLEN; 466 + break; 467 + default: 468 + return false; 469 + } 470 + 471 + if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) 472 + return false; 473 + 474 + msgtype = data + offset; 475 + clkid = (__be64 *)(data + offset + OFF_PTP_CLOCK_ID); 476 + portn = (__be16 *)(data + offset + OFF_PTP_PORT_NUM); 477 + seqid = (__be16 *)(data + offset + OFF_PTP_SEQUENCE_ID); 478 + 479 + if (tag_to_msgtype(ts->tag & 0x7) != (*msgtype & 0xf)) { 480 + dev_dbg(dev, "msgtype mismatch ts %hhu != skb %hhu\n", 481 + tag_to_msgtype(ts->tag & 0x7), *msgtype & 0xf); 482 + return false; 483 + } 484 + if (cpu_to_be64(ts->clkid) != *clkid) { 485 + dev_dbg(dev, "clkid mismatch ts %llx != skb %llx\n", 486 + cpu_to_be64(ts->clkid), *clkid); 487 + return false; 488 + } 489 + if (ts->portnum != ntohs(*portn)) { 490 + dev_dbg(dev, "portn mismatch ts %hu != skb %hu\n", 491 + ts->portnum, ntohs(*portn)); 492 + return false; 493 + } 494 + if (ts->seqid != ntohs(*seqid)) { 495 + dev_dbg(dev, "seqid mismatch ts %hu != skb %hu\n", 496 + ts->seqid, ntohs(*seqid)); 497 + return false; 498 + } 499 + 500 + return true; 501 + } 502 + 503 + static bool ines_rxtstamp(struct mii_timestamper *mii_ts, 504 + struct sk_buff *skb, int type) 505 + { 506 + struct ines_port *port = container_of(mii_ts, struct ines_port, mii_ts); 507 + struct skb_shared_hwtstamps *ssh; 508 + u64 ns; 509 + 510 + if (!port->rxts_enabled) 511 + return false; 512 + 513 + ns = ines_find_rxts(port, skb, type); 514 + if (!ns) 515 + return false; 516 + 517 + ssh = skb_hwtstamps(skb); 518 + ssh->hwtstamp = ns_to_ktime(ns); 519 + netif_rx(skb); 520 + 521 + return true; 522 + } 523 + 524 + static int ines_rxfifo_read(struct ines_port *port) 525 + { 526 + u32 data_rd_pos, buf_stat, mask, ts_stat_rx; 527 + struct ines_timestamp *ts; 528 + unsigned int i; 529 + 530 + mask = RX_FIFO_NE_1 << port->index; 531 + 532 + for (i = 0; i < INES_FIFO_DEPTH; i++) { 533 + if (list_empty(&port->pool)) { 534 + dev_err(port->clock->dev, "event pool is empty\n"); 535 + return -1; 536 + } 537 + buf_stat = ines_read32(port->clock, buf_stat); 538 + if (!(buf_stat & mask)) 539 + break; 540 + 541 + ts_stat_rx = ines_read32(port, ts_stat_rx); 542 + data_rd_pos = (ts_stat_rx >> DATA_READ_POS_SHIFT) & 543 + DATA_READ_POS_MASK; 544 + if (data_rd_pos) { 545 + dev_err(port->clock->dev, "unexpected Rx read pos %u\n", 546 + data_rd_pos); 547 + break; 548 + } 549 + 550 + ts = list_first_entry(&port->pool, struct ines_timestamp, list); 551 + ts->tmo = jiffies + HZ; 552 + ts->tag = ines_read32(port, ts_rx); 553 + ts->sec = ines_rxts64(port, 3); 554 + ts->nsec = ines_rxts64(port, 2); 555 + ts->clkid = ines_rxts64(port, 4); 556 + ts->portnum = ines_read32(port, ts_rx); 557 + ts->seqid = ines_read32(port, ts_rx); 558 + 559 + list_del_init(&ts->list); 560 + list_add_tail(&ts->list, &port->events); 561 + } 562 + 563 + return 0; 564 + } 565 + 566 + static u64 ines_rxts64(struct ines_port *port, unsigned int words) 567 + { 568 + unsigned int i; 569 + u64 result; 570 + u16 word; 571 + 572 + word = ines_read32(port, ts_rx); 573 + result = word; 574 + words--; 575 + for (i = 0; i < words; i++) { 576 + word = ines_read32(port, ts_rx); 577 + result <<= 16; 578 + result |= word; 579 + } 580 + return result; 581 + } 582 + 583 + static bool ines_timestamp_expired(struct ines_timestamp *ts) 584 + { 585 + return time_after(jiffies, ts->tmo); 586 + } 587 + 588 + static int ines_ts_info(struct mii_timestamper *mii_ts, 589 + struct ethtool_ts_info *info) 590 + { 591 + info->so_timestamping = 592 + SOF_TIMESTAMPING_TX_HARDWARE | 593 + SOF_TIMESTAMPING_TX_SOFTWARE | 594 + SOF_TIMESTAMPING_RX_HARDWARE | 595 + SOF_TIMESTAMPING_RX_SOFTWARE | 596 + SOF_TIMESTAMPING_SOFTWARE | 597 + SOF_TIMESTAMPING_RAW_HARDWARE; 598 + 599 + info->phc_index = -1; 600 + 601 + info->tx_types = 602 + (1 << HWTSTAMP_TX_OFF) | 603 + (1 << HWTSTAMP_TX_ON) | 604 + (1 << HWTSTAMP_TX_ONESTEP_P2P); 605 + 606 + info->rx_filters = 607 + (1 << HWTSTAMP_FILTER_NONE) | 608 + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); 609 + 610 + return 0; 611 + } 612 + 613 + static u64 ines_txts64(struct ines_port *port, unsigned int words) 614 + { 615 + unsigned int i; 616 + u64 result; 617 + u16 word; 618 + 619 + word = ines_read32(port, ts_tx); 620 + result = word; 621 + words--; 622 + for (i = 0; i < words; i++) { 623 + word = ines_read32(port, ts_tx); 624 + result <<= 16; 625 + result |= word; 626 + } 627 + return result; 628 + } 629 + 630 + static bool ines_txts_onestep(struct ines_port *port, struct sk_buff *skb, int type) 631 + { 632 + unsigned long flags; 633 + u32 port_conf; 634 + 635 + spin_lock_irqsave(&port->lock, flags); 636 + port_conf = ines_read32(port, port_conf); 637 + spin_unlock_irqrestore(&port->lock, flags); 638 + 639 + if (port_conf & CM_ONE_STEP) 640 + return is_sync_pdelay_resp(skb, type); 641 + 642 + return false; 643 + } 644 + 645 + static void ines_txtstamp(struct mii_timestamper *mii_ts, 646 + struct sk_buff *skb, int type) 647 + { 648 + struct ines_port *port = container_of(mii_ts, struct ines_port, mii_ts); 649 + struct sk_buff *old_skb = NULL; 650 + unsigned long flags; 651 + 652 + if (!port->txts_enabled || ines_txts_onestep(port, skb, type)) { 653 + kfree_skb(skb); 654 + return; 655 + } 656 + 657 + spin_lock_irqsave(&port->lock, flags); 658 + 659 + if (port->tx_skb) 660 + old_skb = port->tx_skb; 661 + 662 + port->tx_skb = skb; 663 + 664 + spin_unlock_irqrestore(&port->lock, flags); 665 + 666 + if (old_skb) 667 + kfree_skb(old_skb); 668 + 669 + schedule_delayed_work(&port->ts_work, 1); 670 + } 671 + 672 + static void ines_txtstamp_work(struct work_struct *work) 673 + { 674 + struct ines_port *port = 675 + container_of(work, struct ines_port, ts_work.work); 676 + struct skb_shared_hwtstamps ssh; 677 + struct sk_buff *skb; 678 + unsigned long flags; 679 + u64 ns; 680 + 681 + spin_lock_irqsave(&port->lock, flags); 682 + skb = port->tx_skb; 683 + port->tx_skb = NULL; 684 + spin_unlock_irqrestore(&port->lock, flags); 685 + 686 + ns = ines_find_txts(port, skb); 687 + if (!ns) { 688 + kfree_skb(skb); 689 + return; 690 + } 691 + ssh.hwtstamp = ns_to_ktime(ns); 692 + skb_complete_tx_timestamp(skb, &ssh); 693 + } 694 + 695 + static bool is_sync_pdelay_resp(struct sk_buff *skb, int type) 696 + { 697 + u8 *data = skb->data, *msgtype; 698 + unsigned int offset = 0; 699 + 700 + if (type & PTP_CLASS_VLAN) 701 + offset += VLAN_HLEN; 702 + 703 + switch (type & PTP_CLASS_PMASK) { 704 + case PTP_CLASS_IPV4: 705 + offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN; 706 + break; 707 + case PTP_CLASS_IPV6: 708 + offset += ETH_HLEN + IP6_HLEN + UDP_HLEN; 709 + break; 710 + case PTP_CLASS_L2: 711 + offset += ETH_HLEN; 712 + break; 713 + default: 714 + return 0; 715 + } 716 + 717 + if (type & PTP_CLASS_V1) 718 + offset += OFF_PTP_CONTROL; 719 + 720 + if (skb->len < offset + 1) 721 + return 0; 722 + 723 + msgtype = data + offset; 724 + 725 + switch ((*msgtype & 0xf)) { 726 + case SYNC: 727 + case PDELAY_RESP: 728 + return true; 729 + default: 730 + return false; 731 + } 732 + } 733 + 734 + static u8 tag_to_msgtype(u8 tag) 735 + { 736 + switch (tag) { 737 + case MESSAGE_TYPE_SYNC: 738 + return SYNC; 739 + case MESSAGE_TYPE_P_DELAY_REQ: 740 + return PDELAY_REQ; 741 + case MESSAGE_TYPE_P_DELAY_RESP: 742 + return PDELAY_RESP; 743 + case MESSAGE_TYPE_DELAY_REQ: 744 + return DELAY_REQ; 745 + } 746 + return 0xf; 747 + } 748 + 749 + static struct mii_timestamper *ines_ptp_probe_channel(struct device *device, 750 + unsigned int index) 751 + { 752 + struct device_node *node = device->of_node; 753 + struct ines_port *port; 754 + 755 + if (index > INES_N_PORTS - 1) { 756 + dev_err(device, "bad port index %u\n", index); 757 + return ERR_PTR(-EINVAL); 758 + } 759 + port = ines_find_port(node, index); 760 + if (!port) { 761 + dev_err(device, "missing port index %u\n", index); 762 + return ERR_PTR(-ENODEV); 763 + } 764 + port->mii_ts.rxtstamp = ines_rxtstamp; 765 + port->mii_ts.txtstamp = ines_txtstamp; 766 + port->mii_ts.hwtstamp = ines_hwtstamp; 767 + port->mii_ts.link_state = ines_link_state; 768 + port->mii_ts.ts_info = ines_ts_info; 769 + 770 + return &port->mii_ts; 771 + } 772 + 773 + static void ines_ptp_release_channel(struct device *device, 774 + struct mii_timestamper *mii_ts) 775 + { 776 + } 777 + 778 + static struct mii_timestamping_ctrl ines_ctrl = { 779 + .probe_channel = ines_ptp_probe_channel, 780 + .release_channel = ines_ptp_release_channel, 781 + }; 782 + 783 + static int ines_ptp_ctrl_probe(struct platform_device *pld) 784 + { 785 + struct ines_clock *clock; 786 + struct resource *res; 787 + void __iomem *addr; 788 + int err = 0; 789 + 790 + res = platform_get_resource(pld, IORESOURCE_MEM, 0); 791 + if (!res) { 792 + dev_err(&pld->dev, "missing memory resource\n"); 793 + return -EINVAL; 794 + } 795 + addr = devm_ioremap_resource(&pld->dev, res); 796 + if (IS_ERR(addr)) { 797 + err = PTR_ERR(addr); 798 + goto out; 799 + } 800 + clock = kzalloc(sizeof(*clock), GFP_KERNEL); 801 + if (!clock) { 802 + err = -ENOMEM; 803 + goto out; 804 + } 805 + if (ines_clock_init(clock, &pld->dev, addr)) { 806 + kfree(clock); 807 + err = -ENOMEM; 808 + goto out; 809 + } 810 + err = register_mii_tstamp_controller(&pld->dev, &ines_ctrl); 811 + if (err) { 812 + kfree(clock); 813 + goto out; 814 + } 815 + mutex_lock(&ines_clocks_lock); 816 + list_add_tail(&ines_clocks, &clock->list); 817 + mutex_unlock(&ines_clocks_lock); 818 + 819 + dev_set_drvdata(&pld->dev, clock); 820 + out: 821 + return err; 822 + } 823 + 824 + static int ines_ptp_ctrl_remove(struct platform_device *pld) 825 + { 826 + struct ines_clock *clock = dev_get_drvdata(&pld->dev); 827 + 828 + unregister_mii_tstamp_controller(&pld->dev); 829 + mutex_lock(&ines_clocks_lock); 830 + list_del(&clock->list); 831 + mutex_unlock(&ines_clocks_lock); 832 + ines_clock_cleanup(clock); 833 + kfree(clock); 834 + return 0; 835 + } 836 + 837 + static const struct of_device_id ines_ptp_ctrl_of_match[] = { 838 + { .compatible = "ines,ptp-ctrl" }, 839 + { } 840 + }; 841 + 842 + MODULE_DEVICE_TABLE(of, ines_ptp_ctrl_of_match); 843 + 844 + static struct platform_driver ines_ptp_ctrl_driver = { 845 + .probe = ines_ptp_ctrl_probe, 846 + .remove = ines_ptp_ctrl_remove, 847 + .driver = { 848 + .name = "ines_ptp_ctrl", 849 + .of_match_table = of_match_ptr(ines_ptp_ctrl_of_match), 850 + }, 851 + }; 852 + module_platform_driver(ines_ptp_ctrl_driver);
+121
include/linux/mii_timestamper.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Support for generic time stamping devices on MII buses. 4 + * Copyright (C) 2018 Richard Cochran <richardcochran@gmail.com> 5 + */ 6 + #ifndef _LINUX_MII_TIMESTAMPER_H 7 + #define _LINUX_MII_TIMESTAMPER_H 8 + 9 + #include <linux/device.h> 10 + #include <linux/ethtool.h> 11 + #include <linux/skbuff.h> 12 + 13 + struct phy_device; 14 + 15 + /** 16 + * struct mii_timestamper - Callback interface to MII time stamping devices. 17 + * 18 + * @rxtstamp: Requests a Rx timestamp for 'skb'. If the skb is accepted, 19 + * the MII time stamping device promises to deliver it using 20 + * netif_rx() as soon as a timestamp becomes available. One of 21 + * the PTP_CLASS_ values is passed in 'type'. The function 22 + * must return true if the skb is accepted for delivery. 23 + * 24 + * @txtstamp: Requests a Tx timestamp for 'skb'. The MII time stamping 25 + * device promises to deliver it using skb_complete_tx_timestamp() 26 + * as soon as a timestamp becomes available. One of the PTP_CLASS_ 27 + * values is passed in 'type'. 28 + * 29 + * @hwtstamp: Handles SIOCSHWTSTAMP ioctl for hardware time stamping. 30 + * 31 + * @link_state: Allows the device to respond to changes in the link 32 + * state. The caller invokes this function while holding 33 + * the phy_device mutex. 34 + * 35 + * @ts_info: Handles ethtool queries for hardware time stamping. 36 + * @device: Remembers the device to which the instance belongs. 37 + * 38 + * Drivers for PHY time stamping devices should embed their 39 + * mii_timestamper within a private structure, obtaining a reference 40 + * to it using container_of(). 41 + * 42 + * Drivers for non-PHY time stamping devices should return a pointer 43 + * to a mii_timestamper from the probe_channel() callback of their 44 + * mii_timestamping_ctrl interface. 45 + */ 46 + struct mii_timestamper { 47 + bool (*rxtstamp)(struct mii_timestamper *mii_ts, 48 + struct sk_buff *skb, int type); 49 + 50 + void (*txtstamp)(struct mii_timestamper *mii_ts, 51 + struct sk_buff *skb, int type); 52 + 53 + int (*hwtstamp)(struct mii_timestamper *mii_ts, 54 + struct ifreq *ifreq); 55 + 56 + void (*link_state)(struct mii_timestamper *mii_ts, 57 + struct phy_device *phydev); 58 + 59 + int (*ts_info)(struct mii_timestamper *mii_ts, 60 + struct ethtool_ts_info *ts_info); 61 + 62 + struct device *device; 63 + }; 64 + 65 + /** 66 + * struct mii_timestamping_ctrl - MII time stamping controller interface. 67 + * 68 + * @probe_channel: Callback into the controller driver announcing the 69 + * presence of the 'port' channel. The 'device' field 70 + * had been passed to register_mii_tstamp_controller(). 71 + * The driver must return either a pointer to a valid 72 + * MII timestamper instance or PTR_ERR. 73 + * 74 + * @release_channel: Releases an instance obtained via .probe_channel. 75 + */ 76 + struct mii_timestamping_ctrl { 77 + struct mii_timestamper *(*probe_channel)(struct device *device, 78 + unsigned int port); 79 + void (*release_channel)(struct device *device, 80 + struct mii_timestamper *mii_ts); 81 + }; 82 + 83 + #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING 84 + 85 + int register_mii_tstamp_controller(struct device *device, 86 + struct mii_timestamping_ctrl *ctrl); 87 + 88 + void unregister_mii_tstamp_controller(struct device *device); 89 + 90 + struct mii_timestamper *register_mii_timestamper(struct device_node *node, 91 + unsigned int port); 92 + 93 + void unregister_mii_timestamper(struct mii_timestamper *mii_ts); 94 + 95 + #else 96 + 97 + static inline 98 + int register_mii_tstamp_controller(struct device *device, 99 + struct mii_timestamping_ctrl *ctrl) 100 + { 101 + return -EOPNOTSUPP; 102 + } 103 + 104 + static inline void unregister_mii_tstamp_controller(struct device *device) 105 + { 106 + } 107 + 108 + static inline 109 + struct mii_timestamper *register_mii_timestamper(struct device_node *node, 110 + unsigned int port) 111 + { 112 + return NULL; 113 + } 114 + 115 + static inline void unregister_mii_timestamper(struct mii_timestamper *mii_ts) 116 + { 117 + } 118 + 119 + #endif 120 + 121 + #endif
+62 -23
include/linux/phy.h
··· 17 17 #include <linux/linkmode.h> 18 18 #include <linux/mdio.h> 19 19 #include <linux/mii.h> 20 + #include <linux/mii_timestamper.h> 20 21 #include <linux/module.h> 21 22 #include <linux/timer.h> 22 23 #include <linux/workqueue.h> ··· 442 441 struct sfp_bus *sfp_bus; 443 442 struct phylink *phylink; 444 443 struct net_device *attached_dev; 444 + struct mii_timestamper *mii_ts; 445 445 446 446 u8 mdix; 447 447 u8 mdix_ctrl; ··· 547 545 * phy_id_mask. 548 546 */ 549 547 int (*match_phy_device)(struct phy_device *phydev); 550 - 551 - /* Handles ethtool queries for hardware time stamping. */ 552 - int (*ts_info)(struct phy_device *phydev, struct ethtool_ts_info *ti); 553 - 554 - /* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */ 555 - int (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr); 556 - 557 - /* 558 - * Requests a Rx timestamp for 'skb'. If the skb is accepted, 559 - * the phy driver promises to deliver it using netif_rx() as 560 - * soon as a timestamp becomes available. One of the 561 - * PTP_CLASS_ values is passed in 'type'. The function must 562 - * return true if the skb is accepted for delivery. 563 - */ 564 - bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type); 565 - 566 - /* 567 - * Requests a Tx timestamp for 'skb'. The phy driver promises 568 - * to deliver it using skb_complete_tx_timestamp() as soon as a 569 - * timestamp becomes available. One of the PTP_CLASS_ values 570 - * is passed in 'type'. 571 - */ 572 - void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type); 573 548 574 549 /* Some devices (e.g. qnap TS-119P II) require PHY register changes to 575 550 * enable Wake on LAN, so set_wol is provided to be called in the ··· 913 934 static inline bool phy_polling_mode(struct phy_device *phydev) 914 935 { 915 936 return phydev->irq == PHY_POLL; 937 + } 938 + 939 + /** 940 + * phy_has_hwtstamp - Tests whether a PHY time stamp configuration. 941 + * @phydev: the phy_device struct 942 + */ 943 + static inline bool phy_has_hwtstamp(struct phy_device *phydev) 944 + { 945 + return phydev && phydev->mii_ts && phydev->mii_ts->hwtstamp; 946 + } 947 + 948 + /** 949 + * phy_has_rxtstamp - Tests whether a PHY supports receive time stamping. 950 + * @phydev: the phy_device struct 951 + */ 952 + static inline bool phy_has_rxtstamp(struct phy_device *phydev) 953 + { 954 + return phydev && phydev->mii_ts && phydev->mii_ts->rxtstamp; 955 + } 956 + 957 + /** 958 + * phy_has_tsinfo - Tests whether a PHY reports time stamping and/or 959 + * PTP hardware clock capabilities. 960 + * @phydev: the phy_device struct 961 + */ 962 + static inline bool phy_has_tsinfo(struct phy_device *phydev) 963 + { 964 + return phydev && phydev->mii_ts && phydev->mii_ts->ts_info; 965 + } 966 + 967 + /** 968 + * phy_has_txtstamp - Tests whether a PHY supports transmit time stamping. 969 + * @phydev: the phy_device struct 970 + */ 971 + static inline bool phy_has_txtstamp(struct phy_device *phydev) 972 + { 973 + return phydev && phydev->mii_ts && phydev->mii_ts->txtstamp; 974 + } 975 + 976 + static inline int phy_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) 977 + { 978 + return phydev->mii_ts->hwtstamp(phydev->mii_ts, ifr); 979 + } 980 + 981 + static inline bool phy_rxtstamp(struct phy_device *phydev, struct sk_buff *skb, 982 + int type) 983 + { 984 + return phydev->mii_ts->rxtstamp(phydev->mii_ts, skb, type); 985 + } 986 + 987 + static inline int phy_ts_info(struct phy_device *phydev, 988 + struct ethtool_ts_info *tsinfo) 989 + { 990 + return phydev->mii_ts->ts_info(phydev->mii_ts, tsinfo); 991 + } 992 + 993 + static inline void phy_txtstamp(struct phy_device *phydev, struct sk_buff *skb, 994 + int type) 995 + { 996 + phydev->mii_ts->txtstamp(phydev->mii_ts, skb, type); 916 997 } 917 998 918 999 /**
+8
include/uapi/linux/net_tstamp.h
··· 90 90 * queue. 91 91 */ 92 92 HWTSTAMP_TX_ONESTEP_SYNC, 93 + 94 + /* 95 + * Same as HWTSTAMP_TX_ONESTEP_SYNC, but also enables time 96 + * stamp insertion directly into PDelay_Resp packets. In this 97 + * case, neither transmitted Sync nor PDelay_Resp packets will 98 + * receive a time stamp via the socket error queue. 99 + */ 100 + HWTSTAMP_TX_ONESTEP_P2P, 93 101 }; 94 102 95 103 /* possible values for hwtstamp_config->rx_filter */
+2 -2
net/8021q/vlan_dev.c
··· 646 646 const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops; 647 647 struct phy_device *phydev = vlan->real_dev->phydev; 648 648 649 - if (phydev && phydev->drv && phydev->drv->ts_info) { 650 - return phydev->drv->ts_info(phydev, info); 649 + if (phy_has_tsinfo(phydev)) { 650 + return phy_ts_info(phydev, info); 651 651 } else if (ops->get_ts_info) { 652 652 return ops->get_ts_info(vlan->real_dev, info); 653 653 } else {
+4 -3
net/Kconfig
··· 108 108 bool "Timestamping in PHY devices" 109 109 select NET_PTP_CLASSIFY 110 110 help 111 - This allows timestamping of network packets by PHYs with 112 - hardware timestamping capabilities. This option adds some 113 - overhead in the transmit and receive paths. 111 + This allows timestamping of network packets by PHYs (or 112 + other MII bus snooping devices) with hardware timestamping 113 + capabilities. This option adds some overhead in the transmit 114 + and receive paths. 114 115 115 116 If you are unsure how to answer this question, answer N. 116 117
+1
net/core/dev_ioctl.c
··· 187 187 case HWTSTAMP_TX_OFF: 188 188 case HWTSTAMP_TX_ON: 189 189 case HWTSTAMP_TX_ONESTEP_SYNC: 190 + case HWTSTAMP_TX_ONESTEP_P2P: 190 191 tx_type_valid = 1; 191 192 break; 192 193 }
+10 -10
net/core/timestamping.c
··· 13 13 static unsigned int classify(const struct sk_buff *skb) 14 14 { 15 15 if (likely(skb->dev && skb->dev->phydev && 16 - skb->dev->phydev->drv)) 16 + skb->dev->phydev->mii_ts)) 17 17 return ptp_classify_raw(skb); 18 18 else 19 19 return PTP_CLASS_NONE; ··· 21 21 22 22 void skb_clone_tx_timestamp(struct sk_buff *skb) 23 23 { 24 - struct phy_device *phydev; 24 + struct mii_timestamper *mii_ts; 25 25 struct sk_buff *clone; 26 26 unsigned int type; 27 27 ··· 32 32 if (type == PTP_CLASS_NONE) 33 33 return; 34 34 35 - phydev = skb->dev->phydev; 36 - if (likely(phydev->drv->txtstamp)) { 35 + mii_ts = skb->dev->phydev->mii_ts; 36 + if (likely(mii_ts->txtstamp)) { 37 37 clone = skb_clone_sk(skb); 38 38 if (!clone) 39 39 return; 40 - phydev->drv->txtstamp(phydev, clone, type); 40 + mii_ts->txtstamp(mii_ts, clone, type); 41 41 } 42 42 } 43 43 EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); 44 44 45 45 bool skb_defer_rx_timestamp(struct sk_buff *skb) 46 46 { 47 - struct phy_device *phydev; 47 + struct mii_timestamper *mii_ts; 48 48 unsigned int type; 49 49 50 - if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->drv) 50 + if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->mii_ts) 51 51 return false; 52 52 53 53 if (skb_headroom(skb) < ETH_HLEN) ··· 62 62 if (type == PTP_CLASS_NONE) 63 63 return false; 64 64 65 - phydev = skb->dev->phydev; 66 - if (likely(phydev->drv->rxtstamp)) 67 - return phydev->drv->rxtstamp(phydev, skb, type); 65 + mii_ts = skb->dev->phydev->mii_ts; 66 + if (likely(mii_ts->rxtstamp)) 67 + return mii_ts->rxtstamp(mii_ts, skb, type); 68 68 69 69 return false; 70 70 }
+2 -2
net/ethtool/ioctl.c
··· 2096 2096 memset(&info, 0, sizeof(info)); 2097 2097 info.cmd = ETHTOOL_GET_TS_INFO; 2098 2098 2099 - if (phydev && phydev->drv && phydev->drv->ts_info) { 2100 - err = phydev->drv->ts_info(phydev, &info); 2099 + if (phy_has_tsinfo(phydev)) { 2100 + err = phy_ts_info(phydev, &info); 2101 2101 } else if (ops->get_ts_info) { 2102 2102 err = ops->get_ts_info(dev, &info); 2103 2103 } else {