Commit d9d28b6f authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'eth-fbnic-add-timestamping-support'

Vadim Fedorenko says:

====================
eth: fbnic: add timestamping support

The series is to add timestamping support for Meta's NIC driver.

Changelog:
v3 -> v4:
- use adjust_by_scaled_ppm() instead of open coding it
- adjust cached value of high bits of timestamp to be sure it
  is older then incoming timestamps
v2 -> v3:
- rebase on top of net-next
- add doc to describe retur value of fbnic_ts40_to_ns()
v1 -> v2:
- adjust comment about using u64 stats locking primitive
- fix typo in the first patch
- Cc Richard
====================

Link: https://patch.msgid.link/20241008181436.4120604-1-vadfed@meta.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 9e542ff8 96f358f7
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -18,4 +18,5 @@ fbnic-y := fbnic_devlink.o \
	   fbnic_phylink.o \
	   fbnic_rpc.o \
	   fbnic_tlv.o \
	   fbnic_txrx.o
	   fbnic_txrx.o \
	   fbnic_time.o
+11 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/types.h>
#include <linux/workqueue.h>

@@ -49,6 +50,16 @@ struct fbnic_dev {
	/* Number of TCQs/RCQs available on hardware */
	u16 max_num_queues;

	/* Lock protecting writes to @time_high, @time_offset of fbnic_netdev,
	 * and the HW time CSR machinery.
	 */
	spinlock_t time_lock;
	/* Externally accessible PTP clock, may be NULL */
	struct ptp_clock *ptp;
	struct ptp_clock_info ptp_info;
	/* Last @time_high refresh time in jiffies (to catch stalls) */
	unsigned long last_read;

	/* Local copy of hardware statistics */
	struct fbnic_hw_stats hw_stats;
};
+39 −0
Original line number Diff line number Diff line
@@ -413,6 +413,44 @@ enum {
#define FBNIC_TMI_DROP_CTRL		0x04401		/* 0x11004 */
#define FBNIC_TMI_DROP_CTRL_EN			CSR_BIT(0)
#define FBNIC_CSR_END_TMI		0x0443f	/* CSR section delimiter */

/* Precision Time Protocol Registers */
#define FBNIC_CSR_START_PTP		0x04800 /* CSR section delimiter */
#define FBNIC_PTP_REG_BASE		0x04800		/* 0x12000 */

#define FBNIC_PTP_CTRL			0x04800		/* 0x12000 */
#define FBNIC_PTP_CTRL_EN			CSR_BIT(0)
#define FBNIC_PTP_CTRL_MONO_EN			CSR_BIT(4)
#define FBNIC_PTP_CTRL_TQS_OUT_EN		CSR_BIT(8)
#define FBNIC_PTP_CTRL_MAC_OUT_IVAL		CSR_GENMASK(16, 12)
#define FBNIC_PTP_CTRL_TICK_IVAL		CSR_GENMASK(23, 20)

#define FBNIC_PTP_ADJUST		0x04801		/* 0x12004 */
#define FBNIC_PTP_ADJUST_INIT			CSR_BIT(0)
#define FBNIC_PTP_ADJUST_SUB_NUDGE		CSR_BIT(8)
#define FBNIC_PTP_ADJUST_ADD_NUDGE		CSR_BIT(16)
#define FBNIC_PTP_ADJUST_ADDEND_SET		CSR_BIT(24)

#define FBNIC_PTP_INIT_HI		0x04802		/* 0x12008 */
#define FBNIC_PTP_INIT_LO		0x04803		/* 0x1200c */

#define FBNIC_PTP_NUDGE_NS		0x04804		/* 0x12010 */
#define FBNIC_PTP_NUDGE_SUBNS		0x04805		/* 0x12014 */

#define FBNIC_PTP_ADD_VAL_NS		0x04806		/* 0x12018 */
#define FBNIC_PTP_ADD_VAL_NS_MASK		CSR_GENMASK(15, 0)
#define FBNIC_PTP_ADD_VAL_SUBNS		0x04807	/* 0x1201c */

#define FBNIC_PTP_CTR_VAL_HI		0x04808		/* 0x12020 */
#define FBNIC_PTP_CTR_VAL_LO		0x04809		/* 0x12024 */

#define FBNIC_PTP_MONO_PTP_CTR_HI	0x0480a		/* 0x12028 */
#define FBNIC_PTP_MONO_PTP_CTR_LO	0x0480b		/* 0x1202c */

#define FBNIC_PTP_CDC_FIFO_STATUS	0x0480c		/* 0x12030 */
#define FBNIC_PTP_SPARE			0x0480d		/* 0x12034 */
#define FBNIC_CSR_END_PTP		0x0480d /* CSR section delimiter */

/* Rx Buffer Registers */
#define FBNIC_CSR_START_RXB		0x08000	/* CSR section delimiter */
enum {
@@ -548,6 +586,7 @@ enum {
};

#define FBNIC_RPC_ACT_TBL0_DMA_HINT		CSR_GENMASK(24, 16)
#define FBNIC_RPC_ACT_TBL0_TS_ENA		CSR_BIT(28)
#define FBNIC_RPC_ACT_TBL0_RSS_CTXT_ID		CSR_BIT(30)

#define FBNIC_RPC_ACT_TBL1_DEFAULT	0x0840b		/* 0x2102c */
+54 −0
Original line number Diff line number Diff line
@@ -6,6 +6,35 @@
#include "fbnic_netdev.h"
#include "fbnic_tlv.h"

static int
fbnic_get_ts_info(struct net_device *netdev,
		  struct kernel_ethtool_ts_info *tsinfo)
{
	struct fbnic_net *fbn = netdev_priv(netdev);

	tsinfo->phc_index = ptp_clock_index(fbn->fbd->ptp);

	tsinfo->so_timestamping =
		SOF_TIMESTAMPING_TX_SOFTWARE |
		SOF_TIMESTAMPING_TX_HARDWARE |
		SOF_TIMESTAMPING_RX_HARDWARE |
		SOF_TIMESTAMPING_RAW_HARDWARE;

	tsinfo->tx_types =
		BIT(HWTSTAMP_TX_OFF) |
		BIT(HWTSTAMP_TX_ON);

	tsinfo->rx_filters =
		BIT(HWTSTAMP_FILTER_NONE) |
		BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
		BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
		BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
		BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
		BIT(HWTSTAMP_FILTER_ALL);

	return 0;
}

static void
fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
{
@@ -64,8 +93,33 @@ fbnic_get_eth_mac_stats(struct net_device *netdev,
			  &mac_stats->eth_mac.FrameTooLongErrors);
}

static void fbnic_get_ts_stats(struct net_device *netdev,
			       struct ethtool_ts_stats *ts_stats)
{
	struct fbnic_net *fbn = netdev_priv(netdev);
	u64 ts_packets, ts_lost;
	struct fbnic_ring *ring;
	unsigned int start;
	int i;

	ts_stats->pkts = fbn->tx_stats.ts_packets;
	ts_stats->lost = fbn->tx_stats.ts_lost;
	for (i = 0; i < fbn->num_tx_queues; i++) {
		ring = fbn->tx[i];
		do {
			start = u64_stats_fetch_begin(&ring->stats.syncp);
			ts_packets = ring->stats.ts_packets;
			ts_lost = ring->stats.ts_lost;
		} while (u64_stats_fetch_retry(&ring->stats.syncp, start));
		ts_stats->pkts += ts_packets;
		ts_stats->lost += ts_lost;
	}
}

static const struct ethtool_ops fbnic_ethtool_ops = {
	.get_drvinfo		= fbnic_get_drvinfo,
	.get_ts_info		= fbnic_get_ts_info,
	.get_ts_stats		= fbnic_get_ts_stats,
	.get_eth_mac_stats	= fbnic_get_eth_mac_stats,
};

+89 −2
Original line number Diff line number Diff line
@@ -42,18 +42,24 @@ int __fbnic_open(struct fbnic_net *fbn)
		goto free_resources;
	}

	err = fbnic_fw_init_heartbeat(fbd, false);
	err = fbnic_time_start(fbn);
	if (err)
		goto release_ownership;

	err = fbnic_fw_init_heartbeat(fbd, false);
	if (err)
		goto time_stop;

	err = fbnic_pcs_irq_enable(fbd);
	if (err)
		goto release_ownership;
		goto time_stop;
	/* Pull the BMC config and initialize the RPC */
	fbnic_bmc_rpc_init(fbd);
	fbnic_rss_reinit(fbd, fbn);

	return 0;
time_stop:
	fbnic_time_stop(fbn);
release_ownership:
	fbnic_fw_xmit_ownership_msg(fbn->fbd, false);
free_resources:
@@ -82,6 +88,7 @@ static int fbnic_stop(struct net_device *netdev)
	fbnic_down(fbn);
	fbnic_pcs_irq_disable(fbn->fbd);

	fbnic_time_stop(fbn);
	fbnic_fw_xmit_ownership_msg(fbn->fbd, false);

	fbnic_free_resources(fbn);
@@ -317,6 +324,84 @@ void fbnic_clear_rx_mode(struct net_device *netdev)
	__dev_mc_unsync(netdev, NULL);
}

static int fbnic_hwtstamp_get(struct net_device *netdev,
			      struct kernel_hwtstamp_config *config)
{
	struct fbnic_net *fbn = netdev_priv(netdev);

	*config = fbn->hwtstamp_config;

	return 0;
}

static int fbnic_hwtstamp_set(struct net_device *netdev,
			      struct kernel_hwtstamp_config *config,
			      struct netlink_ext_ack *extack)
{
	struct fbnic_net *fbn = netdev_priv(netdev);
	int old_rx_filter;

	if (config->source != HWTSTAMP_SOURCE_NETDEV)
		return -EOPNOTSUPP;

	if (!kernel_hwtstamp_config_changed(config, &fbn->hwtstamp_config))
		return 0;

	/* Upscale the filters */
	switch (config->rx_filter) {
	case HWTSTAMP_FILTER_NONE:
	case HWTSTAMP_FILTER_ALL:
	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
	case HWTSTAMP_FILTER_PTP_V2_EVENT:
		break;
	case HWTSTAMP_FILTER_NTP_ALL:
		config->rx_filter = HWTSTAMP_FILTER_ALL;
		break;
	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
		config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
		break;
	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
		break;
	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
		break;
	case HWTSTAMP_FILTER_PTP_V2_SYNC:
	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
		config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
		break;
	default:
		return -ERANGE;
	}

	/* Configure */
	old_rx_filter = fbn->hwtstamp_config.rx_filter;
	memcpy(&fbn->hwtstamp_config, config, sizeof(*config));

	if (old_rx_filter != config->rx_filter && netif_running(fbn->netdev)) {
		fbnic_rss_reinit(fbn->fbd, fbn);
		fbnic_write_rules(fbn->fbd);
	}

	/* Save / report back filter configuration
	 * Note that our filter configuration is inexact. Instead of
	 * filtering for a specific UDP port or L2 Ethertype we are
	 * filtering in all UDP or all non-IP packets for timestamping. So
	 * if anything other than FILTER_ALL is requested we report
	 * FILTER_SOME indicating that we will be timestamping a few
	 * additional packets.
	 */
	if (config->rx_filter > HWTSTAMP_FILTER_ALL)
		config->rx_filter = HWTSTAMP_FILTER_SOME;

	return 0;
}

static void fbnic_get_stats64(struct net_device *dev,
			      struct rtnl_link_stats64 *stats64)
{
@@ -394,6 +479,8 @@ static const struct net_device_ops fbnic_netdev_ops = {
	.ndo_set_mac_address	= fbnic_set_mac,
	.ndo_set_rx_mode	= fbnic_set_rx_mode,
	.ndo_get_stats64	= fbnic_get_stats64,
	.ndo_hwtstamp_get	= fbnic_hwtstamp_get,
	.ndo_hwtstamp_set	= fbnic_hwtstamp_set,
};

static void fbnic_get_queue_stats_rx(struct net_device *dev, int idx,
Loading