Commit 6a2b3ede authored by Vadim Fedorenko's avatar Vadim Fedorenko Committed by Paolo Abeni
Browse files

eth: fbnic: add RX packets timestamping support



Add callbacks to support timestamping configuration via ethtool.
Add processing of RX timestamps.

Signed-off-by: default avatarVadim Fedorenko <vadfed@meta.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent ad8e66a4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -586,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 */
+15 −1
Original line number Diff line number Diff line
@@ -10,8 +10,22 @@ 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_SOFTWARE |
		SOF_TIMESTAMPING_RX_HARDWARE |
		SOF_TIMESTAMPING_RAW_HARDWARE;

	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;
}
+80 −0
Original line number Diff line number Diff line
@@ -324,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)
{
@@ -401,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,
+3 −0
Original line number Diff line number Diff line
@@ -54,6 +54,9 @@ struct fbnic_net {
	struct fbnic_queue_stats rx_stats;
	u64 link_down_events;

	/* Time stampinn filter config */
	struct kernel_hwtstamp_config hwtstamp_config;

	struct list_head napis;
};

+31 −0
Original line number Diff line number Diff line
@@ -244,6 +244,12 @@ void fbnic_bmc_rpc_init(struct fbnic_dev *fbd)
	 ((_ip) ? FBNIC_RPC_TCAM_ACT1_IP_VALID : 0) |	\
	 ((_v6) ? FBNIC_RPC_TCAM_ACT1_IP_IS_V6 : 0))

#define FBNIC_TSTAMP_MASK(_all, _udp, _ether)			\
	(((_all) ? ((1u << FBNIC_NUM_HASH_OPT) - 1) : 0) |	\
	 ((_udp) ? (1u << FBNIC_UDP6_HASH_OPT) |		\
		   (1u << FBNIC_UDP4_HASH_OPT) : 0) |		\
	 ((_ether) ? (1u << FBNIC_ETHER_HASH_OPT) : 0))

void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn)
{
	static const u32 act1_value[FBNIC_NUM_HASH_OPT] = {
@@ -255,6 +261,7 @@ void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn)
		FBNIC_ACT1_INIT(0, 0, 1, 0),	/* IP4 */
		0				/* Ether */
	};
	u32 tstamp_mask = 0;
	unsigned int i;

	/* To support scenarios where a BMC is present we must write the
@@ -264,6 +271,28 @@ void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn)
	BUILD_BUG_ON(FBNIC_RSS_EN_NUM_UNICAST * 2 != FBNIC_RSS_EN_NUM_ENTRIES);
	BUILD_BUG_ON(ARRAY_SIZE(act1_value) != FBNIC_NUM_HASH_OPT);

	/* Set timestamp mask with 1b per flow type */
	if (fbn->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) {
		switch (fbn->hwtstamp_config.rx_filter) {
		case HWTSTAMP_FILTER_ALL:
			tstamp_mask = FBNIC_TSTAMP_MASK(1, 1, 1);
			break;
		case HWTSTAMP_FILTER_PTP_V2_EVENT:
			tstamp_mask = FBNIC_TSTAMP_MASK(0, 1, 1);
			break;
		case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
		case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
			tstamp_mask = FBNIC_TSTAMP_MASK(0, 1, 0);
			break;
		case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
			tstamp_mask = FBNIC_TSTAMP_MASK(0, 0, 1);
			break;
		default:
			netdev_warn(fbn->netdev, "Unsupported hwtstamp_rx_filter\n");
			break;
		}
	}

	/* Program RSS hash enable mask for host in action TCAM/table. */
	for (i = fbnic_bmc_present(fbd) ? 0 : FBNIC_RSS_EN_NUM_UNICAST;
	     i < FBNIC_RSS_EN_NUM_ENTRIES; i++) {
@@ -287,6 +316,8 @@ void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn)

		if (!dest)
			dest = FBNIC_RPC_ACT_TBL0_DROP;
		else if (tstamp_mask & (1u << flow_type))
			dest |= FBNIC_RPC_ACT_TBL0_TS_ENA;

		if (act1_value[flow_type] & FBNIC_RPC_TCAM_ACT1_L4_VALID)
			dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT,
Loading