Skip to content

Commit

Permalink
Merge branch 'bnxt_en-ptp'
Browse files Browse the repository at this point in the history
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: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 28, 2021
2 parents 2eeae3a + 93cb62d commit a1b0563
Show file tree
Hide file tree
Showing 9 changed files with 1,355 additions and 51 deletions.
1 change: 1 addition & 0 deletions drivers/net/ethernet/broadcom/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/broadcom/bnxt/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 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
134 changes: 127 additions & 7 deletions drivers/net/ethernet/broadcom/bnxt/bnxt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;

Expand All @@ -679,12 +701,21 @@ 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;
dev_kfree_skb_any(skb);
if (!compl_deferred)
dev_kfree_skb_any(skb);
}

netdev_tx_completed_queue(txq, nr_pkts, tx_bytes);
Expand Down Expand Up @@ -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)];
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
10 changes: 9 additions & 1 deletion drivers/net/ethernet/broadcom/bnxt/bnxt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 \
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down
34 changes: 34 additions & 0 deletions drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Loading

0 comments on commit a1b0563

Please sign in to comment.