|
5 | 5 | #include <linux/phy.h> |
6 | 6 | #include <linux/rtnetlink.h> |
7 | 7 | #include <linux/ptp_clock_kernel.h> |
| 8 | +#include <linux/phy_link_topology.h> |
8 | 9 |
|
9 | 10 | #include "netlink.h" |
10 | 11 | #include "common.h" |
| 12 | +#include "../core/dev.h" |
| 13 | + |
11 | 14 |
|
12 | 15 | const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = { |
13 | 16 | [NETIF_F_SG_BIT] = "tx-scatter-gather", |
@@ -763,27 +766,147 @@ int ethtool_check_ops(const struct ethtool_ops *ops) |
763 | 766 | return 0; |
764 | 767 | } |
765 | 768 |
|
766 | | -int __ethtool_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info) |
| 769 | +static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info) |
767 | 770 | { |
768 | | - const struct ethtool_ops *ops = dev->ethtool_ops; |
769 | | - struct phy_device *phydev = dev->phydev; |
770 | | - int err = 0; |
771 | | - |
772 | 771 | memset(info, 0, sizeof(*info)); |
773 | 772 | info->cmd = ETHTOOL_GET_TS_INFO; |
774 | 773 | info->phc_index = -1; |
| 774 | +} |
| 775 | + |
| 776 | +int ethtool_net_get_ts_info_by_phc(struct net_device *dev, |
| 777 | + struct kernel_ethtool_ts_info *info, |
| 778 | + struct hwtstamp_provider_desc *hwprov_desc) |
| 779 | +{ |
| 780 | + const struct ethtool_ops *ops = dev->ethtool_ops; |
| 781 | + int err; |
| 782 | + |
| 783 | + if (!ops->get_ts_info) |
| 784 | + return -ENODEV; |
| 785 | + |
| 786 | + /* Does ptp comes from netdev */ |
| 787 | + ethtool_init_tsinfo(info); |
| 788 | + info->phc_qualifier = hwprov_desc->qualifier; |
| 789 | + err = ops->get_ts_info(dev, info); |
| 790 | + if (err) |
| 791 | + return err; |
| 792 | + |
| 793 | + if (info->phc_index == hwprov_desc->index && |
| 794 | + net_support_hwtstamp_qualifier(dev, hwprov_desc->qualifier)) |
| 795 | + return 0; |
| 796 | + |
| 797 | + return -ENODEV; |
| 798 | +} |
| 799 | + |
| 800 | +int |
| 801 | +ethtool_phy_get_ts_info_by_phc(struct net_device *dev, |
| 802 | + struct kernel_ethtool_ts_info *info, |
| 803 | + struct hwtstamp_provider_desc *hwprov_desc) |
| 804 | +{ |
| 805 | + int err; |
| 806 | + |
| 807 | + /* Only precise qualifier is supported in phydev */ |
| 808 | + if (hwprov_desc->qualifier != HWTSTAMP_PROVIDER_QUALIFIER_PRECISE) |
| 809 | + return -ENODEV; |
| 810 | + |
| 811 | + /* Look in the phy topology */ |
| 812 | + if (dev->link_topo) { |
| 813 | + struct phy_device_node *pdn; |
| 814 | + unsigned long phy_index; |
| 815 | + |
| 816 | + xa_for_each(&dev->link_topo->phys, phy_index, pdn) { |
| 817 | + if (!phy_has_tsinfo(pdn->phy)) |
| 818 | + continue; |
| 819 | + |
| 820 | + ethtool_init_tsinfo(info); |
| 821 | + err = phy_ts_info(pdn->phy, info); |
| 822 | + if (err) |
| 823 | + return err; |
| 824 | + |
| 825 | + if (info->phc_index == hwprov_desc->index) |
| 826 | + return 0; |
| 827 | + } |
| 828 | + return -ENODEV; |
| 829 | + } |
| 830 | + |
| 831 | + /* Look on the dev->phydev */ |
| 832 | + if (phy_has_tsinfo(dev->phydev)) { |
| 833 | + ethtool_init_tsinfo(info); |
| 834 | + err = phy_ts_info(dev->phydev, info); |
| 835 | + if (err) |
| 836 | + return err; |
| 837 | + |
| 838 | + if (info->phc_index == hwprov_desc->index) |
| 839 | + return 0; |
| 840 | + } |
| 841 | + |
| 842 | + return -ENODEV; |
| 843 | +} |
| 844 | + |
| 845 | +int ethtool_get_ts_info_by_phc(struct net_device *dev, |
| 846 | + struct kernel_ethtool_ts_info *info, |
| 847 | + struct hwtstamp_provider_desc *hwprov_desc) |
| 848 | +{ |
| 849 | + int err; |
775 | 850 |
|
776 | | - if (phy_is_default_hwtstamp(phydev) && phy_has_tsinfo(phydev)) |
777 | | - err = phy_ts_info(phydev, info); |
778 | | - else if (ops->get_ts_info) |
779 | | - err = ops->get_ts_info(dev, info); |
| 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); |
780 | 854 |
|
781 | 855 | info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE | |
782 | 856 | SOF_TIMESTAMPING_SOFTWARE; |
783 | 857 |
|
784 | 858 | return err; |
785 | 859 | } |
786 | 860 |
|
| 861 | +int __ethtool_get_ts_info(struct net_device *dev, |
| 862 | + struct kernel_ethtool_ts_info *info) |
| 863 | +{ |
| 864 | + struct hwtstamp_provider *hwprov; |
| 865 | + |
| 866 | + hwprov = rtnl_dereference(dev->hwprov); |
| 867 | + /* No provider specified, use default behavior */ |
| 868 | + if (!hwprov) { |
| 869 | + const struct ethtool_ops *ops = dev->ethtool_ops; |
| 870 | + struct phy_device *phydev = dev->phydev; |
| 871 | + int err = 0; |
| 872 | + |
| 873 | + ethtool_init_tsinfo(info); |
| 874 | + if (phy_is_default_hwtstamp(phydev) && |
| 875 | + phy_has_tsinfo(phydev)) |
| 876 | + err = phy_ts_info(phydev, info); |
| 877 | + else if (ops->get_ts_info) |
| 878 | + err = ops->get_ts_info(dev, info); |
| 879 | + |
| 880 | + info->so_timestamping |= SOF_TIMESTAMPING_RX_SOFTWARE | |
| 881 | + SOF_TIMESTAMPING_SOFTWARE; |
| 882 | + |
| 883 | + return err; |
| 884 | + } |
| 885 | + |
| 886 | + return ethtool_get_ts_info_by_phc(dev, info, &hwprov->desc); |
| 887 | +} |
| 888 | + |
| 889 | +bool net_support_hwtstamp_qualifier(struct net_device *dev, |
| 890 | + enum hwtstamp_provider_qualifier qualifier) |
| 891 | +{ |
| 892 | + const struct ethtool_ops *ops = dev->ethtool_ops; |
| 893 | + |
| 894 | + if (!ops) |
| 895 | + return false; |
| 896 | + |
| 897 | + /* Return true with precise qualifier and with NIC without |
| 898 | + * qualifier description to not break the old behavior. |
| 899 | + */ |
| 900 | + if (!ops->supported_hwtstamp_qualifiers && |
| 901 | + qualifier == HWTSTAMP_PROVIDER_QUALIFIER_PRECISE) |
| 902 | + return true; |
| 903 | + |
| 904 | + if (ops->supported_hwtstamp_qualifiers & BIT(qualifier)) |
| 905 | + return true; |
| 906 | + |
| 907 | + return false; |
| 908 | +} |
| 909 | + |
787 | 910 | int ethtool_get_phc_vclocks(struct net_device *dev, int **vclock_index) |
788 | 911 | { |
789 | 912 | struct kernel_ethtool_ts_info info = { }; |
|
0 commit comments