Introduce support for ETHTOOL_MSG_TSCONFIG_GET/SET ethtool netlink socket to read and configure hwtstamp configuration of a PHC provider. Note that simultaneous hwtstamp isn't supported; configuring a new one disables the previous setting.
Unified · Split
| @@ -1489,6 +1489,33 @@ attribute-sets: · 1488 unmodified lines | ||
| 1489 | 1489 | - |
| 1490 | 1490 | name: downstream-sfp-name |
| 1491 | 1491 | type: string |
| 1492 | + - | |
| 1493 | + name: tsconfig | |
| 1494 | + attr-cnt-name: __ethtool-a-tsconfig-cnt | |
| 1495 | + attributes: | |
| 1496 | + - | |
| 1497 | + name: unspec | |
| 1498 | + type: unused | |
| 1499 | + value: 0 | |
| 1500 | + - | |
| 1501 | + name: header | |
| 1502 | + type: nest | |
| 1503 | + nested-attributes: header | |
| 1504 | + - | |
| 1505 | + name: hwtstamp-provider | |
| 1506 | + type: nest | |
| 1507 | + nested-attributes: ts-hwtstamp-provider | |
| 1508 | + - | |
| 1509 | + name: tx-types | |
| 1510 | + type: nest | |
| 1511 | + nested-attributes: bitset | |
| 1512 | + - | |
| 1513 | + name: rx-filters | |
| 1514 | + type: nest | |
| 1515 | + nested-attributes: bitset | |
| 1516 | + - | |
| 1517 | + name: hwtstamp-flags | |
| 1518 | + type: u32 | |
| 1492 | 1519 | |
| 1493 | 1520 | operations: |
| 1494 | 1521 | enum-model: directional |
| @@ -2314,3 +2341,32 @@ operations: · 819 unmodified lines | ||
| 2314 | 2341 | name: phy-ntf |
| 2315 | 2342 | doc: Notification for change in PHY devices. |
| 2316 | 2343 | notify: phy-get |
| 2344 | + - | |
| 2345 | + name: tsconfig-get | |
| 2346 | + doc: Get hwtstamp config. | |
| 2347 | + | |
| 2348 | + attribute-set: tsconfig | |
| 2349 | + | |
| 2350 | + do: &tsconfig-get-op | |
| 2351 | + request: | |
| 2352 | + attributes: | |
| 2353 | + - header | |
| 2354 | + reply: | |
| 2355 | + attributes: &tsconfig | |
| 2356 | + - header | |
| 2357 | + - hwtstamp-provider | |
| 2358 | + - tx-types | |
| 2359 | + - rx-filters | |
| 2360 | + - hwtstamp-flags | |
| 2361 | + dump: *tsconfig-get-op | |
| 2362 | + - | |
| 2363 | + name: tsconfig-set | |
| 2364 | + doc: Set hwtstamp config. | |
| 2365 | + | |
| 2366 | + attribute-set: tsconfig | |
| 2367 | + | |
| 2368 | + do: | |
| 2369 | + request: | |
| 2370 | + attributes: *tsconfig | |
| 2371 | + reply: | |
| 2372 | + attributes: *tsconfig | |
| @@ -237,6 +237,8 @@ Userspace to kernel: · 236 unmodified lines | ||
| 237 | 237 | ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters |
| 238 | 238 | ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware |
| 239 | 239 | ``ETHTOOL_MSG_PHY_GET`` get Ethernet PHY information |
| 240 | + ``ETHTOOL_MSG_TSCONFIG_GET`` get hw timestamping configuration | |
| 241 | + ``ETHTOOL_MSG_TSCONFIG_SET`` set hw timestamping configuration | |
| 240 | 242 | ===================================== ================================= |
| 241 | 243 | |
| 242 | 244 | Kernel to userspace: |
| @@ -286,6 +288,8 @@ Kernel to userspace: · 43 unmodified lines | ||
| 286 | 288 | ``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates |
| 287 | 289 | ``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information |
| 288 | 290 | ``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change |
| 291 | + ``ETHTOOL_MSG_TSCONFIG_GET_REPLY`` hw timestamping configuration | |
| 292 | + ``ETHTOOL_MSG_TSCONFIG_SET_REPLY`` new hw timestamping configuration | |
| 289 | 293 | ======================================== ================================= |
| 290 | 294 | |
| 291 | 295 | ``GET`` requests are sent by userspace applications to retrieve device |
| @@ -2244,6 +2248,75 @@ Kernel response contents: · 1952 unmodified lines | ||
| 2244 | 2248 | When ``ETHTOOL_A_PHY_UPSTREAM_TYPE`` is PHY_UPSTREAM_PHY, the PHY's parent is |
| 2245 | 2249 | another PHY. |
| 2246 | 2250 | |
| 2251 | +TSCONFIG_GET | |
| 2252 | +============ | |
| 2253 | + | |
| 2254 | +Retrieves the information about the current hardware timestamping source and | |
| 2255 | +configuration. | |
| 2256 | + | |
| 2257 | +It is similar to the deprecated ``SIOCGHWTSTAMP`` ioctl request. | |
| 2258 | + | |
| 2259 | +Request contents: | |
| 2260 | + | |
| 2261 | + ==================================== ====== ========================== | |
| 2262 | + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header | |
| 2263 | + ==================================== ====== ========================== | |
| 2264 | + | |
| 2265 | +Kernel response contents: | |
| 2266 | + | |
| 2267 | + ======================================== ====== ============================ | |
| 2268 | + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header | |
| 2269 | + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider | |
| 2270 | + ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type | |
| 2271 | + ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter | |
| 2272 | + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags | |
| 2273 | + ======================================== ====== ============================ | |
| 2274 | + | |
| 2275 | +When set the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` attribute identifies the | |
| 2276 | +source of the hw timestamping provider. It is composed by | |
| 2277 | +``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX`` attribute which describe the index of | |
| 2278 | +the PTP device and ``ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER`` which describe | |
| 2279 | +the qualifier of the timestamp. | |
| 2280 | + | |
| 2281 | +When set the ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` | |
| 2282 | +and the ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` attributes identify the Tx | |
| 2283 | +type, the Rx filter and the flags configured for the current hw timestamping | |
| 2284 | +provider. The attributes are propagated to the driver through the following | |
| 2285 | +structure: | |
| 2286 | + | |
| 2287 | +.. kernel-doc:: include/linux/net_tstamp.h | |
| 2288 | + :identifiers: kernel_hwtstamp_config | |
| 2289 | + | |
| 2290 | +TSCONFIG_SET | |
| 2291 | +============ | |
| 2292 | + | |
| 2293 | +Set the information about the current hardware timestamping source and | |
| 2294 | +configuration. | |
| 2295 | + | |
| 2296 | +It is similar to the deprecated ``SIOCSHWTSTAMP`` ioctl request. | |
| 2297 | + | |
| 2298 | +Request contents: | |
| 2299 | + | |
| 2300 | + ======================================== ====== ============================ | |
| 2301 | + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header | |
| 2302 | + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider | |
| 2303 | + ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type | |
| 2304 | + ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter | |
| 2305 | + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags | |
| 2306 | + ======================================== ====== ============================ | |
| 2307 | + | |
| 2308 | +Kernel response contents: | |
| 2309 | + | |
| 2310 | + ======================================== ====== ============================ | |
| 2311 | + ``ETHTOOL_A_TSCONFIG_HEADER`` nested request header | |
| 2312 | + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` nested PTP hw clock provider | |
| 2313 | + ``ETHTOOL_A_TSCONFIG_TX_TYPES`` bitset hwtstamp Tx type | |
| 2314 | + ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` bitset hwtstamp Rx filter | |
| 2315 | + ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` u32 hwtstamp flags | |
| 2316 | + ======================================== ====== ============================ | |
| 2317 | + | |
| 2318 | +For a description of each attribute, see ``TSCONFIG_GET``. | |
| 2319 | + | |
| 2247 | 2320 | Request translation |
| 2248 | 2321 | =================== |
| 2249 | 2322 | |
| @@ -2352,4 +2425,6 @@ are netlink only. · 102 unmodified lines | ||
| 2352 | 2425 | n/a ``ETHTOOL_MSG_MM_SET`` |
| 2353 | 2426 | n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` |
| 2354 | 2427 | n/a ``ETHTOOL_MSG_PHY_GET`` |
| 2428 | + ``SIOCGHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_GET`` | |
| 2429 | + ``SIOCSHWTSTAMP`` ``ETHTOOL_MSG_TSCONFIG_SET`` | |
| 2355 | 2430 | =================================== ===================================== |
| @@ -525,8 +525,8 @@ implicitly defined. ts[0] holds a software timestamp if set, ts[1] · 524 unmodified lines | ||
| 525 | 525 | is again deprecated and ts[2] holds a hardware timestamp if set. |
| 526 | 526 | |
| 527 | 527 | |
| 528 | −3. Hardware Timestamping configuration: SIOCSHWTSTAMP and SIOCGHWTSTAMP | |
| 529 | −======================================================================= | |
| 528 | +3. Hardware Timestamping configuration: ETHTOOL_MSG_TSCONFIG_SET/GET | |
| 529 | +==================================================================== | |
| 530 | 530 | |
| 531 | 531 | Hardware time stamping must also be initialized for each device driver |
| 532 | 532 | that is expected to do hardware time stamping. The parameter is defined in |
| @@ -539,12 +539,14 @@ include/uapi/linux/net_tstamp.h as:: · 6 unmodified lines | ||
| 539 | 539 | }; |
| 540 | 540 | |
| 541 | 541 | Desired behavior is passed into the kernel and to a specific device by |
| 542 | −calling ioctl(SIOCSHWTSTAMP) with a pointer to a struct ifreq whose | |
| 543 | −ifr_data points to a struct hwtstamp_config. The tx_type and | |
| 544 | −rx_filter are hints to the driver what it is expected to do. If | |
| 545 | −the requested fine-grained filtering for incoming packets is not | |
| 546 | −supported, the driver may time stamp more than just the requested types | |
| 547 | −of packets. | |
| 542 | +calling the tsconfig netlink socket ``ETHTOOL_MSG_TSCONFIG_SET``. | |
| 543 | +The ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` and | |
| 544 | +``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` netlink attributes are then used to set | |
| 545 | +the struct hwtstamp_config accordingly. | |
| 546 | + | |
| 547 | +The ``ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER`` netlink nested attribute is used | |
| 548 | +to select the source of the hardware time stamping. It is composed of an index | |
| 549 | +for the device source and a qualifier for the type of time stamping. | |
| 548 | 550 | |
| 549 | 551 | Drivers are free to use a more permissive configuration than the requested |
| 550 | 552 | configuration. It is expected that drivers should only implement directly the |
| @@ -563,9 +565,16 @@ Only a processes with admin rights may change the configuration. User · 12 unmodified lines | ||
| 563 | 565 | space is responsible to ensure that multiple processes don't interfere |
| 564 | 566 | with each other and that the settings are reset. |
| 565 | 567 | |
| 566 | −Any process can read the actual configuration by passing this | |
| 567 | −structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has | |
| 568 | −not been implemented in all drivers. | |
| 568 | +Any process can read the actual configuration by requesting tsconfig netlink | |
| 569 | +socket ``ETHTOOL_MSG_TSCONFIG_GET``. | |
| 570 | + | |
| 571 | +The legacy configuration is the use of the ioctl(SIOCSHWTSTAMP) with a pointer | |
| 572 | +to a struct ifreq whose ifr_data points to a struct hwtstamp_config. | |
| 573 | +The tx_type and rx_filter are hints to the driver what it is expected to do. | |
| 574 | +If the requested fine-grained filtering for incoming packets is not | |
| 575 | +supported, the driver may time stamp more than just the requested types | |
| 576 | +of packets. ioctl(SIOCGHWTSTAMP) is used in the same way as the | |
| 577 | +ioctl(SIOCSHWTSTAMP). However, this has not been implemented in all drivers. | |
| 569 | 578 | |
| 570 | 579 | :: |
| 571 | 580 | |
| @@ -610,9 +619,10 @@ not been implemented in all drivers. · 38 unmodified lines | ||
| 610 | 619 | -------------------------------------------------------- |
| 611 | 620 | |
| 612 | 621 | A driver which supports hardware time stamping must support the |
| 613 | −SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with | |
| 614 | −the actual values as described in the section on SIOCSHWTSTAMP. It | |
| 615 | −should also support SIOCGHWTSTAMP. | |
| 622 | +ndo_hwtstamp_set NDO or the legacy SIOCSHWTSTAMP ioctl and update the | |
| 623 | +supplied struct hwtstamp_config with the actual values as described in | |
| 624 | +the section on SIOCSHWTSTAMP. It should also support ndo_hwtstamp_get or | |
| 625 | +the legacy SIOCGHWTSTAMP. | |
| 616 | 626 | |
| 617 | 627 | Time stamps for received packets must be stored in the skb. To get a pointer |
| 618 | 628 | to the shared time stamp structure of the skb call skb_hwtstamps(). Then |
| @@ -694,6 +694,18 @@ enum { · 693 unmodified lines | ||
| 694 | 694 | ETHTOOL_A_PHY_MAX = (__ETHTOOL_A_PHY_CNT - 1) |
| 695 | 695 | }; |
| 696 | 696 | |
| 697 | +enum { | |
| 698 | + ETHTOOL_A_TSCONFIG_UNSPEC, | |
| 699 | + ETHTOOL_A_TSCONFIG_HEADER, | |
| 700 | + ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER, | |
| 701 | + ETHTOOL_A_TSCONFIG_TX_TYPES, | |
| 702 | + ETHTOOL_A_TSCONFIG_RX_FILTERS, | |
| 703 | + ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS, | |
| 704 | + | |
| 705 | + __ETHTOOL_A_TSCONFIG_CNT, | |
| 706 | + ETHTOOL_A_TSCONFIG_MAX = (__ETHTOOL_A_TSCONFIG_CNT - 1) | |
| 707 | +}; | |
| 708 | + | |
| 697 | 709 | enum { |
| 698 | 710 | ETHTOOL_MSG_USER_NONE = 0, |
| 699 | 711 | ETHTOOL_MSG_STRSET_GET = 1, |
| @@ -741,6 +753,8 @@ enum { · 41 unmodified lines | ||
| 741 | 753 | ETHTOOL_MSG_MM_SET, |
| 742 | 754 | ETHTOOL_MSG_MODULE_FW_FLASH_ACT, |
| 743 | 755 | ETHTOOL_MSG_PHY_GET, |
| 756 | + ETHTOOL_MSG_TSCONFIG_GET, | |
| 757 | + ETHTOOL_MSG_TSCONFIG_SET, | |
| 744 | 758 | |
| 745 | 759 | __ETHTOOL_MSG_USER_CNT, |
| 746 | 760 | ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1) |
| @@ -794,6 +808,8 @@ enum { · 47 unmodified lines | ||
| 794 | 808 | ETHTOOL_MSG_MODULE_FW_FLASH_NTF, |
| 795 | 809 | ETHTOOL_MSG_PHY_GET_REPLY, |
| 796 | 810 | ETHTOOL_MSG_PHY_NTF, |
| 811 | + ETHTOOL_MSG_TSCONFIG_GET_REPLY, | |
| 812 | + ETHTOOL_MSG_TSCONFIG_SET_REPLY, | |
| 797 | 813 | |
| 798 | 814 | __ETHTOOL_MSG_KERNEL_CNT, |
| 799 | 815 | ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1) |
| @@ -9,4 +9,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \ · 8 unmodified lines | ||
| 9 | 9 | channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ |
| 10 | 10 | tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \ |
| 11 | 11 | module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o mm.o \ |
| 12 | − phy.o | |
| 12 | + phy.o tsconfig.o | |
| @@ -797,7 +797,7 @@ int ethtool_net_get_ts_info_by_phc(struct net_device *dev, · 796 unmodified lines | ||
| 797 | 797 | return -ENODEV; |
| 798 | 798 | } |
| 799 | 799 | |
| 800 | −int | |
| 800 | +struct phy_device * | |
| 801 | 801 | ethtool_phy_get_ts_info_by_phc(struct net_device *dev, |
| 802 | 802 | struct kernel_ethtool_ts_info *info, |
| 803 | 803 | struct hwtstamp_provider_desc *hwprov_desc) |
| @@ -806,7 +806,7 @@ ethtool_phy_get_ts_info_by_phc(struct net_device *dev, · 2 unmodified lines | ||
| 806 | 806 | |
| 807 | 807 | /* Only precise qualifier is supported in phydev */ |
| 808 | 808 | if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE) |
| 809 | − return -ENODEV; | |
| 809 | + return ERR_PTR(-ENODEV); | |
| 810 | 810 | |
| 811 | 811 | /* Look in the phy topology */ |
| 812 | 812 | if (dev->link_topo) { |
| @@ -820,12 +820,12 @@ ethtool_phy_get_ts_info_by_phc(struct net_device *dev, · 7 unmodified lines | ||
| 820 | 820 | ethtool_init_tsinfo(info); |
| 821 | 821 | err = phy_ts_info(pdn->phy, info); |
| 822 | 822 | if (err) |
| 823 | − return err; | |
| 823 | + return ERR_PTR(err); | |
| 824 | 824 | |
| 825 | 825 | if (info->phc_index == hwprov_desc->index) |
| 826 | − return 0; | |
| 826 | + return pdn->phy; | |
| 827 | 827 | } |
| 828 | − return -ENODEV; | |
| 828 | + return ERR_PTR(-ENODEV); | |
| 829 | 829 | } |
| 830 | 830 | |
| 831 | 831 | /* Look on the dev->phydev */ |
| @@ -833,13 +833,13 @@ ethtool_phy_get_ts_info_by_phc(struct net_device *dev, · 1 unmodified line | ||
| 833 | 833 | ethtool_init_tsinfo(info); |
| 834 | 834 | err = phy_ts_info(dev->phydev, info); |
| 835 | 835 | if (err) |
| 836 | − return err; | |
| 836 | + return ERR_PTR(err); | |
| 837 | 837 | |
| 838 | 838 | if (info->phc_index == hwprov_desc->index) |
| 839 | − return 0; | |
| 839 | + return dev->phydev; | |
| 840 | 840 | } |
| 841 | 841 | |
| 842 | − return -ENODEV; | |
| 842 | + return ERR_PTR(-ENODEV); | |
| 843 | 843 | } |
| 844 | 844 | |
| 845 | 845 | int ethtool_get_ts_info_by_phc(struct net_device *dev, |
| @@ -849,8 +849,15 @@ int ethtool_get_ts_info_by_phc(struct net_device *dev, · 3 unmodified lines | ||
| 849 | 849 | int err; |
| 850 | 850 | |
| 851 | 851 | err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc); |
| 852 | − if (err == -ENODEV) | |
| 853 | − err = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc); | |
| 852 | + if (err == -ENODEV) { | |
| 853 | + struct phy_device *phy; | |
| 854 | + | |
| 855 | + phy = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc); | |
| 856 | + if (IS_ERR(phy)) | |
| 857 | + err = PTR_ERR(phy); | |
| 858 | + else | |
| 859 | + err = 0; | |
| 860 | + } | |
| 854 | 861 | |
| 855 | 862 | info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE | |
| 856 | 863 | SOF_TIMESTAMPING_SOFTWARE; |
| @@ -56,7 +56,7 @@ int ethtool_get_ts_info_by_phc(struct net_device *dev, · 55 unmodified lines | ||
| 56 | 56 | int ethtool_net_get_ts_info_by_phc(struct net_device *dev, |
| 57 | 57 | struct kernel_ethtool_ts_info *info, |
| 58 | 58 | struct hwtstamp_provider_desc *hwprov_desc); |
| 59 | −int | |
| 59 | +struct phy_device * | |
| 60 | 60 | ethtool_phy_get_ts_info_by_phc(struct net_device *dev, |
| 61 | 61 | struct kernel_ethtool_ts_info *info, |
| 62 | 62 | struct hwtstamp_provider_desc *hwprov_desc); |
| @@ -394,6 +394,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { · 393 unmodified lines | ||
| 394 | 394 | [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops, |
| 395 | 395 | [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops, |
| 396 | 396 | [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, |
| 397 | + [ETHTOOL_MSG_TSCONFIG_GET] = ðnl_tsconfig_request_ops, | |
| 398 | + [ETHTOOL_MSG_TSCONFIG_SET] = ðnl_tsconfig_request_ops, | |
| 397 | 399 | }; |
| 398 | 400 | |
| 399 | 401 | static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) |
| @@ -1243,6 +1245,22 @@ static const struct genl_ops ethtool_genl_ops[] = { · 843 unmodified lines | ||
| 1243 | 1245 | .policy = ethnl_phy_get_policy, |
| 1244 | 1246 | .maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1, |
| 1245 | 1247 | }, |
| 1248 | + { | |
| 1249 | + .cmd = ETHTOOL_MSG_TSCONFIG_GET, | |
| 1250 | + .doit = ethnl_default_doit, | |
| 1251 | + .start = ethnl_default_start, | |
| 1252 | + .dumpit = ethnl_default_dumpit, | |
| 1253 | + .done = ethnl_default_done, | |
| 1254 | + .policy = ethnl_tsconfig_get_policy, | |
| 1255 | + .maxattr = ARRAY_SIZE(ethnl_tsconfig_get_policy) - 1, | |
| 1256 | + }, | |
| 1257 | + { | |
| 1258 | + .cmd = ETHTOOL_MSG_TSCONFIG_SET, | |
| 1259 | + .flags = GENL_UNS_ADMIN_PERM, | |
| 1260 | + .doit = ethnl_default_set_doit, | |
| 1261 | + .policy = ethnl_tsconfig_set_policy, | |
| 1262 | + .maxattr = ARRAY_SIZE(ethnl_tsconfig_set_policy) - 1, | |
| 1263 | + }, | |
| 1246 | 1264 | }; |
| 1247 | 1265 | |
| 1248 | 1266 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { |
| @@ -435,6 +435,7 @@ extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops; · 434 unmodified lines | ||
| 435 | 435 | extern const struct ethnl_request_ops ethnl_plca_status_request_ops; |
| 436 | 436 | extern const struct ethnl_request_ops ethnl_mm_request_ops; |
| 437 | 437 | extern const struct ethnl_request_ops ethnl_phy_request_ops; |
| 438 | +extern const struct ethnl_request_ops ethnl_tsconfig_request_ops; | |
| 438 | 439 | |
| 439 | 440 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; |
| 440 | 441 | extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; |
| @@ -485,6 +486,8 @@ extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1]; · 44 unmodified lines | ||
| 485 | 486 | extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; |
| 486 | 487 | extern const struct nla_policy ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1]; |
| 487 | 488 | extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1]; |
| 489 | +extern const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1]; | |
| 490 | +extern const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1]; | |
| 488 | 491 | |
| 489 | 492 | int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); |
| 490 | 493 | int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); |
| @@ -0,0 +1,444 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | + | |
| 3 | +#include <linux/net_tstamp.h> | |
| 4 | +#include <linux/ptp_clock_kernel.h> | |
| 5 | + | |
| 6 | +#include "netlink.h" | |
| 7 | +#include "common.h" | |
| 8 | +#include "bitset.h" | |
| 9 | +#include "../core/dev.h" | |
| 10 | +#include "ts.h" | |
| 11 | + | |
| 12 | +struct tsconfig_req_info { | |
| 13 | + struct ethnl_req_info base; | |
| 14 | +}; | |
| 15 | + | |
| 16 | +struct tsconfig_reply_data { | |
| 17 | + struct ethnl_reply_data base; | |
| 18 | + struct hwtstamp_provider_desc hwprov_desc; | |
| 19 | + struct { | |
| 20 | + u32 tx_type; | |
| 21 | + u32 rx_filter; | |
| 22 | + u32 flags; | |
| 23 | + } hwtst_config; | |
| 24 | +}; | |
| 25 | + | |
| 26 | +#define TSCONFIG_REPDATA(__reply_base) \ | |
| 27 | + container_of(__reply_base, struct tsconfig_reply_data, base) | |
| 28 | + | |
| 29 | +const struct nla_policy ethnl_tsconfig_get_policy[ETHTOOL_A_TSCONFIG_HEADER + 1] = { | |
| 30 | + [ETHTOOL_A_TSCONFIG_HEADER] = | |
| 31 | + NLA_POLICY_NESTED(ethnl_header_policy), | |
| 32 | +}; | |
| 33 | + | |
| 34 | +static int tsconfig_prepare_data(const struct ethnl_req_info *req_base, | |
| 35 | + struct ethnl_reply_data *reply_base, | |
| 36 | + const struct genl_info *info) | |
| 37 | +{ | |
| 38 | + struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base); | |
| 39 | + struct hwtstamp_provider *hwprov = NULL; | |
| 40 | + struct net_device *dev = reply_base->dev; | |
| 41 | + struct kernel_hwtstamp_config cfg = {}; | |
| 42 | + int ret; | |
| 43 | + | |
| 44 | + if (!dev->netdev_ops->ndo_hwtstamp_get) | |
| 45 | + return -EOPNOTSUPP; | |
| 46 | + | |
| 47 | + ret = ethnl_ops_begin(dev); | |
| 48 | + if (ret < 0) | |
| 49 | + return ret; | |
| 50 | + | |
| 51 | + ret = dev_get_hwtstamp_phylib(dev, &cfg); | |
| 52 | + if (ret) | |
| 53 | + goto out; | |
| 54 | + | |
| 55 | + data->hwtst_config.tx_type = BIT(cfg.tx_type); | |
| 56 | + data->hwtst_config.rx_filter = BIT(cfg.rx_filter); | |
| 57 | + data->hwtst_config.flags = BIT(cfg.flags); | |
| 58 | + | |
| 59 | + data->hwprov_desc.index = -1; | |
| 60 | + hwprov = rtnl_dereference(dev->hwprov); | |
| 61 | + if (hwprov) { | |
| 62 | + data->hwprov_desc.index = hwprov->desc.index; | |
| 63 | + data->hwprov_desc.qualifier = hwprov->desc.qualifier; | |
| 64 | + } else { | |
| 65 | + struct kernel_ethtool_ts_info ts_info = {}; | |
| 66 | + | |
| 67 | + ts_info.phc_index = -1; | |
| 68 | + ret = __ethtool_get_ts_info(dev, &ts_info); | |
| 69 | + if (ret) | |
| 70 | + goto out; | |
| 71 | + | |
| 72 | + if (ts_info.phc_index == -1) | |
| 73 | + return -ENODEV; | |
| 74 | + | |
| 75 | + data->hwprov_desc.index = ts_info.phc_index; | |
| 76 | + data->hwprov_desc.qualifier = ts_info.phc_qualifier; | |
| 77 | + } | |
| 78 | + | |
| 79 | +out: | |
| 80 | + ethnl_ops_complete(dev); | |
| 81 | + return ret; | |
| 82 | +} | |
| 83 | + | |
| 84 | +static int tsconfig_reply_size(const struct ethnl_req_info *req_base, | |
| 85 | + const struct ethnl_reply_data *reply_base) | |
| 86 | +{ | |
| 87 | + const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base); | |
| 88 | + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; | |
| 89 | + int len = 0; | |
| 90 | + int ret; | |
| 91 | + | |
| 92 | + BUILD_BUG_ON(__HWTSTAMP_TX_CNT > 32); | |
| 93 | + BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT > 32); | |
| 94 | + | |
| 95 | + if (data->hwtst_config.flags) | |
| 96 | + /* _TSCONFIG_HWTSTAMP_FLAGS */ | |
| 97 | + len += nla_total_size(sizeof(u32)); | |
| 98 | + | |
| 99 | + if (data->hwtst_config.tx_type) { | |
| 100 | + ret = ethnl_bitset32_size(&data->hwtst_config.tx_type, | |
| 101 | + NULL, __HWTSTAMP_TX_CNT, | |
| 102 | + ts_tx_type_names, compact); | |
| 103 | + if (ret < 0) | |
| 104 | + return ret; | |
| 105 | + len += ret; /* _TSCONFIG_TX_TYPES */ | |
| 106 | + } | |
| 107 | + if (data->hwtst_config.rx_filter) { | |
| 108 | + ret = ethnl_bitset32_size(&data->hwtst_config.rx_filter, | |
| 109 | + NULL, __HWTSTAMP_FILTER_CNT, | |
| 110 | + ts_rx_filter_names, compact); | |
| 111 | + if (ret < 0) | |
| 112 | + return ret; | |
| 113 | + len += ret; /* _TSCONFIG_RX_FILTERS */ | |
| 114 | + } | |
| 115 | + | |
| 116 | + if (data->hwprov_desc.index >= 0) | |
| 117 | + /* _TSCONFIG_HWTSTAMP_PROVIDER */ | |
| 118 | + len += nla_total_size(0) + | |
| 119 | + 2 * nla_total_size(sizeof(u32)); | |
| 120 | + | |
| 121 | + return len; | |
| 122 | +} | |
| 123 | + | |
| 124 | +static int tsconfig_fill_reply(struct sk_buff *skb, | |
| 125 | + const struct ethnl_req_info *req_base, | |
| 126 | + const struct ethnl_reply_data *reply_base) | |
| 127 | +{ | |
| 128 | + const struct tsconfig_reply_data *data = TSCONFIG_REPDATA(reply_base); | |
| 129 | + bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS; | |
| 130 | + int ret; | |
| 131 | + | |
| 132 | + if (data->hwtst_config.flags) { | |
| 133 | + ret = nla_put_u32(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS, | |
| 134 | + data->hwtst_config.flags); | |
| 135 | + if (ret < 0) | |
| 136 | + return ret; | |
| 137 | + } | |
| 138 | + | |
| 139 | + if (data->hwtst_config.tx_type) { | |
| 140 | + ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_TX_TYPES, | |
| 141 | + &data->hwtst_config.tx_type, NULL, | |
| 142 | + __HWTSTAMP_TX_CNT, | |
| 143 | + ts_tx_type_names, compact); | |
| 144 | + if (ret < 0) | |
| 145 | + return ret; | |
| 146 | + } | |
| 147 | + | |
| 148 | + if (data->hwtst_config.rx_filter) { | |
| 149 | + ret = ethnl_put_bitset32(skb, ETHTOOL_A_TSCONFIG_RX_FILTERS, | |
| 150 | + &data->hwtst_config.rx_filter, | |
| 151 | + NULL, __HWTSTAMP_FILTER_CNT, | |
| 152 | + ts_rx_filter_names, compact); | |
| 153 | + if (ret < 0) | |
| 154 | + return ret; | |
| 155 | + } | |
| 156 | + | |
| 157 | + if (data->hwprov_desc.index >= 0) { | |
| 158 | + struct nlattr *nest; | |
| 159 | + | |
| 160 | + nest = nla_nest_start(skb, ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER); | |
| 161 | + if (!nest) | |
| 162 | + return -EMSGSIZE; | |
| 163 | + | |
| 164 | + if (nla_put_u32(skb, ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX, | |
| 165 | + data->hwprov_desc.index) || | |
| 166 | + nla_put_u32(skb, | |
| 167 | + ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER, | |
| 168 | + data->hwprov_desc.qualifier)) { | |
| 169 | + nla_nest_cancel(skb, nest); | |
| 170 | + return -EMSGSIZE; | |
| 171 | + } | |
| 172 | + | |
| 173 | + nla_nest_end(skb, nest); | |
| 174 | + } | |
| 175 | + return 0; | |
| 176 | +} | |
| 177 | + | |
| 178 | +/* TSCONFIG_SET */ | |
| 179 | +const struct nla_policy ethnl_tsconfig_set_policy[ETHTOOL_A_TSCONFIG_MAX + 1] = { | |
| 180 | + [ETHTOOL_A_TSCONFIG_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy), | |
| 181 | + [ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER] = | |
| 182 | + NLA_POLICY_NESTED(ethnl_ts_hwtst_prov_policy), | |
| 183 | + [ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS] = { .type = NLA_U32 }, | |
| 184 | + [ETHTOOL_A_TSCONFIG_RX_FILTERS] = { .type = NLA_NESTED }, | |
| 185 | + [ETHTOOL_A_TSCONFIG_TX_TYPES] = { .type = NLA_NESTED }, | |
| 186 | +}; | |
| 187 | + | |
| 188 | +static int tsconfig_send_reply(struct net_device *dev, struct genl_info *info) | |
| 189 | +{ | |
| 190 | + struct tsconfig_reply_data *reply_data; | |
| 191 | + struct tsconfig_req_info *req_info; | |
| 192 | + struct sk_buff *rskb; | |
| 193 | + void *reply_payload; | |
| 194 | + int reply_len = 0; | |
| 195 | + int ret; | |
| 196 | + | |
| 197 | + req_info = kzalloc(sizeof(*req_info), GFP_KERNEL); | |
| 198 | + if (!req_info) | |
| 199 | + return -ENOMEM; | |
| 200 | + reply_data = kmalloc(sizeof(*reply_data), GFP_KERNEL); | |
| 201 | + if (!reply_data) { | |
| 202 | + kfree(req_info); | |
| 203 | + return -ENOMEM; | |
| 204 | + } | |
| 205 | + | |
| 206 | + ASSERT_RTNL(); | |
| 207 | + reply_data->base.dev = dev; | |
| 208 | + ret = tsconfig_prepare_data(&req_info->base, &reply_data->base, info); | |
| 209 | + if (ret < 0) | |
| 210 | + goto err_cleanup; | |
| 211 | + | |
| 212 | + ret = tsconfig_reply_size(&req_info->base, &reply_data->base); | |
| 213 | + if (ret < 0) | |
| 214 | + goto err_cleanup; | |
| 215 | + | |
| 216 | + reply_len = ret + ethnl_reply_header_size(); | |
| 217 | + rskb = ethnl_reply_init(reply_len, dev, ETHTOOL_MSG_TSCONFIG_SET_REPLY, | |
| 218 | + ETHTOOL_A_TSCONFIG_HEADER, info, &reply_payload); | |
| 219 | + if (!rskb) | |
| 220 | + goto err_cleanup; | |
| 221 | + | |
| 222 | + ret = tsconfig_fill_reply(rskb, &req_info->base, &reply_data->base); | |
| 223 | + if (ret < 0) | |
| 224 | + goto err_cleanup; | |
| 225 | + | |
| 226 | + genlmsg_end(rskb, reply_payload); | |
| 227 | + ret = genlmsg_reply(rskb, info); | |
| 228 | + | |
| 229 | +err_cleanup: | |
| 230 | + kfree(reply_data); | |
| 231 | + kfree(req_info); | |
| 232 | + return ret; | |
| 233 | +} | |
| 234 | + | |
| 235 | +static int ethnl_set_tsconfig_validate(struct ethnl_req_info *req_base, | |
| 236 | + struct genl_info *info) | |
| 237 | +{ | |
| 238 | + const struct net_device_ops *ops = req_base->dev->netdev_ops; | |
| 239 | + | |
| 240 | + if (!ops->ndo_hwtstamp_set || !ops->ndo_hwtstamp_get) | |
| 241 | + return -EOPNOTSUPP; | |
| 242 | + | |
| 243 | + return 1; | |
| 244 | +} | |
| 245 | + | |
| 246 | +static struct hwtstamp_provider * | |
| 247 | +tsconfig_set_hwprov_from_desc(struct net_device *dev, | |
| 248 | + struct genl_info *info, | |
| 249 | + struct hwtstamp_provider_desc *hwprov_desc) | |
| 250 | +{ | |
| 251 | + struct kernel_ethtool_ts_info ts_info; | |
| 252 | + struct hwtstamp_provider *hwprov; | |
| 253 | + struct nlattr **tb = info->attrs; | |
| 254 | + struct phy_device *phy = NULL; | |
| 255 | + enum hwtstamp_source source; | |
| 256 | + int ret; | |
| 257 | + | |
| 258 | + ret = ethtool_net_get_ts_info_by_phc(dev, &ts_info, hwprov_desc); | |
| 259 | + if (!ret) { | |
| 260 | + /* Found */ | |
| 261 | + source = HWTSTAMP_SOURCE_NETDEV; | |
| 262 | + } else { | |
| 263 | + phy = ethtool_phy_get_ts_info_by_phc(dev, &ts_info, hwprov_desc); | |
| 264 | + if (IS_ERR(phy)) { | |
| 265 | + if (PTR_ERR(phy) == -ENODEV) | |
| 266 | + NL_SET_ERR_MSG_ATTR(info->extack, | |
| 267 | + tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER], | |
| 268 | + "phc not in this net device topology"); | |
| 269 | + return ERR_CAST(phy); | |
| 270 | + } | |
| 271 | + | |
| 272 | + source = HWTSTAMP_SOURCE_PHYLIB; | |
| 273 | + } | |
| 274 | + | |
| 275 | + hwprov = kzalloc(sizeof(*hwprov), GFP_KERNEL); | |
| 276 | + if (!hwprov) | |
| 277 | + return ERR_PTR(-ENOMEM); | |
| 278 | + | |
| 279 | + hwprov->desc.index = hwprov_desc->index; | |
| 280 | + hwprov->desc.qualifier = hwprov_desc->qualifier; | |
| 281 | + hwprov->source = source; | |
| 282 | + hwprov->phydev = phy; | |
| 283 | + | |
| 284 | + return hwprov; | |
| 285 | +} | |
| 286 | + | |
| 287 | +static int ethnl_set_tsconfig(struct ethnl_req_info *req_base, | |
| 288 | + struct genl_info *info) | |
| 289 | +{ | |
| 290 | + struct kernel_hwtstamp_config hwtst_config = {0}; | |
| 291 | + bool hwprov_mod = false, config_mod = false; | |
| 292 | + struct hwtstamp_provider *hwprov = NULL; | |
| 293 | + struct net_device *dev = req_base->dev; | |
| 294 | + struct nlattr **tb = info->attrs; | |
| 295 | + int ret; | |
| 296 | + | |
| 297 | + BUILD_BUG_ON(__HWTSTAMP_TX_CNT >= 32); | |
| 298 | + BUILD_BUG_ON(__HWTSTAMP_FILTER_CNT >= 32); | |
| 299 | + | |
| 300 | + if (!netif_device_present(dev)) | |
| 301 | + return -ENODEV; | |
| 302 | + | |
| 303 | + if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER]) { | |
| 304 | + struct hwtstamp_provider_desc __hwprov_desc = {.index = -1}; | |
| 305 | + struct hwtstamp_provider *__hwprov; | |
| 306 | + | |
| 307 | + __hwprov = rtnl_dereference(dev->hwprov); | |
| 308 | + if (__hwprov) { | |
| 309 | + __hwprov_desc.index = __hwprov->desc.index; | |
| 310 | + __hwprov_desc.qualifier = __hwprov->desc.qualifier; | |
| 311 | + } | |
| 312 | + | |
| 313 | + ret = ts_parse_hwtst_provider(tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER], | |
| 314 | + &__hwprov_desc, info->extack, | |
| 315 | + &hwprov_mod); | |
| 316 | + if (ret < 0) | |
| 317 | + return ret; | |
| 318 | + | |
| 319 | + if (hwprov_mod) { | |
| 320 | + hwprov = tsconfig_set_hwprov_from_desc(dev, info, | |
| 321 | + &__hwprov_desc); | |
| 322 | + if (IS_ERR(hwprov)) | |
| 323 | + return PTR_ERR(hwprov); | |
| 324 | + } | |
| 325 | + } | |
| 326 | + | |
| 327 | + /* Get current hwtstamp config if we are not changing the | |
| 328 | + * hwtstamp source. It will be zeroed in the other case. | |
| 329 | + */ | |
| 330 | + if (!hwprov_mod) { | |
| 331 | + ret = dev_get_hwtstamp_phylib(dev, &hwtst_config); | |
| 332 | + if (ret < 0 && ret != -EOPNOTSUPP) | |
| 333 | + goto err_free_hwprov; | |
| 334 | + } | |
| 335 | + | |
| 336 | + /* Get the hwtstamp config from netlink */ | |
| 337 | + if (tb[ETHTOOL_A_TSCONFIG_TX_TYPES]) { | |
| 338 | + u32 req_tx_type; | |
| 339 | + | |
| 340 | + req_tx_type = BIT(hwtst_config.tx_type); | |
| 341 | + ret = ethnl_update_bitset32(&req_tx_type, | |
| 342 | + __HWTSTAMP_TX_CNT, | |
| 343 | + tb[ETHTOOL_A_TSCONFIG_TX_TYPES], | |
| 344 | + ts_tx_type_names, info->extack, | |
| 345 | + &config_mod); | |
| 346 | + if (ret < 0) | |
| 347 | + goto err_free_hwprov; | |
| 348 | + | |
| 349 | + /* Select only one tx type at a time */ | |
| 350 | + if (ffs(req_tx_type) != fls(req_tx_type)) { | |
| 351 | + ret = -EINVAL; | |
| 352 | + goto err_free_hwprov; | |
| 353 | + } | |
| 354 | + | |
| 355 | + hwtst_config.tx_type = ffs(req_tx_type) - 1; | |
| 356 | + } | |
| 357 | + | |
| 358 | + if (tb[ETHTOOL_A_TSCONFIG_RX_FILTERS]) { | |
| 359 | + u32 req_rx_filter; | |
| 360 | + | |
| 361 | + req_rx_filter = BIT(hwtst_config.rx_filter); | |
| 362 | + ret = ethnl_update_bitset32(&req_rx_filter, | |
| 363 | + __HWTSTAMP_FILTER_CNT, | |
| 364 | + tb[ETHTOOL_A_TSCONFIG_RX_FILTERS], | |
| 365 | + ts_rx_filter_names, info->extack, | |
| 366 | + &config_mod); | |
| 367 | + if (ret < 0) | |
| 368 | + goto err_free_hwprov; | |
| 369 | + | |
| 370 | + /* Select only one rx filter at a time */ | |
| 371 | + if (ffs(req_rx_filter) != fls(req_rx_filter)) { | |
| 372 | + ret = -EINVAL; | |
| 373 | + goto err_free_hwprov; | |
| 374 | + } | |
| 375 | + | |
| 376 | + hwtst_config.rx_filter = ffs(req_rx_filter) - 1; | |
| 377 | + } | |
| 378 | + | |
| 379 | + if (tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS]) { | |
| 380 | + ethnl_update_u32(&hwtst_config.flags, | |
| 381 | + tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS], | |
| 382 | + &config_mod); | |
| 383 | + } | |
| 384 | + | |
| 385 | + ret = net_hwtstamp_validate(&hwtst_config); | |
| 386 | + if (ret) | |
| 387 | + goto err_free_hwprov; | |
| 388 | + | |
| 389 | + if (hwprov_mod) { | |
| 390 | + struct kernel_hwtstamp_config zero_config = {0}; | |
| 391 | + struct hwtstamp_provider *__hwprov; | |
| 392 | + | |
| 393 | + /* Disable current time stamping if we try to enable | |
| 394 | + * another one | |
| 395 | + */ | |
| 396 | + ret = dev_set_hwtstamp_phylib(dev, &zero_config, info->extack); | |
| 397 | + if (ret < 0) | |
| 398 | + goto err_free_hwprov; | |
| 399 | + | |
| 400 | + /* Change the selected hwtstamp source */ | |
| 401 | + __hwprov = rcu_replace_pointer_rtnl(dev->hwprov, hwprov); | |
| 402 | + if (__hwprov) | |
| 403 | + kfree_rcu(__hwprov, rcu_head); | |
| 404 | + } | |
| 405 | + | |
| 406 | + if (config_mod) { | |
| 407 | + ret = dev_set_hwtstamp_phylib(dev, &hwtst_config, | |
| 408 | + info->extack); | |
| 409 | + if (ret < 0) | |
| 410 | + return ret; | |
| 411 | + } | |
| 412 | + | |
| 413 | + if (hwprov_mod || config_mod) { | |
| 414 | + ret = tsconfig_send_reply(dev, info); | |
| 415 | + if (ret && ret != -EOPNOTSUPP) { | |
| 416 | + NL_SET_ERR_MSG(info->extack, | |
| 417 | + "error while reading the new configuration set"); | |
| 418 | + return ret; | |
| 419 | + } | |
| 420 | + } | |
| 421 | + | |
| 422 | + /* tsconfig has no notification */ | |
| 423 | + return 0; | |
| 424 | + | |
| 425 | +err_free_hwprov: | |
| 426 | + kfree(hwprov); | |
| 427 | + | |
| 428 | + return ret; | |
| 429 | +} | |
| 430 | + | |
| 431 | +const struct ethnl_request_ops ethnl_tsconfig_request_ops = { | |
| 432 | + .request_cmd = ETHTOOL_MSG_TSCONFIG_GET, | |
| 433 | + .reply_cmd = ETHTOOL_MSG_TSCONFIG_GET_REPLY, | |
| 434 | + .hdr_attr = ETHTOOL_A_TSCONFIG_HEADER, | |
| 435 | + .req_info_size = sizeof(struct tsconfig_req_info), | |
| 436 | + .reply_data_size = sizeof(struct tsconfig_reply_data), | |
| 437 | + | |
| 438 | + .prepare_data = tsconfig_prepare_data, | |
| 439 | + .reply_size = tsconfig_reply_size, | |
| 440 | + .fill_reply = tsconfig_fill_reply, | |
| 441 | + | |
| 442 | + .set_validate = ethnl_set_tsconfig_validate, | |
| 443 | + .set = ethnl_set_tsconfig, | |
| 444 | +}; | |