diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/enetc/enetc_ethtool.c')
-rw-r--r-- | drivers/net/ethernet/freescale/enetc/enetc_ethtool.c | 86 |
1 files changed, 73 insertions, 13 deletions
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index 961e76cd8489..71d052de669a 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -4,6 +4,9 @@ #include <linux/ethtool_netlink.h> #include <linux/net_tstamp.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/ptp_clock_kernel.h> + #include "enetc.h" static const u32 enetc_si_regs[] = { @@ -877,23 +880,58 @@ static int enetc_set_coalesce(struct net_device *ndev, return 0; } -static int enetc_get_ts_info(struct net_device *ndev, - struct kernel_ethtool_ts_info *info) +static int enetc_get_phc_index_by_pdev(struct enetc_si *si) { - struct enetc_ndev_priv *priv = netdev_priv(ndev); - int *phc_idx; - - phc_idx = symbol_get(enetc_phc_index); - if (phc_idx) { - info->phc_index = *phc_idx; - symbol_put(enetc_phc_index); + struct pci_bus *bus = si->pdev->bus; + struct pci_dev *timer_pdev; + unsigned int devfn; + int phc_index; + + switch (si->revision) { + case ENETC_REV_1_0: + devfn = PCI_DEVFN(0, 4); + break; + case ENETC_REV_4_1: + devfn = PCI_DEVFN(24, 0); + break; + default: + return -1; } - if (!IS_ENABLED(CONFIG_FSL_ENETC_PTP_CLOCK)) { - info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE; + timer_pdev = pci_get_domain_bus_and_slot(pci_domain_nr(bus), + bus->number, devfn); + if (!timer_pdev) + return -1; - return 0; - } + phc_index = ptp_clock_index_by_dev(&timer_pdev->dev); + pci_dev_put(timer_pdev); + + return phc_index; +} + +static int enetc_get_phc_index(struct enetc_si *si) +{ + struct device_node *np = si->pdev->dev.of_node; + struct device_node *timer_np; + int phc_index; + + if (!np) + return enetc_get_phc_index_by_pdev(si); + + timer_np = of_parse_phandle(np, "ptp-timer", 0); + if (!timer_np) + return enetc_get_phc_index_by_pdev(si); + + phc_index = ptp_clock_index_by_of_node(timer_np); + of_node_put(timer_np); + + return phc_index; +} + +static void enetc_get_ts_generic_info(struct net_device *ndev, + struct kernel_ethtool_ts_info *info) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | @@ -908,6 +946,27 @@ static int enetc_get_ts_info(struct net_device *ndev, info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_ALL); +} + +static int enetc_get_ts_info(struct net_device *ndev, + struct kernel_ethtool_ts_info *info) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_si *si = priv->si; + + if (!enetc_ptp_clock_is_enabled(si)) + goto timestamp_tx_sw; + + info->phc_index = enetc_get_phc_index(si); + if (info->phc_index < 0) + goto timestamp_tx_sw; + + enetc_get_ts_generic_info(ndev, info); + + return 0; + +timestamp_tx_sw: + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE; return 0; } @@ -1296,6 +1355,7 @@ const struct ethtool_ops enetc4_pf_ethtool_ops = { .get_rxfh = enetc_get_rxfh, .set_rxfh = enetc_set_rxfh, .get_rxfh_fields = enetc_get_rxfh_fields, + .get_ts_info = enetc_get_ts_info, }; void enetc_set_ethtool_ops(struct net_device *ndev) |