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 | name: downstream-sfp-name | 1490 | name: downstream-sfp-name |
| 1491 | type: string | 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 | operations: | 1520 | operations: |
| 1494 | enum-model: directional | 1521 | enum-model: directional |
| @@ -2314,3 +2341,32 @@ operations: · 819 unmodified lines | |||
| 2314 | name: phy-ntf | 2341 | name: phy-ntf |
| 2315 | doc: Notification for change in PHY devices. | 2342 | doc: Notification for change in PHY devices. |
| 2316 | notify: phy-get | 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 | ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters | 237 | ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters |
| 238 | ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware | 238 | ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` flash transceiver module firmware |
| 239 | ``ETHTOOL_MSG_PHY_GET`` get Ethernet PHY information | 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 | Kernel to userspace: | 244 | Kernel to userspace: |
| @@ -286,6 +288,8 @@ Kernel to userspace: · 43 unmodified lines | |||
| 286 | ``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates | 288 | ``ETHTOOL_MSG_MODULE_FW_FLASH_NTF`` transceiver module flash updates |
| 287 | ``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information | 289 | ``ETHTOOL_MSG_PHY_GET_REPLY`` Ethernet PHY information |
| 288 | ``ETHTOOL_MSG_PHY_NTF`` Ethernet PHY information change | 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 | ``GET`` requests are sent by userspace applications to retrieve device | 295 | ``GET`` requests are sent by userspace applications to retrieve device |
| @@ -2244,6 +2248,75 @@ Kernel response contents: · 1952 unmodified lines | |||
| 2244 | When ``ETHTOOL_A_PHY_UPSTREAM_TYPE`` is PHY_UPSTREAM_PHY, the PHY's parent is | 2248 | When ``ETHTOOL_A_PHY_UPSTREAM_TYPE`` is PHY_UPSTREAM_PHY, the PHY's parent is |
| 2245 | another PHY. | 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 | Request translation | 2320 | Request translation |
| 2248 | =================== | 2321 | =================== |
| 2249 | 2322 | ||
| @@ -2352,4 +2425,6 @@ are netlink only. · 102 unmodified lines | |||
| 2352 | n/a ``ETHTOOL_MSG_MM_SET`` | 2425 | n/a ``ETHTOOL_MSG_MM_SET`` |
| 2353 | n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` | 2426 | n/a ``ETHTOOL_MSG_MODULE_FW_FLASH_ACT`` |
| 2354 | n/a ``ETHTOOL_MSG_PHY_GET`` | 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 | is again deprecated and ts[2] holds a hardware timestamp if set. | 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 | 528 | 3. Hardware Timestamping configuration: ETHTOOL_MSG_TSCONFIG_SET/GET |
| 529 | ======================================================================= | 529 | ==================================================================== |
| 530 | 530 | ||
| 531 | Hardware time stamping must also be initialized for each device driver | 531 | Hardware time stamping must also be initialized for each device driver |
| 532 | that is expected to do hardware time stamping. The parameter is defined in | 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 | Desired behavior is passed into the kernel and to a specific device by | 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 | 542 | calling the tsconfig netlink socket ``ETHTOOL_MSG_TSCONFIG_SET``. |
| 543 | ifr_data points to a struct hwtstamp_config. The tx_type and | 543 | The ``ETHTOOL_A_TSCONFIG_TX_TYPES``, ``ETHTOOL_A_TSCONFIG_RX_FILTERS`` and |
| 544 | rx_filter are hints to the driver what it is expected to do. If | 544 | ``ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS`` netlink attributes are then used to set |
| 545 | the requested fine-grained filtering for incoming packets is not | 545 | the struct hwtstamp_config accordingly. |
| 546 | supported, the driver may time stamp more than just the requested types | 546 | |
| 547 | of packets. | 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 | Drivers are free to use a more permissive configuration than the requested | 551 | Drivers are free to use a more permissive configuration than the requested |
| 550 | configuration. It is expected that drivers should only implement directly the | 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 | space is responsible to ensure that multiple processes don't interfere | 565 | space is responsible to ensure that multiple processes don't interfere |
| 564 | with each other and that the settings are reset. | 566 | with each other and that the settings are reset. |
| 565 | 567 | ||
| 566 | Any process can read the actual configuration by passing this | 568 | Any process can read the actual configuration by requesting tsconfig netlink |
| 567 | structure to ioctl(SIOCGHWTSTAMP) in the same way. However, this has | 569 | socket ``ETHTOOL_MSG_TSCONFIG_GET``. |
| 568 | not been implemented in all drivers. | 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 | A driver which supports hardware time stamping must support the | 621 | A driver which supports hardware time stamping must support the |
| 613 | SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with | 622 | ndo_hwtstamp_set NDO or the legacy SIOCSHWTSTAMP ioctl and update the |
| 614 | the actual values as described in the section on SIOCSHWTSTAMP. It | 623 | supplied struct hwtstamp_config with the actual values as described in |
| 615 | should also support SIOCGHWTSTAMP. | 624 | the section on SIOCSHWTSTAMP. It should also support ndo_hwtstamp_get or |
| 625 | the legacy SIOCGHWTSTAMP. | ||
| 616 | 626 | ||
| 617 | Time stamps for received packets must be stored in the skb. To get a pointer | 627 | Time stamps for received packets must be stored in the skb. To get a pointer |
| 618 | to the shared time stamp structure of the skb call skb_hwtstamps(). Then | 628 | to the shared time stamp structure of the skb call skb_hwtstamps(). Then |
| @@ -694,6 +694,18 @@ enum { · 693 unmodified lines | |||
| 694 | ETHTOOL_A_PHY_MAX = (__ETHTOOL_A_PHY_CNT - 1) | 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 | enum { | 709 | enum { |
| 698 | ETHTOOL_MSG_USER_NONE = 0, | 710 | ETHTOOL_MSG_USER_NONE = 0, |
| 699 | ETHTOOL_MSG_STRSET_GET = 1, | 711 | ETHTOOL_MSG_STRSET_GET = 1, |
| @@ -741,6 +753,8 @@ enum { · 41 unmodified lines | |||
| 741 | ETHTOOL_MSG_MM_SET, | 753 | ETHTOOL_MSG_MM_SET, |
| 742 | ETHTOOL_MSG_MODULE_FW_FLASH_ACT, | 754 | ETHTOOL_MSG_MODULE_FW_FLASH_ACT, |
| 743 | ETHTOOL_MSG_PHY_GET, | 755 | ETHTOOL_MSG_PHY_GET, |
| 756 | ETHTOOL_MSG_TSCONFIG_GET, | ||
| 757 | ETHTOOL_MSG_TSCONFIG_SET, | ||
| 744 | 758 | ||
| 745 | __ETHTOOL_MSG_USER_CNT, | 759 | __ETHTOOL_MSG_USER_CNT, |
| 746 | ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1) | 760 | ETHTOOL_MSG_USER_MAX = (__ETHTOOL_MSG_USER_CNT - 1) |
| @@ -794,6 +808,8 @@ enum { · 47 unmodified lines | |||
| 794 | ETHTOOL_MSG_MODULE_FW_FLASH_NTF, | 808 | ETHTOOL_MSG_MODULE_FW_FLASH_NTF, |
| 795 | ETHTOOL_MSG_PHY_GET_REPLY, | 809 | ETHTOOL_MSG_PHY_GET_REPLY, |
| 796 | ETHTOOL_MSG_PHY_NTF, | 810 | ETHTOOL_MSG_PHY_NTF, |
| 811 | ETHTOOL_MSG_TSCONFIG_GET_REPLY, | ||
| 812 | ETHTOOL_MSG_TSCONFIG_SET_REPLY, | ||
| 797 | 813 | ||
| 798 | __ETHTOOL_MSG_KERNEL_CNT, | 814 | __ETHTOOL_MSG_KERNEL_CNT, |
| 799 | ETHTOOL_MSG_KERNEL_MAX = (__ETHTOOL_MSG_KERNEL_CNT - 1) | 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 | channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ | 9 | channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \ |
| 10 | tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \ | 10 | tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \ |
| 11 | module.o cmis_fw_update.o cmis_cdb.o pse-pd.o plca.o mm.o \ | 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 | return -ENODEV; | 797 | return -ENODEV; |
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | int | 800 | struct phy_device * |
| 801 | ethtool_phy_get_ts_info_by_phc(struct net_device *dev, | 801 | ethtool_phy_get_ts_info_by_phc(struct net_device *dev, |
| 802 | struct kernel_ethtool_ts_info *info, | 802 | struct kernel_ethtool_ts_info *info, |
| 803 | struct hwtstamp_provider_desc *hwprov_desc) | 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 | /* Only precise qualifier is supported in phydev */ | 807 | /* Only precise qualifier is supported in phydev */ |
| 808 | if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE) | 808 | if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE) |
| 809 | return -ENODEV; | 809 | return ERR_PTR(-ENODEV); |
| 810 | 810 | ||
| 811 | /* Look in the phy topology */ | 811 | /* Look in the phy topology */ |
| 812 | if (dev->link_topo) { | 812 | if (dev->link_topo) { |
| @@ -820,12 +820,12 @@ ethtool_phy_get_ts_info_by_phc(struct net_device *dev, · 7 unmodified lines | |||
| 820 | ethtool_init_tsinfo(info); | 820 | ethtool_init_tsinfo(info); |
| 821 | err = phy_ts_info(pdn->phy, info); | 821 | err = phy_ts_info(pdn->phy, info); |
| 822 | if (err) | 822 | if (err) |
| 823 | return err; | 823 | return ERR_PTR(err); |
| 824 | 824 | ||
| 825 | if (info->phc_index == hwprov_desc->index) | 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 | /* Look on the dev->phydev */ | 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 | ethtool_init_tsinfo(info); | 833 | ethtool_init_tsinfo(info); |
| 834 | err = phy_ts_info(dev->phydev, info); | 834 | err = phy_ts_info(dev->phydev, info); |
| 835 | if (err) | 835 | if (err) |
| 836 | return err; | 836 | return ERR_PTR(err); |
| 837 | 837 | ||
| 838 | if (info->phc_index == hwprov_desc->index) | 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 | int ethtool_get_ts_info_by_phc(struct net_device *dev, | 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 | int err; | 849 | int err; |
| 850 | 850 | ||
| 851 | err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc); | 851 | err = ethtool_net_get_ts_info_by_phc(dev, info, hwprov_desc); |
| 852 | if (err == -ENODEV) | 852 | if (err == -ENODEV) { |
| 853 | err = ethtool_phy_get_ts_info_by_phc(dev, info, hwprov_desc); | 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 | info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE | | 862 | info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE | |
| 856 | SOF_TIMESTAMPING_SOFTWARE; | 863 | SOF_TIMESTAMPING_SOFTWARE; |
| @@ -56,7 +56,7 @@ int ethtool_get_ts_info_by_phc(struct net_device *dev, · 55 unmodified lines | |||
| 56 | int ethtool_net_get_ts_info_by_phc(struct net_device *dev, | 56 | int ethtool_net_get_ts_info_by_phc(struct net_device *dev, |
| 57 | struct kernel_ethtool_ts_info *info, | 57 | struct kernel_ethtool_ts_info *info, |
| 58 | struct hwtstamp_provider_desc *hwprov_desc); | 58 | struct hwtstamp_provider_desc *hwprov_desc); |
| 59 | int | 59 | struct phy_device * |
| 60 | ethtool_phy_get_ts_info_by_phc(struct net_device *dev, | 60 | ethtool_phy_get_ts_info_by_phc(struct net_device *dev, |
| 61 | struct kernel_ethtool_ts_info *info, | 61 | struct kernel_ethtool_ts_info *info, |
| 62 | struct hwtstamp_provider_desc *hwprov_desc); | 62 | struct hwtstamp_provider_desc *hwprov_desc); |
| @@ -394,6 +394,8 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = { · 393 unmodified lines | |||
| 394 | [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops, | 394 | [ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops, |
| 395 | [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops, | 395 | [ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops, |
| 396 | [ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops, | 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 | static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) | 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 | .policy = ethnl_phy_get_policy, | 1245 | .policy = ethnl_phy_get_policy, |
| 1244 | .maxattr = ARRAY_SIZE(ethnl_phy_get_policy) - 1, | 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 | static const struct genl_multicast_group ethtool_nl_mcgrps[] = { | 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 | extern const struct ethnl_request_ops ethnl_plca_status_request_ops; | 435 | extern const struct ethnl_request_ops ethnl_plca_status_request_ops; |
| 436 | extern const struct ethnl_request_ops ethnl_mm_request_ops; | 436 | extern const struct ethnl_request_ops ethnl_mm_request_ops; |
| 437 | extern const struct ethnl_request_ops ethnl_phy_request_ops; | 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 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; | 440 | extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; |
| 440 | extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; | 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 | extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; | 486 | extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1]; |
| 486 | extern const struct nla_policy ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1]; | 487 | extern const struct nla_policy ethnl_module_fw_flash_act_policy[ETHTOOL_A_MODULE_FW_FLASH_PASSWORD + 1]; |
| 487 | extern const struct nla_policy ethnl_phy_get_policy[ETHTOOL_A_PHY_HEADER + 1]; | 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 | int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); | 492 | int ethnl_set_features(struct sk_buff *skb, struct genl_info *info); |
| 490 | int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info); | 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 | }; | ||