Skip to content

Commit

Permalink
Merge branch 'eth-fbnic-add-timestamping-support'
Browse files Browse the repository at this point in the history
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: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni committed Oct 10, 2024
2 parents 9e542ff + 96f358f commit d9d28b6
Show file tree
Hide file tree
Showing 11 changed files with 722 additions and 8 deletions.
3 changes: 2 additions & 1 deletion drivers/net/ethernet/meta/fbnic/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 11 additions & 0 deletions drivers/net/ethernet/meta/fbnic/fbnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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;
};
Expand Down
39 changes: 39 additions & 0 deletions drivers/net/ethernet/meta/fbnic/fbnic_csr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 */
Expand Down
54 changes: 54 additions & 0 deletions drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
};

Expand Down
91 changes: 89 additions & 2 deletions drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down
18 changes: 18 additions & 0 deletions drivers/net/ethernet/meta/fbnic/fbnic_netdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ struct fbnic_net {
u8 fec;
u8 link_mode;

/* Cached top bits of the HW time counter for 40b -> 64b conversion */
u32 time_high;
/* Protect readers of @time_offset, writers take @time_lock. */
struct u64_stats_sync time_seq;
/* Offset in ns between free running NIC PHC and time set via PTP
* clock callbacks
*/
s64 time_offset;

u16 num_tx_queues;
u16 num_rx_queues;

Expand All @@ -45,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;
};

Expand All @@ -60,6 +72,12 @@ void fbnic_reset_queues(struct fbnic_net *fbn,
unsigned int tx, unsigned int rx);
void fbnic_set_ethtool_ops(struct net_device *dev);

int fbnic_ptp_setup(struct fbnic_dev *fbd);
void fbnic_ptp_destroy(struct fbnic_dev *fbd);
void fbnic_time_init(struct fbnic_net *fbn);
int fbnic_time_start(struct fbnic_net *fbn);
void fbnic_time_stop(struct fbnic_net *fbn);

void __fbnic_set_rx_mode(struct net_device *netdev);
void fbnic_clear_rx_mode(struct net_device *netdev);

Expand Down
9 changes: 8 additions & 1 deletion drivers/net/ethernet/meta/fbnic/fbnic_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,14 +300,20 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto init_failure_mode;
}

err = fbnic_ptp_setup(fbd);
if (err)
goto ifm_free_netdev;

err = fbnic_netdev_register(netdev);
if (err) {
dev_err(&pdev->dev, "Netdev registration failed: %d\n", err);
goto ifm_free_netdev;
goto ifm_destroy_ptp;
}

return 0;

ifm_destroy_ptp:
fbnic_ptp_destroy(fbd);
ifm_free_netdev:
fbnic_netdev_free(fbd);
init_failure_mode:
Expand Down Expand Up @@ -342,6 +348,7 @@ static void fbnic_remove(struct pci_dev *pdev)

fbnic_netdev_unregister(netdev);
cancel_delayed_work_sync(&fbd->service_task);
fbnic_ptp_destroy(fbd);
fbnic_netdev_free(fbd);
}

Expand Down
Loading

0 comments on commit d9d28b6

Please sign in to comment.