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

net: Introduce a new MII time stamping interface.

Currently the stack supports time stamping in PHY devices. However,
there are newer, non-PHY devices that can snoop an MII bus and provide
time stamps. In order to support such devices, this patch introduces
a new interface to be used by both PHY and non-PHY devices.

In addition, the one and only user of the old PHY time stamping API is
converted to the new interface.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Richard Cochran and committed by
David S. Miller
4715f65f 12d0efb9

+106 -58
+24 -15
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; ··· 1230 1229 } 1231 1230 } 1232 1231 1233 - static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) 1232 + static int dp83640_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) 1234 1233 { 1235 - struct dp83640_private *dp83640 = phydev->priv; 1234 + struct dp83640_private *dp83640 = 1235 + container_of(mii_ts, struct dp83640_private, mii_ts); 1236 1236 struct hwtstamp_config cfg; 1237 1237 u16 txcfg0, rxcfg0; 1238 1238 ··· 1309 1307 1310 1308 mutex_lock(&dp83640->clock->extreg_lock); 1311 1309 1312 - ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0); 1313 - ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0); 1310 + ext_write(0, dp83640->phydev, PAGE5, PTP_TXCFG0, txcfg0); 1311 + ext_write(0, dp83640->phydev, PAGE5, PTP_RXCFG0, rxcfg0); 1314 1312 1315 1313 mutex_unlock(&dp83640->clock->extreg_lock); 1316 1314 ··· 1340 1338 schedule_delayed_work(&dp83640->ts_work, SKB_TIMESTAMP_TIMEOUT); 1341 1339 } 1342 1340 1343 - static bool dp83640_rxtstamp(struct phy_device *phydev, 1341 + static bool dp83640_rxtstamp(struct mii_timestamper *mii_ts, 1344 1342 struct sk_buff *skb, int type) 1345 1343 { 1346 - struct dp83640_private *dp83640 = phydev->priv; 1344 + struct dp83640_private *dp83640 = 1345 + container_of(mii_ts, struct dp83640_private, mii_ts); 1347 1346 struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb; 1348 1347 struct list_head *this, *next; 1349 1348 struct rxts *rxts; ··· 1390 1387 return true; 1391 1388 } 1392 1389 1393 - static void dp83640_txtstamp(struct phy_device *phydev, 1390 + static void dp83640_txtstamp(struct mii_timestamper *mii_ts, 1394 1391 struct sk_buff *skb, int type) 1395 1392 { 1396 1393 struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb; 1397 - struct dp83640_private *dp83640 = phydev->priv; 1394 + struct dp83640_private *dp83640 = 1395 + container_of(mii_ts, struct dp83640_private, mii_ts); 1398 1396 1399 1397 switch (dp83640->hwts_tx_en) { 1400 1398 ··· 1418 1414 } 1419 1415 } 1420 1416 1421 - static int dp83640_ts_info(struct phy_device *dev, struct ethtool_ts_info *info) 1417 + static int dp83640_ts_info(struct mii_timestamper *mii_ts, 1418 + struct ethtool_ts_info *info) 1422 1419 { 1423 - struct dp83640_private *dp83640 = dev->priv; 1420 + struct dp83640_private *dp83640 = 1421 + container_of(mii_ts, struct dp83640_private, mii_ts); 1424 1422 1425 1423 info->so_timestamping = 1426 1424 SOF_TIMESTAMPING_TX_HARDWARE | ··· 1460 1454 goto no_memory; 1461 1455 1462 1456 dp83640->phydev = phydev; 1463 - INIT_DELAYED_WORK(&dp83640->ts_work, rx_timestamp_work); 1457 + dp83640->mii_ts.rxtstamp = dp83640_rxtstamp; 1458 + dp83640->mii_ts.txtstamp = dp83640_txtstamp; 1459 + dp83640->mii_ts.hwtstamp = dp83640_hwtstamp; 1460 + dp83640->mii_ts.ts_info = dp83640_ts_info; 1464 1461 1462 + INIT_DELAYED_WORK(&dp83640->ts_work, rx_timestamp_work); 1465 1463 INIT_LIST_HEAD(&dp83640->rxts); 1466 1464 INIT_LIST_HEAD(&dp83640->rxpool); 1467 1465 for (i = 0; i < MAX_RXTS; i++) 1468 1466 list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool); 1469 1467 1468 + phydev->mii_ts = &dp83640->mii_ts; 1470 1469 phydev->priv = dp83640; 1471 1470 1472 1471 spin_lock_init(&dp83640->rx_lock); ··· 1512 1501 if (phydev->mdio.addr == BROADCAST_ADDR) 1513 1502 return; 1514 1503 1504 + phydev->mii_ts = NULL; 1505 + 1515 1506 enable_status_frames(phydev, false); 1516 1507 cancel_delayed_work_sync(&dp83640->ts_work); 1517 1508 ··· 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)
+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:
+2
drivers/net/phy/phy_device.c
··· 919 919 netif_carrier_off(netdev); 920 920 } 921 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); 922 924 } 923 925 924 926 /**
+58
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 + * 37 + * Drivers for PHY time stamping devices should embed their 38 + * mii_timestamper within a private structure, obtaining a reference 39 + * to it using container_of(). 40 + */ 41 + struct mii_timestamper { 42 + bool (*rxtstamp)(struct mii_timestamper *mii_ts, 43 + struct sk_buff *skb, int type); 44 + 45 + void (*txtstamp)(struct mii_timestamper *mii_ts, 46 + struct sk_buff *skb, int type); 47 + 48 + int (*hwtstamp)(struct mii_timestamper *mii_ts, 49 + struct ifreq *ifreq); 50 + 51 + void (*link_state)(struct mii_timestamper *mii_ts, 52 + struct phy_device *phydev); 53 + 54 + int (*ts_info)(struct mii_timestamper *mii_ts, 55 + struct ethtool_ts_info *ts_info); 56 + }; 57 + 58 + #endif
+10 -31
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 ··· 921 942 */ 922 943 static inline bool phy_has_hwtstamp(struct phy_device *phydev) 923 944 { 924 - return phydev && phydev->drv && phydev->drv->hwtstamp; 945 + return phydev && phydev->mii_ts && phydev->mii_ts->hwtstamp; 925 946 } 926 947 927 948 /** ··· 930 951 */ 931 952 static inline bool phy_has_rxtstamp(struct phy_device *phydev) 932 953 { 933 - return phydev && phydev->drv && phydev->drv->rxtstamp; 954 + return phydev && phydev->mii_ts && phydev->mii_ts->rxtstamp; 934 955 } 935 956 936 957 /** ··· 940 961 */ 941 962 static inline bool phy_has_tsinfo(struct phy_device *phydev) 942 963 { 943 - return phydev && phydev->drv && phydev->drv->ts_info; 964 + return phydev && phydev->mii_ts && phydev->mii_ts->ts_info; 944 965 } 945 966 946 967 /** ··· 949 970 */ 950 971 static inline bool phy_has_txtstamp(struct phy_device *phydev) 951 972 { 952 - return phydev && phydev->drv && phydev->drv->txtstamp; 973 + return phydev && phydev->mii_ts && phydev->mii_ts->txtstamp; 953 974 } 954 975 955 976 static inline int phy_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) 956 977 { 957 - return phydev->drv->hwtstamp(phydev, ifr); 978 + return phydev->mii_ts->hwtstamp(phydev->mii_ts, ifr); 958 979 } 959 980 960 981 static inline bool phy_rxtstamp(struct phy_device *phydev, struct sk_buff *skb, 961 982 int type) 962 983 { 963 - return phydev->drv->rxtstamp(phydev, skb, type); 984 + return phydev->mii_ts->rxtstamp(phydev->mii_ts, skb, type); 964 985 } 965 986 966 987 static inline int phy_ts_info(struct phy_device *phydev, 967 988 struct ethtool_ts_info *tsinfo) 968 989 { 969 - return phydev->drv->ts_info(phydev, tsinfo); 990 + return phydev->mii_ts->ts_info(phydev->mii_ts, tsinfo); 970 991 } 971 992 972 993 static inline void phy_txtstamp(struct phy_device *phydev, struct sk_buff *skb, 973 994 int type) 974 995 { 975 - phydev->drv->txtstamp(phydev, skb, type); 996 + phydev->mii_ts->txtstamp(phydev->mii_ts, skb, type); 976 997 } 977 998 978 999 /**
+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 }