Commit a1b05634 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bnxt_en-ptp'



Michael Chan says:

====================
bnxt_en: Add hardware PTP timestamping support on 575XX devices

Add PTP RX and TX hardware timestamp support on 575XX devices.  These
devices use the two-step method to implement the IEEE-1588 timestamping
support.

v2: Add spinlock to serialize access to the timecounter.
    Use .do_aux_work() for the periodic timer reading and to get the TX
    timestamp from the firmware.
    Propagate error code from ptp_clock_register().
    Make the 64-bit timer access safe on 32-bit CPUs.
    Read PHC using direct register access.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2eeae3a5 93cb62d9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ config SYSTEMPORT
config BNXT
	tristate "Broadcom NetXtreme-C/E support"
	depends on PCI
	imply PTP_1588_CLOCK
	select FW_LOADER
	select LIBCRC32C
	select NET_DEVLINK
+1 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_BNXT) += bnxt_en.o

bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o
bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o
bnxt_en-$(CONFIG_BNXT_FLOWER_OFFLOAD) += bnxt_tc.o
bnxt_en-$(CONFIG_DEBUG_FS) += bnxt_debugfs.o
+127 −7
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@
#include <linux/log2.h>
#include <linux/aer.h>
#include <linux/bitmap.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
#include <linux/cpu_rmap.h>
#include <linux/cpumask.h>
#include <net/pkt_cls.h>
@@ -63,6 +65,7 @@
#include "bnxt_ethtool.h"
#include "bnxt_dcb.h"
#include "bnxt_xdp.h"
#include "bnxt_ptp.h"
#include "bnxt_vfr.h"
#include "bnxt_tc.h"
#include "bnxt_devlink.h"
@@ -418,12 +421,25 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
			vlan_tag_flags |= 1 << TX_BD_CFA_META_TPID_SHIFT;
	}

	if (unlikely(skb->no_fcs)) {
		lflags |= cpu_to_le32(TX_BD_FLAGS_NO_CRC);
		goto normal_tx;
	if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
		struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;

		if (ptp && ptp->tx_tstamp_en && !skb_is_gso(skb) &&
		    atomic_dec_if_positive(&ptp->tx_avail) >= 0) {
			if (!bnxt_ptp_parse(skb, &ptp->tx_seqid)) {
				lflags |= cpu_to_le32(TX_BD_FLAGS_STAMP);
				skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
			} else {
				atomic_inc(&bp->ptp_cfg->tx_avail);
			}
		}
	}

	if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh) {
	if (unlikely(skb->no_fcs))
		lflags |= cpu_to_le32(TX_BD_FLAGS_NO_CRC);

	if (free_size == bp->tx_ring_size && length <= bp->tx_push_thresh &&
	    !lflags) {
		struct tx_push_buffer *tx_push_buf = txr->tx_push;
		struct tx_push_bd *tx_push = &tx_push_buf->push_bd;
		struct tx_bd_ext *tx_push1 = &tx_push->txbd2;
@@ -590,6 +606,8 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)

	netdev_tx_sent_queue(txq, skb->len);

	skb_tx_timestamp(skb);

	/* Sync BD data before updating doorbell */
	wmb();

@@ -619,6 +637,9 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
	return NETDEV_TX_OK;

tx_dma_error:
	if (BNXT_TX_PTP_IS_SET(lflags))
		atomic_inc(&bp->ptp_cfg->tx_avail);

	last_frag = i;

	/* start back at beginning and unmap skb */
@@ -653,6 +674,7 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)

	for (i = 0; i < nr_pkts; i++) {
		struct bnxt_sw_tx_bd *tx_buf;
		bool compl_deferred = false;
		struct sk_buff *skb;
		int j, last;

@@ -679,11 +701,20 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
				skb_frag_size(&skb_shinfo(skb)->frags[j]),
				PCI_DMA_TODEVICE);
		}
		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
			if (bp->flags & BNXT_FLAG_CHIP_P5) {
				if (!bnxt_get_tx_ts_p5(bp, skb))
					compl_deferred = true;
				else
					atomic_inc(&bp->ptp_cfg->tx_avail);
			}
		}

next_tx_int:
		cons = NEXT_TX(cons);

		tx_bytes += skb->len;
		if (!compl_deferred)
			dev_kfree_skb_any(skb);
	}

@@ -1706,9 +1737,9 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
	u8 *data_ptr, agg_bufs, cmp_type;
	dma_addr_t dma_addr;
	struct sk_buff *skb;
	u32 flags, misc;
	void *data;
	int rc = 0;
	u32 misc;

	rxcmp = (struct rx_cmp *)
			&cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
@@ -1806,7 +1837,8 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
		goto next_rx_no_len;
	}

	len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT;
	flags = le32_to_cpu(rxcmp->rx_cmp_len_flags_type);
	len = flags >> RX_CMP_LEN_SHIFT;
	dma_addr = rx_buf->mapping;

	if (bnxt_rx_xdp(bp, rxr, cons, data, &data_ptr, &len, event)) {
@@ -1883,6 +1915,24 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
		}
	}

	if (unlikely((flags & RX_CMP_FLAGS_ITYPES_MASK) ==
		     RX_CMP_FLAGS_ITYPE_PTP_W_TS)) {
		if (bp->flags & BNXT_FLAG_CHIP_P5) {
			u32 cmpl_ts = le32_to_cpu(rxcmp1->rx_cmp_timestamp);
			u64 ns, ts;

			if (!bnxt_get_rx_ts_p5(bp, &ts, cmpl_ts)) {
				struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;

				spin_lock_bh(&ptp->ptp_lock);
				ns = timecounter_cyc2time(&ptp->tc, ts);
				spin_unlock_bh(&ptp->ptp_lock);
				memset(skb_hwtstamps(skb), 0,
				       sizeof(*skb_hwtstamps(skb)));
				skb_hwtstamps(skb)->hwtstamp = ns_to_ktime(ns);
			}
		}
	}
	bnxt_deliver_skb(bp, bnapi, skb);
	rc = 1;

@@ -7391,6 +7441,56 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all)
	return rc;
}

/* bp->hwrm_cmd_lock already held. */
static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp)
{
	struct hwrm_port_mac_ptp_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
	struct hwrm_port_mac_ptp_qcfg_input req = {0};
	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
	u8 flags;
	int rc;

	if (bp->hwrm_spec_code < 0x10801) {
		rc = -ENODEV;
		goto no_ptp;
	}

	req.port_id = cpu_to_le16(bp->pf.port_id);
	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_PTP_QCFG, -1, -1);
	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
	if (rc)
		goto no_ptp;

	flags = resp->flags;
	if (!(flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS)) {
		rc = -ENODEV;
		goto no_ptp;
	}
	if (!ptp) {
		ptp = kzalloc(sizeof(*ptp), GFP_KERNEL);
		if (!ptp)
			return -ENOMEM;
		ptp->bp = bp;
		bp->ptp_cfg = ptp;
	}
	if (flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_PARTIAL_DIRECT_ACCESS_REF_CLOCK) {
		ptp->refclk_regs[0] = le32_to_cpu(resp->ts_ref_clock_reg_lower);
		ptp->refclk_regs[1] = le32_to_cpu(resp->ts_ref_clock_reg_upper);
	} else if (bp->flags & BNXT_FLAG_CHIP_P5) {
		ptp->refclk_regs[0] = BNXT_TS_REG_TIMESYNC_TS0_LOWER;
		ptp->refclk_regs[1] = BNXT_TS_REG_TIMESYNC_TS0_UPPER;
	} else {
		rc = -ENODEV;
		goto no_ptp;
	}
	return 0;

no_ptp:
	kfree(ptp);
	bp->ptp_cfg = NULL;
	return rc;
}

static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
{
	int rc = 0;
@@ -7462,6 +7562,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
		bp->flags &= ~BNXT_FLAG_WOL_CAP;
		if (flags & FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED)
			bp->flags |= BNXT_FLAG_WOL_CAP;
		if (flags & FUNC_QCAPS_RESP_FLAGS_PTP_SUPPORTED)
			__bnxt_hwrm_ptp_qcfg(bp);
	} else {
#ifdef CONFIG_BNXT_SRIOV
		struct bnxt_vf_info *vf = &bp->vf;
@@ -10020,6 +10122,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
		}
	}

	bnxt_ptp_start(bp);
	rc = bnxt_init_nic(bp, irq_re_init);
	if (rc) {
		netdev_err(bp->dev, "bnxt_init_nic err: %x\n", rc);
@@ -10335,6 +10438,12 @@ 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;
@@ -12551,6 +12660,8 @@ static void bnxt_remove_one(struct pci_dev *pdev)

	if (BNXT_PF(bp))
		devlink_port_type_clear(&bp->dl_port);

	bnxt_ptp_clear(bp);
	pci_disable_pcie_error_reporting(pdev);
	unregister_netdev(dev);
	clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state);
@@ -12571,6 +12682,8 @@ static void bnxt_remove_one(struct pci_dev *pdev)
	bnxt_dcb_free(bp);
	kfree(bp->edev);
	bp->edev = NULL;
	kfree(bp->ptp_cfg);
	bp->ptp_cfg = NULL;
	kfree(bp->fw_health);
	bp->fw_health = NULL;
	bnxt_cleanup_pci(bp);
@@ -13132,6 +13245,11 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
				   rc);
	}

	if (bnxt_ptp_init(bp)) {
		netdev_warn(dev, "PTP initialization failed.\n");
		kfree(bp->ptp_cfg);
		bp->ptp_cfg = NULL;
	}
	bnxt_inv_fw_health_reg(bp);
	bnxt_dl_register(bp);

@@ -13161,6 +13279,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
	bnxt_free_hwrm_short_cmd_req(bp);
	bnxt_free_hwrm_resources(bp);
	bnxt_ethtool_free(bp);
	kfree(bp->ptp_cfg);
	bp->ptp_cfg = NULL;
	kfree(bp->fw_health);
	bp->fw_health = NULL;
	bnxt_cleanup_pci(bp);
+9 −1
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ struct tx_bd_ext {
	#define TX_BD_CFA_META_KEY_VLAN                         (1 << 28)
};

#define BNXT_TX_PTP_IS_SET(lflags) ((lflags) & cpu_to_le32(TX_BD_FLAGS_STAMP))

struct rx_bd {
	__le32 rx_bd_len_flags_type;
	#define RX_BD_TYPE					(0x3f << 0)
@@ -159,6 +161,7 @@ struct rx_cmp {
	#define RX_CMP_FLAGS_RSS_VALID				(1 << 10)
	#define RX_CMP_FLAGS_UNUSED				(1 << 11)
	 #define RX_CMP_FLAGS_ITYPES_SHIFT			 12
	 #define RX_CMP_FLAGS_ITYPES_MASK			 0xf000
	 #define RX_CMP_FLAGS_ITYPE_UNKNOWN			 (0 << 12)
	 #define RX_CMP_FLAGS_ITYPE_IP				 (1 << 12)
	 #define RX_CMP_FLAGS_ITYPE_TCP				 (2 << 12)
@@ -240,7 +243,7 @@ struct rx_cmp_ext {
	#define RX_CMPL_CFA_CODE_MASK				(0xffff << 16)
	 #define RX_CMPL_CFA_CODE_SFT				 16

	__le32 rx_cmp_unused3;
	__le32 rx_cmp_timestamp;
};

#define RX_CMP_L2_ERRORS						\
@@ -1362,6 +1365,9 @@ struct bnxt_test_info {
#define BNXT_GRC_REG_CHIP_NUM			0x48
#define BNXT_GRC_REG_BASE			0x260000

#define BNXT_TS_REG_TIMESYNC_TS0_LOWER		0x640180c
#define BNXT_TS_REG_TIMESYNC_TS0_UPPER		0x6401810

#define BNXT_GRC_BASE_MASK			0xfffff000
#define BNXT_GRC_OFFSET_MASK			0x00000ffc

@@ -2042,6 +2048,8 @@ struct bnxt {

	struct bpf_prog		*xdp_prog;

	struct bnxt_ptp_cfg	*ptp_cfg;

	/* devlink interface and vf-rep structs */
	struct devlink		*dl;
	struct devlink_port	dl_port;
+34 −0
Original line number Diff line number Diff line
@@ -19,9 +19,13 @@
#include <linux/firmware.h>
#include <linux/utsname.h>
#include <linux/time.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/timecounter.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_xdp.h"
#include "bnxt_ptp.h"
#include "bnxt_ethtool.h"
#include "bnxt_nvm_defs.h"	/* NVRAM content constant and structure defs */
#include "bnxt_fw_hdr.h"	/* Firmware hdr constant and structure defs */
@@ -3926,6 +3930,35 @@ static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
	return 0;
}

static int bnxt_get_ts_info(struct net_device *dev,
			    struct ethtool_ts_info *info)
{
	struct bnxt *bp = netdev_priv(dev);
	struct bnxt_ptp_cfg *ptp;

	ptp = bp->ptp_cfg;
	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
				SOF_TIMESTAMPING_RX_SOFTWARE |
				SOF_TIMESTAMPING_SOFTWARE;

	info->phc_index = -1;
	if (!ptp)
		return 0;

	info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
				 SOF_TIMESTAMPING_RX_HARDWARE |
				 SOF_TIMESTAMPING_RAW_HARDWARE;
	if (ptp->ptp_clock)
		info->phc_index = ptp_clock_index(ptp->ptp_clock);

	info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);

	info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
			   (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
			   (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
	return 0;
}

void bnxt_ethtool_init(struct bnxt *bp)
{
	struct hwrm_selftest_qlist_output *resp = bp->hwrm_cmd_resp_addr;
@@ -4172,6 +4205,7 @@ const struct ethtool_ops bnxt_ethtool_ops = {
	.nway_reset		= bnxt_nway_reset,
	.set_phys_id		= bnxt_set_phys_id,
	.self_test		= bnxt_self_test,
	.get_ts_info		= bnxt_get_ts_info,
	.reset			= bnxt_reset,
	.set_dump		= bnxt_set_dump,
	.get_dump_flag		= bnxt_get_dump_flag,
Loading