Commit 85036aee authored by Pavan Chebbi's avatar Pavan Chebbi Committed by Paolo Abeni

bnxt_en: Add a non-real time mode to access NIC clock

When using a PHC that is shared between multiple hosts,
in order to achieve consistent timestamps across all hosts,
we need to isolate the PHC from any host making frequency
adjustments.

This patch adds a non-real time mode for this purpose.
The implementation is based on a free running NIC hardware timer
which is used as the timestamper time-base. Each host implements
individual adjustments to a local timecounter based on the NIC free
running timer.

Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: default avatarPavan Chebbi <pavan.chebbi@broadcom.com>
Reviewed-by: default avatarAndy Gospodarek <andrew.gospodarek@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Reviewed-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 98a4322b
...@@ -6985,8 +6985,11 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) ...@@ -6985,8 +6985,11 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp)
if (flags & FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED) if (flags & FUNC_QCFG_RESP_FLAGS_FW_DCBX_AGENT_ENABLED)
bp->fw_cap |= BNXT_FW_CAP_DCBX_AGENT; bp->fw_cap |= BNXT_FW_CAP_DCBX_AGENT;
} }
if (BNXT_PF(bp) && (flags & FUNC_QCFG_RESP_FLAGS_MULTI_HOST)) if (BNXT_PF(bp) && (flags & FUNC_QCFG_RESP_FLAGS_MULTI_HOST)) {
bp->flags |= BNXT_FLAG_MULTI_HOST; bp->flags |= BNXT_FLAG_MULTI_HOST;
if (bp->fw_cap & BNXT_FW_CAP_PTP_RTC)
bp->fw_cap &= ~BNXT_FW_CAP_PTP_RTC;
}
if (flags & FUNC_QCFG_RESP_FLAGS_RING_MONITOR_ENABLED) if (flags & FUNC_QCFG_RESP_FLAGS_RING_MONITOR_ENABLED)
bp->fw_cap |= BNXT_FW_CAP_RING_MONITOR; bp->fw_cap |= BNXT_FW_CAP_RING_MONITOR;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/net_tstamp.h> #include <linux/net_tstamp.h>
#include <linux/timekeeping.h> #include <linux/timekeeping.h>
#include <linux/ptp_classify.h> #include <linux/ptp_classify.h>
#include <linux/clocksource.h>
#include "bnxt_hsi.h" #include "bnxt_hsi.h"
#include "bnxt.h" #include "bnxt.h"
#include "bnxt_hwrm.h" #include "bnxt_hwrm.h"
...@@ -210,18 +211,37 @@ static int bnxt_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb) ...@@ -210,18 +211,37 @@ static int bnxt_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb)
ptp_info); ptp_info);
struct hwrm_port_mac_cfg_input *req; struct hwrm_port_mac_cfg_input *req;
struct bnxt *bp = ptp->bp; struct bnxt *bp = ptp->bp;
int rc; int rc = 0;
rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG); if (!(ptp->bp->fw_cap & BNXT_FW_CAP_PTP_RTC)) {
if (rc) int neg_adj = 0;
return rc; u32 diff;
u64 adj;
req->ptp_freq_adj_ppb = cpu_to_le32(ppb); if (ppb < 0) {
req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB); neg_adj = 1;
rc = hwrm_req_send(ptp->bp, req); ppb = -ppb;
if (rc) }
netdev_err(ptp->bp->dev, adj = ptp->cmult;
"ptp adjfreq failed. rc = %d\n", rc); adj *= ppb;
diff = div_u64(adj, 1000000000ULL);
spin_lock_bh(&ptp->ptp_lock);
timecounter_read(&ptp->tc);
ptp->cc.mult = neg_adj ? ptp->cmult - diff : ptp->cmult + diff;
spin_unlock_bh(&ptp->ptp_lock);
} else {
rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG);
if (rc)
return rc;
req->ptp_freq_adj_ppb = cpu_to_le32(ppb);
req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB);
rc = hwrm_req_send(ptp->bp, req);
if (rc)
netdev_err(ptp->bp->dev,
"ptp adjfreq failed. rc = %d\n", rc);
}
return rc; return rc;
} }
...@@ -846,8 +866,9 @@ static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc) ...@@ -846,8 +866,9 @@ static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc)
memset(&ptp->cc, 0, sizeof(ptp->cc)); memset(&ptp->cc, 0, sizeof(ptp->cc));
ptp->cc.read = bnxt_cc_read; ptp->cc.read = bnxt_cc_read;
ptp->cc.mask = CYCLECOUNTER_MASK(48); ptp->cc.mask = CYCLECOUNTER_MASK(48);
ptp->cc.shift = 0; ptp->cc.shift = BNXT_CYCLES_SHIFT;
ptp->cc.mult = 1; ptp->cc.mult = clocksource_khz2mult(BNXT_DEVCLK_FREQ, ptp->cc.shift);
ptp->cmult = ptp->cc.mult;
ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD; ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD;
} }
if (init_tc) if (init_tc)
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#define BNXT_PTP_GRC_WIN_BASE 0x6000 #define BNXT_PTP_GRC_WIN_BASE 0x6000
#define BNXT_MAX_PHC_DRIFT 31000000 #define BNXT_MAX_PHC_DRIFT 31000000
#define BNXT_CYCLES_SHIFT 23
#define BNXT_DEVCLK_FREQ 1000000
#define BNXT_LO_TIMER_MASK 0x0000ffffffffUL #define BNXT_LO_TIMER_MASK 0x0000ffffffffUL
#define BNXT_HI_TIMER_MASK 0xffff00000000UL #define BNXT_HI_TIMER_MASK 0xffff00000000UL
...@@ -88,8 +90,9 @@ struct bnxt_ptp_cfg { ...@@ -88,8 +90,9 @@ struct bnxt_ptp_cfg {
u64 old_time; u64 old_time;
unsigned long next_period; unsigned long next_period;
unsigned long next_overflow_check; unsigned long next_overflow_check;
/* 48-bit PHC overflows in 78 hours. Check overflow every 19 hours. */ u32 cmult;
#define BNXT_PHC_OVERFLOW_PERIOD (19 * 3600 * HZ) /* a 23b shift cyclecounter will overflow in ~36 mins. Check overflow every 18 mins. */
#define BNXT_PHC_OVERFLOW_PERIOD (18 * 60 * HZ)
u16 tx_seqid; u16 tx_seqid;
u16 tx_hdr_off; u16 tx_hdr_off;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment