diff options
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 | ||||
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c | 35 | ||||
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h | 7 | ||||
| -rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 66 | ||||
| -rw-r--r-- | tools/testing/selftests/drivers/net/hw/Makefile | 1 | ||||
| -rwxr-xr-x | tools/testing/selftests/drivers/net/hw/nic_timestamp.py | 113 |
6 files changed, 166 insertions, 64 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d59612d1e176..1d0e0e7362bd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -13278,12 +13278,6 @@ static int bnxt_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return bnxt_hwrm_port_phy_write(bp, mdio->phy_id, mdio->reg_num, mdio->val_in); - case SIOCSHWTSTAMP: - return bnxt_hwtstamp_set(dev, ifr); - - case SIOCGHWTSTAMP: - return bnxt_hwtstamp_get(dev, ifr); - default: /* do nothing */ break; @@ -15806,6 +15800,8 @@ static const struct net_device_ops bnxt_netdev_ops = { .ndo_xdp_xmit = bnxt_xdp_xmit, .ndo_bridge_getlink = bnxt_bridge_getlink, .ndo_bridge_setlink = bnxt_bridge_setlink, + .ndo_hwtstamp_get = bnxt_hwtstamp_get, + .ndo_hwtstamp_set = bnxt_hwtstamp_set, }; static void bnxt_get_queue_stats_rx(struct net_device *dev, int i, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c index ca660e6d28a4..db81cf6d5289 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c @@ -560,10 +560,11 @@ static int bnxt_hwrm_ptp_cfg(struct bnxt *bp) return bnxt_ptp_cfg_tstamp_filters(bp); } -int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) +int bnxt_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf, + struct netlink_ext_ack *extack) { struct bnxt *bp = netdev_priv(dev); - struct hwtstamp_config stmpconf; struct bnxt_ptp_cfg *ptp; u16 old_rxctl; int old_rx_filter, rc; @@ -573,17 +574,14 @@ int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) if (!ptp) return -EOPNOTSUPP; - if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf))) - return -EFAULT; - - if (stmpconf.tx_type != HWTSTAMP_TX_ON && - stmpconf.tx_type != HWTSTAMP_TX_OFF) + if (stmpconf->tx_type != HWTSTAMP_TX_ON && + stmpconf->tx_type != HWTSTAMP_TX_OFF) return -ERANGE; old_rx_filter = ptp->rx_filter; old_rxctl = ptp->rxctl; old_tx_tstamp_en = ptp->tx_tstamp_en; - switch (stmpconf.rx_filter) { + switch (stmpconf->rx_filter) { case HWTSTAMP_FILTER_NONE: ptp->rxctl = 0; ptp->rx_filter = HWTSTAMP_FILTER_NONE; @@ -616,7 +614,7 @@ int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) return -ERANGE; } - if (stmpconf.tx_type == HWTSTAMP_TX_ON) + if (stmpconf->tx_type == HWTSTAMP_TX_ON) ptp->tx_tstamp_en = 1; else ptp->tx_tstamp_en = 0; @@ -625,9 +623,8 @@ int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) if (rc) goto ts_set_err; - stmpconf.rx_filter = ptp->rx_filter; - return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ? - -EFAULT : 0; + stmpconf->rx_filter = ptp->rx_filter; + return 0; ts_set_err: ptp->rx_filter = old_rx_filter; @@ -636,22 +633,22 @@ ts_set_err: return rc; } -int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +int bnxt_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf) { struct bnxt *bp = netdev_priv(dev); - struct hwtstamp_config stmpconf; struct bnxt_ptp_cfg *ptp; ptp = bp->ptp_cfg; if (!ptp) return -EOPNOTSUPP; - stmpconf.flags = 0; - stmpconf.tx_type = ptp->tx_tstamp_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + stmpconf->flags = 0; + stmpconf->tx_type = ptp->tx_tstamp_en ? HWTSTAMP_TX_ON + : HWTSTAMP_TX_OFF; - stmpconf.rx_filter = ptp->rx_filter; - return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ? - -EFAULT : 0; + stmpconf->rx_filter = ptp->rx_filter; + return 0; } static int bnxt_map_regs(struct bnxt *bp, u32 *reg_arr, int count, int reg_win) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h index 0481161d26ef..8cc2fae47644 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.h @@ -160,8 +160,11 @@ void bnxt_ptp_update_current_time(struct bnxt *bp); void bnxt_ptp_pps_event(struct bnxt *bp, u32 data1, u32 data2); int bnxt_ptp_cfg_tstamp_filters(struct bnxt *bp); void bnxt_ptp_reapply_pps(struct bnxt *bp); -int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr); -int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr); +int bnxt_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf, + struct netlink_ext_ack *extack); +int bnxt_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf); void bnxt_ptp_free_txts_skbs(struct bnxt_ptp_cfg *ptp); int bnxt_ptp_get_txts_prod(struct bnxt_ptp_cfg *ptp, u16 *prod); void bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb, u16 prod); diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index b4dc93a48718..7f00ec7fd7b9 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -13929,22 +13929,20 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, } -static int tg3_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) +static int tg3_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf, + struct netlink_ext_ack *extack) { struct tg3 *tp = netdev_priv(dev); - struct hwtstamp_config stmpconf; if (!tg3_flag(tp, PTP_CAPABLE)) return -EOPNOTSUPP; - if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf))) - return -EFAULT; - - if (stmpconf.tx_type != HWTSTAMP_TX_ON && - stmpconf.tx_type != HWTSTAMP_TX_OFF) + if (stmpconf->tx_type != HWTSTAMP_TX_ON && + stmpconf->tx_type != HWTSTAMP_TX_OFF) return -ERANGE; - switch (stmpconf.rx_filter) { + switch (stmpconf->rx_filter) { case HWTSTAMP_FILTER_NONE: tp->rxptpctl = 0; break; @@ -14004,74 +14002,72 @@ static int tg3_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) tw32(TG3_RX_PTP_CTL, tp->rxptpctl | TG3_RX_PTP_CTL_HWTS_INTERLOCK); - if (stmpconf.tx_type == HWTSTAMP_TX_ON) + if (stmpconf->tx_type == HWTSTAMP_TX_ON) tg3_flag_set(tp, TX_TSTAMP_EN); else tg3_flag_clear(tp, TX_TSTAMP_EN); - return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ? - -EFAULT : 0; + return 0; } -static int tg3_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +static int tg3_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *stmpconf) { struct tg3 *tp = netdev_priv(dev); - struct hwtstamp_config stmpconf; if (!tg3_flag(tp, PTP_CAPABLE)) return -EOPNOTSUPP; - stmpconf.flags = 0; - stmpconf.tx_type = (tg3_flag(tp, TX_TSTAMP_EN) ? - HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF); + stmpconf->flags = 0; + stmpconf->tx_type = tg3_flag(tp, TX_TSTAMP_EN) ? + HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; switch (tp->rxptpctl) { case 0: - stmpconf.rx_filter = HWTSTAMP_FILTER_NONE; + stmpconf->rx_filter = HWTSTAMP_FILTER_NONE; break; case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_ALL_V1_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V1_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; break; case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_ALL_V2_EVENTS: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; break; case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_SYNC_EVNT: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; break; case TG3_RX_PTP_CTL_RX_PTP_V2_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L2_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ; break; case TG3_RX_PTP_CTL_RX_PTP_V2_L4_EN | TG3_RX_PTP_CTL_DELAY_REQ: - stmpconf.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; + stmpconf->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; break; default: WARN_ON_ONCE(1); return -ERANGE; } - return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ? - -EFAULT : 0; + return 0; } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -14126,12 +14122,6 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; - case SIOCSHWTSTAMP: - return tg3_hwtstamp_set(dev, ifr); - - case SIOCGHWTSTAMP: - return tg3_hwtstamp_get(dev, ifr); - default: /* do nothing */ break; @@ -14407,6 +14397,8 @@ static const struct net_device_ops tg3_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = tg3_poll_controller, #endif + .ndo_hwtstamp_get = tg3_hwtstamp_get, + .ndo_hwtstamp_set = tg3_hwtstamp_set, }; static void tg3_get_eeprom_size(struct tg3 *tp) diff --git a/tools/testing/selftests/drivers/net/hw/Makefile b/tools/testing/selftests/drivers/net/hw/Makefile index 5159fd34cb33..ee09a40d532c 100644 --- a/tools/testing/selftests/drivers/net/hw/Makefile +++ b/tools/testing/selftests/drivers/net/hw/Makefile @@ -15,6 +15,7 @@ TEST_PROGS = \ iou-zcrx.py \ irq.py \ loopback.sh \ + nic_timestamp.py \ pp_alloc_fail.py \ rss_api.py \ rss_ctx.py \ diff --git a/tools/testing/selftests/drivers/net/hw/nic_timestamp.py b/tools/testing/selftests/drivers/net/hw/nic_timestamp.py new file mode 100755 index 000000000000..c1e943d53f19 --- /dev/null +++ b/tools/testing/selftests/drivers/net/hw/nic_timestamp.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +""" +Tests related to configuration of HW timestamping +""" + +import errno +from lib.py import ksft_run, ksft_exit, ksft_ge, ksft_eq, KsftSkipEx +from lib.py import NetDrvEnv, EthtoolFamily, NlError + + +def __get_hwtimestamp_support(cfg): + """ Retrieve supported configuration information """ + + try: + tsinfo = cfg.ethnl.tsinfo_get({'header': {'dev-name': cfg.ifname}}) + except NlError as e: + if e.error == errno.EOPNOTSUPP: + raise KsftSkipEx("timestamping configuration is not supported") from e + raise + + ctx = {} + tx = tsinfo.get('tx-types', {}) + rx = tsinfo.get('rx-filters', {}) + + bits = tx.get('bits', {}) + ctx['tx'] = bits.get('bit', []) + bits = rx.get('bits', {}) + ctx['rx'] = bits.get('bit', []) + return ctx + + +def __get_hwtimestamp_config(cfg): + """ Retrieve current TS configuration information """ + + try: + tscfg = cfg.ethnl.tsconfig_get({'header': {'dev-name': cfg.ifname}}) + except NlError as e: + if e.error == errno.EOPNOTSUPP: + raise KsftSkipEx("timestamping configuration is not supported via netlink") from e + raise + return tscfg + + +def __set_hwtimestamp_config(cfg, ts): + """ Setup new TS configuration information """ + + ts['header'] = {'dev-name': cfg.ifname} + try: + res = cfg.ethnl.tsconfig_set(ts) + except NlError as e: + if e.error == errno.EOPNOTSUPP: + raise KsftSkipEx("timestamping configuration is not supported via netlink") from e + raise + return res + + +def test_hwtstamp_tx(cfg): + """ + Test TX timestamp configuration. + The driver should apply provided config and report back proper state. + """ + + orig_tscfg = __get_hwtimestamp_config(cfg) + ts = __get_hwtimestamp_support(cfg) + tx = ts['tx'] + for t in tx: + tscfg = orig_tscfg + tscfg['tx-types']['bits']['bit'] = [t] + res = __set_hwtimestamp_config(cfg, tscfg) + if res is None: + res = __get_hwtimestamp_config(cfg) + ksft_eq(res['tx-types']['bits']['bit'], [t]) + __set_hwtimestamp_config(cfg, orig_tscfg) + + +def test_hwtstamp_rx(cfg): + """ + Test RX timestamp configuration. + The filter configuration is taken from the list of supported filters. + The driver should apply the config without error and report back proper state. + Some extension of the timestamping scope is allowed for PTP filters. + """ + + orig_tscfg = __get_hwtimestamp_config(cfg) + ts = __get_hwtimestamp_support(cfg) + rx = ts['rx'] + for r in rx: + tscfg = orig_tscfg + tscfg['rx-filters']['bits']['bit'] = [r] + res = __set_hwtimestamp_config(cfg, tscfg) + if res is None: + res = __get_hwtimestamp_config(cfg) + if r['index'] == 0 or r['index'] == 1: + ksft_eq(res['rx-filters']['bits']['bit'][0]['index'], r['index']) + else: + # the driver can fallback to some value which has higher coverage for timestamping + ksft_ge(res['rx-filters']['bits']['bit'][0]['index'], r['index']) + __set_hwtimestamp_config(cfg, orig_tscfg) + + +def main() -> None: + """ Ksft boiler plate main """ + + with NetDrvEnv(__file__, nsim_test=False) as cfg: + cfg.ethnl = EthtoolFamily() + ksft_run([test_hwtstamp_tx, test_hwtstamp_rx], args=(cfg,)) + ksft_exit() + + +if __name__ == "__main__": + main() |
