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

Merge branch 'bnxt_en-RTC'



Michael Chan says:

====================
bnxt_en: Add RTC mode for PTP

This series adds Real Time Clock (RTC) mode for PTP timestamping.  In
RTC mode, the 64-bit time value is programmed into the NIC's PTP
hardware clock (PHC).  Prior to this, the PHC is running as a free
counter.  For example, in multi-function environment, we need to run
PTP in RTC mode.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d28b159b 8bcf6f04
Loading
Loading
Loading
Loading
+35 −1
Original line number Diff line number Diff line
@@ -233,6 +233,7 @@ static const u16 bnxt_async_events_arr[] = {
	ASYNC_EVENT_CMPL_EVENT_ID_ECHO_REQUEST,
	ASYNC_EVENT_CMPL_EVENT_ID_PPS_TIMESTAMP,
	ASYNC_EVENT_CMPL_EVENT_ID_ERROR_REPORT,
	ASYNC_EVENT_CMPL_EVENT_ID_PHC_UPDATE,
};

static struct workqueue_struct *bnxt_pf_wq;
@@ -2079,6 +2080,16 @@ static void bnxt_event_error_report(struct bnxt *bp, u32 data1, u32 data2)
	(BNXT_EVENT_RING_TYPE(data2) ==	\
	 ASYNC_EVENT_CMPL_RING_MONITOR_MSG_EVENT_DATA2_DISABLE_RING_TYPE_RX)

#define BNXT_EVENT_PHC_EVENT_TYPE(data1)	\
	(((data1) & ASYNC_EVENT_CMPL_PHC_UPDATE_EVENT_DATA1_FLAGS_MASK) >>\
	 ASYNC_EVENT_CMPL_PHC_UPDATE_EVENT_DATA1_FLAGS_SFT)

#define BNXT_EVENT_PHC_RTC_UPDATE(data1)	\
	(((data1) & ASYNC_EVENT_CMPL_PHC_UPDATE_EVENT_DATA1_PHC_TIME_MSB_MASK) >>\
	 ASYNC_EVENT_CMPL_PHC_UPDATE_EVENT_DATA1_PHC_TIME_MSB_SFT)

#define BNXT_PHC_BITS	48

static int bnxt_async_event_process(struct bnxt *bp,
				    struct hwrm_async_event_cmpl *cmpl)
{
@@ -2258,6 +2269,24 @@ static int bnxt_async_event_process(struct bnxt *bp,
		bnxt_event_error_report(bp, data1, data2);
		goto async_event_process_exit;
	}
	case ASYNC_EVENT_CMPL_EVENT_ID_PHC_UPDATE: {
		switch (BNXT_EVENT_PHC_EVENT_TYPE(data1)) {
		case ASYNC_EVENT_CMPL_PHC_UPDATE_EVENT_DATA1_FLAGS_PHC_RTC_UPDATE:
			if (bp->fw_cap & BNXT_FW_CAP_PTP_RTC) {
				struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
				u64 ns;

				spin_lock_bh(&ptp->ptp_lock);
				bnxt_ptp_update_current_time(bp);
				ns = (((u64)BNXT_EVENT_PHC_RTC_UPDATE(data1) <<
				       BNXT_PHC_BITS) | ptp->current_time);
				bnxt_ptp_rtc_timecounter_init(ptp, ns);
				spin_unlock_bh(&ptp->ptp_lock);
			}
			break;
		}
		goto async_event_process_exit;
	}
	case ASYNC_EVENT_CMPL_EVENT_ID_DEFERRED_RESPONSE: {
		u16 seq_id = le32_to_cpu(cmpl->event_data2) & 0xffff;

@@ -7414,6 +7443,7 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp)
	struct hwrm_port_mac_ptp_qcfg_output *resp;
	struct hwrm_port_mac_ptp_qcfg_input *req;
	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
	bool phc_cfg;
	u8 flags;
	int rc;

@@ -7456,7 +7486,8 @@ static int __bnxt_hwrm_ptp_qcfg(struct bnxt *bp)
		rc = -ENODEV;
		goto exit;
	}
	rc = bnxt_ptp_init(bp);
	phc_cfg = (flags & PORT_MAC_PTP_QCFG_RESP_FLAGS_RTC_CONFIGURED) != 0;
	rc = bnxt_ptp_init(bp, phc_cfg);
	if (rc)
		netdev_warn(bp->dev, "PTP initialization failed.\n");
exit:
@@ -7514,6 +7545,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
		bp->fw_cap |= BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED;
	if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_PTP_PPS_SUPPORTED))
		bp->fw_cap |= BNXT_FW_CAP_PTP_PPS;
	if (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_PTP_64BIT_RTC_SUPPORTED)
		bp->fw_cap |= BNXT_FW_CAP_PTP_RTC;
	if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_HOT_RESET_IF_SUPPORT))
		bp->fw_cap |= BNXT_FW_CAP_HOT_RESET_IF;
	if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_FW_LIVEPATCH_SUPPORTED))
@@ -10288,6 +10321,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
	/* VF-reps may need to be re-opened after the PF is re-opened */
	if (BNXT_PF(bp))
		bnxt_vf_reps_open(bp);
	bnxt_ptp_init_rtc(bp, true);
	return 0;

open_err_irq:
+1 −0
Original line number Diff line number Diff line
@@ -1957,6 +1957,7 @@ struct bnxt {
	#define BNXT_FW_CAP_EXT_STATS_SUPPORTED		0x00040000
	#define BNXT_FW_CAP_ERR_RECOVER_RELOAD		0x00100000
	#define BNXT_FW_CAP_HOT_RESET			0x00200000
	#define BNXT_FW_CAP_PTP_RTC			0x00400000
	#define BNXT_FW_CAP_VLAN_RX_STRIP		0x01000000
	#define BNXT_FW_CAP_VLAN_TX_INSERT		0x02000000
	#define BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED	0x04000000
+460 −39

File changed.

Preview size limit exceeded, changes collapsed.

+135 −17
Original line number Diff line number Diff line
@@ -19,6 +19,20 @@
#include "bnxt_hwrm.h"
#include "bnxt_ptp.h"

static int bnxt_ptp_cfg_settime(struct bnxt *bp, u64 time)
{
	struct hwrm_func_ptp_cfg_input *req;
	int rc;

	rc = hwrm_req_init(bp, req, HWRM_FUNC_PTP_CFG);
	if (rc)
		return rc;

	req->enables = cpu_to_le16(FUNC_PTP_CFG_REQ_ENABLES_PTP_SET_TIME);
	req->ptp_set_time = cpu_to_le64(time);
	return hwrm_req_send(bp, req);
}

int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id, u16 *hdr_off)
{
	unsigned int ptp_class;
@@ -48,6 +62,9 @@ static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info,
						ptp_info);
	u64 ns = timespec64_to_ns(ts);

	if (ptp->bp->fw_cap & BNXT_FW_CAP_PTP_RTC)
		return bnxt_ptp_cfg_settime(ptp->bp, ns);

	spin_lock_bh(&ptp->ptp_lock);
	timecounter_init(&ptp->tc, &ptp->cc, ns);
	spin_unlock_bh(&ptp->ptp_lock);
@@ -131,11 +148,47 @@ static int bnxt_ptp_gettimex(struct ptp_clock_info *ptp_info,
	return 0;
}

/* Caller holds ptp_lock */
void bnxt_ptp_update_current_time(struct bnxt *bp)
{
	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;

	bnxt_refclk_read(ptp->bp, NULL, &ptp->current_time);
	WRITE_ONCE(ptp->old_time, ptp->current_time);
}

static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta)
{
	struct hwrm_port_mac_cfg_input *req;
	int rc;

	rc = hwrm_req_init(ptp->bp, req, HWRM_PORT_MAC_CFG);
	if (rc)
		return rc;

	req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_ADJ_PHASE);
	req->ptp_adj_phase = cpu_to_le64(delta);

	rc = hwrm_req_send(ptp->bp, req);
	if (rc) {
		netdev_err(ptp->bp->dev, "ptp adjphc failed. rc = %x\n", rc);
	} else {
		spin_lock_bh(&ptp->ptp_lock);
		bnxt_ptp_update_current_time(ptp->bp);
		spin_unlock_bh(&ptp->ptp_lock);
	}

	return rc;
}

static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
{
	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
						ptp_info);

	if (ptp->bp->fw_cap & BNXT_FW_CAP_PTP_RTC)
		return bnxt_ptp_adjphc(ptp, delta);

	spin_lock_bh(&ptp->ptp_lock);
	timecounter_adjtime(&ptp->tc, delta);
	spin_unlock_bh(&ptp->ptp_lock);
@@ -714,20 +767,60 @@ static bool bnxt_pps_config_ok(struct bnxt *bp)
	return !(bp->fw_cap & BNXT_FW_CAP_PTP_PPS) == !ptp->ptp_info.pin_config;
}

int bnxt_ptp_init(struct bnxt *bp)
static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc)
{
	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;

	if (!ptp->ptp_clock) {
		memset(&ptp->cc, 0, sizeof(ptp->cc));
		ptp->cc.read = bnxt_cc_read;
		ptp->cc.mask = CYCLECOUNTER_MASK(48);
		ptp->cc.shift = 0;
		ptp->cc.mult = 1;
		ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD;
	}
	if (init_tc)
		timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
}

/* Caller holds ptp_lock */
void bnxt_ptp_rtc_timecounter_init(struct bnxt_ptp_cfg *ptp, u64 ns)
{
	timecounter_init(&ptp->tc, &ptp->cc, ns);
	/* For RTC, cycle_last must be in sync with the timecounter value. */
	ptp->tc.cycle_last = ns & ptp->cc.mask;
}

int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg)
{
	struct timespec64 tsp;
	u64 ns;
	int rc;

	if (!ptp)
		return 0;
	if (!bp->ptp_cfg || !(bp->fw_cap & BNXT_FW_CAP_PTP_RTC))
		return -ENODEV;

	rc = bnxt_map_ptp_regs(bp);
	if (!phc_cfg) {
		ktime_get_real_ts64(&tsp);
		ns = timespec64_to_ns(&tsp);
		rc = bnxt_ptp_cfg_settime(bp, ns);
		if (rc)
			return rc;
	} else {
		rc = bnxt_hwrm_port_ts_query(bp, PORT_TS_QUERY_REQ_FLAGS_CURRENT_TIME, &ns);
		if (rc)
			return rc;
	}
	spin_lock_bh(&bp->ptp_cfg->ptp_lock);
	bnxt_ptp_rtc_timecounter_init(bp->ptp_cfg, ns);
	spin_unlock_bh(&bp->ptp_cfg->ptp_lock);

	if (ptp->ptp_clock && bnxt_pps_config_ok(bp))
	return 0;
}

static void bnxt_ptp_free(struct bnxt *bp)
{
	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;

	if (ptp->ptp_clock) {
		ptp_clock_unregister(ptp->ptp_clock);
@@ -735,17 +828,37 @@ int bnxt_ptp_init(struct bnxt *bp)
		kfree(ptp->ptp_info.pin_config);
		ptp->ptp_info.pin_config = NULL;
	}
}

int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg)
{
	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
	int rc;

	if (!ptp)
		return 0;

	rc = bnxt_map_ptp_regs(bp);
	if (rc)
		return rc;

	if (bp->fw_cap & BNXT_FW_CAP_PTP_RTC) {
		bnxt_ptp_timecounter_init(bp, false);
		rc = bnxt_ptp_init_rtc(bp, phc_cfg);
		if (rc)
			goto out;
	}

	if (ptp->ptp_clock && bnxt_pps_config_ok(bp))
		return 0;

	bnxt_ptp_free(bp);

	atomic_set(&ptp->tx_avail, BNXT_MAX_TX_TS);
	spin_lock_init(&ptp->ptp_lock);

	memset(&ptp->cc, 0, sizeof(ptp->cc));
	ptp->cc.read = bnxt_cc_read;
	ptp->cc.mask = CYCLECOUNTER_MASK(48);
	ptp->cc.shift = 0;
	ptp->cc.mult = 1;

	ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD;
	timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
	if (!(bp->fw_cap & BNXT_FW_CAP_PTP_RTC))
		bnxt_ptp_timecounter_init(bp, true);

	ptp->ptp_info = bnxt_ptp_caps;
	if ((bp->fw_cap & BNXT_FW_CAP_PTP_PPS)) {
@@ -757,8 +870,8 @@ int bnxt_ptp_init(struct bnxt *bp)
		int err = PTR_ERR(ptp->ptp_clock);

		ptp->ptp_clock = NULL;
		bnxt_unmap_ptp_regs(bp);
		return err;
		rc = err;
		goto out;
	}
	if (bp->flags & BNXT_FLAG_CHIP_P5) {
		spin_lock_bh(&ptp->ptp_lock);
@@ -768,6 +881,11 @@ int bnxt_ptp_init(struct bnxt *bp)
		ptp_schedule_worker(ptp->ptp_clock, 0);
	}
	return 0;

out:
	bnxt_ptp_free(bp);
	bnxt_unmap_ptp_regs(bp);
	return rc;
}

void bnxt_ptp_clear(struct bnxt *bp)
+4 −1
Original line number Diff line number Diff line
@@ -131,12 +131,15 @@ do { \
#endif

int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id, u16 *hdr_off);
void bnxt_ptp_update_current_time(struct bnxt *bp);
void bnxt_ptp_pps_event(struct bnxt *bp, u32 data1, u32 data2);
void bnxt_ptp_reapply_pps(struct bnxt *bp);
int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr);
int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr);
int bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb);
int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts);
int bnxt_ptp_init(struct bnxt *bp);
void bnxt_ptp_rtc_timecounter_init(struct bnxt_ptp_cfg *ptp, u64 ns);
int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg);
int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg);
void bnxt_ptp_clear(struct bnxt *bp);
#endif