forked from Minki/linux
Merge branch 'octeontx2-ptp-updates'
Rakesh Babu Saladi says: ==================== RVU AF and NETDEV drivers' PTP updates. Patch 1: Add suppot such that RVU drivers support new timestamp format. Patch 2: This patch adds workaround for PTP errata. Changes made from v1 to v2 1. CC'd Richard Cochran to review PTP related patches. 2. Removed a patch from the old patch series. Will submit the removed patch separately. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
7b779cc884
@ -25,6 +25,9 @@
|
||||
#define PCI_SUBSYS_DEVID_OCTX2_95XXO_PTP 0xB600
|
||||
#define PCI_DEVID_OCTEONTX2_RST 0xA085
|
||||
#define PCI_DEVID_CN10K_PTP 0xA09E
|
||||
#define PCI_SUBSYS_DEVID_CN10K_A_PTP 0xB900
|
||||
#define PCI_SUBSYS_DEVID_CNF10K_A_PTP 0xBA00
|
||||
#define PCI_SUBSYS_DEVID_CNF10K_B_PTP 0xBC00
|
||||
|
||||
#define PCI_PTP_BAR_NO 0
|
||||
|
||||
@ -46,10 +49,105 @@
|
||||
#define PTP_CLOCK_HI 0xF10ULL
|
||||
#define PTP_CLOCK_COMP 0xF18ULL
|
||||
#define PTP_TIMESTAMP 0xF20ULL
|
||||
#define PTP_CLOCK_SEC 0xFD0ULL
|
||||
|
||||
#define CYCLE_MULT 1000
|
||||
|
||||
static struct ptp *first_ptp_block;
|
||||
static const struct pci_device_id ptp_id_table[];
|
||||
|
||||
static bool cn10k_ptp_errata(struct ptp *ptp)
|
||||
{
|
||||
if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP ||
|
||||
ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_ptp_tsfmt_sec_nsec(struct ptp *ptp)
|
||||
{
|
||||
if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP ||
|
||||
ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static u64 read_ptp_tstmp_sec_nsec(struct ptp *ptp)
|
||||
{
|
||||
u64 sec, sec1, nsec;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ptp->ptp_lock, flags);
|
||||
sec = readq(ptp->reg_base + PTP_CLOCK_SEC) & 0xFFFFFFFFUL;
|
||||
nsec = readq(ptp->reg_base + PTP_CLOCK_HI);
|
||||
sec1 = readq(ptp->reg_base + PTP_CLOCK_SEC) & 0xFFFFFFFFUL;
|
||||
/* check nsec rollover */
|
||||
if (sec1 > sec) {
|
||||
nsec = readq(ptp->reg_base + PTP_CLOCK_HI);
|
||||
sec = sec1;
|
||||
}
|
||||
spin_unlock_irqrestore(&ptp->ptp_lock, flags);
|
||||
|
||||
return sec * NSEC_PER_SEC + nsec;
|
||||
}
|
||||
|
||||
static u64 read_ptp_tstmp_nsec(struct ptp *ptp)
|
||||
{
|
||||
return readq(ptp->reg_base + PTP_CLOCK_HI);
|
||||
}
|
||||
|
||||
static u64 ptp_calc_adjusted_comp(u64 ptp_clock_freq)
|
||||
{
|
||||
u64 comp, adj = 0, cycles_per_sec, ns_drift = 0;
|
||||
u32 ptp_clock_nsec, cycle_time;
|
||||
int cycle;
|
||||
|
||||
/* Errata:
|
||||
* Issue #1: At the time of 1 sec rollover of the nano-second counter,
|
||||
* the nano-second counter is set to 0. However, it should be set to
|
||||
* (existing counter_value - 10^9).
|
||||
*
|
||||
* Issue #2: The nano-second counter rolls over at 0x3B9A_C9FF.
|
||||
* It should roll over at 0x3B9A_CA00.
|
||||
*/
|
||||
|
||||
/* calculate ptp_clock_comp value */
|
||||
comp = ((u64)1000000000ULL << 32) / ptp_clock_freq;
|
||||
/* use CYCLE_MULT to avoid accuracy loss due to integer arithmetic */
|
||||
cycle_time = NSEC_PER_SEC * CYCLE_MULT / ptp_clock_freq;
|
||||
/* cycles per sec */
|
||||
cycles_per_sec = ptp_clock_freq;
|
||||
|
||||
/* check whether ptp nanosecond counter rolls over early */
|
||||
cycle = cycles_per_sec - 1;
|
||||
ptp_clock_nsec = (cycle * comp) >> 32;
|
||||
while (ptp_clock_nsec < NSEC_PER_SEC) {
|
||||
if (ptp_clock_nsec == 0x3B9AC9FF)
|
||||
goto calc_adj_comp;
|
||||
cycle++;
|
||||
ptp_clock_nsec = (cycle * comp) >> 32;
|
||||
}
|
||||
/* compute nanoseconds lost per second when nsec counter rolls over */
|
||||
ns_drift = ptp_clock_nsec - NSEC_PER_SEC;
|
||||
/* calculate ptp_clock_comp adjustment */
|
||||
if (ns_drift > 0) {
|
||||
adj = comp * ns_drift;
|
||||
adj = adj / 1000000000ULL;
|
||||
}
|
||||
/* speed up the ptp clock to account for nanoseconds lost */
|
||||
comp += adj;
|
||||
return comp;
|
||||
|
||||
calc_adj_comp:
|
||||
/* slow down the ptp clock to not rollover early */
|
||||
adj = comp * cycle_time;
|
||||
adj = adj / 1000000000ULL;
|
||||
adj = adj / CYCLE_MULT;
|
||||
comp -= adj;
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
struct ptp *ptp_get(void)
|
||||
{
|
||||
struct ptp *ptp = first_ptp_block;
|
||||
@ -77,8 +175,8 @@ void ptp_put(struct ptp *ptp)
|
||||
static int ptp_adjfine(struct ptp *ptp, long scaled_ppm)
|
||||
{
|
||||
bool neg_adj = false;
|
||||
u64 comp;
|
||||
u64 adj;
|
||||
u32 freq, freq_adj;
|
||||
u64 comp, adj;
|
||||
s64 ppb;
|
||||
|
||||
if (scaled_ppm < 0) {
|
||||
@ -100,15 +198,22 @@ static int ptp_adjfine(struct ptp *ptp, long scaled_ppm)
|
||||
* where tbase is the basic compensation value calculated
|
||||
* initialy in the probe function.
|
||||
*/
|
||||
comp = ((u64)1000000000ull << 32) / ptp->clock_rate;
|
||||
/* convert scaled_ppm to ppb */
|
||||
ppb = 1 + scaled_ppm;
|
||||
ppb *= 125;
|
||||
ppb >>= 13;
|
||||
adj = comp * ppb;
|
||||
adj = div_u64(adj, 1000000000ull);
|
||||
comp = neg_adj ? comp - adj : comp + adj;
|
||||
|
||||
if (cn10k_ptp_errata(ptp)) {
|
||||
/* calculate the new frequency based on ppb */
|
||||
freq_adj = (ptp->clock_rate * ppb) / 1000000000ULL;
|
||||
freq = neg_adj ? ptp->clock_rate + freq_adj : ptp->clock_rate - freq_adj;
|
||||
comp = ptp_calc_adjusted_comp(freq);
|
||||
} else {
|
||||
comp = ((u64)1000000000ull << 32) / ptp->clock_rate;
|
||||
adj = comp * ppb;
|
||||
adj = div_u64(adj, 1000000000ull);
|
||||
comp = neg_adj ? comp - adj : comp + adj;
|
||||
}
|
||||
writeq(comp, ptp->reg_base + PTP_CLOCK_COMP);
|
||||
|
||||
return 0;
|
||||
@ -117,7 +222,7 @@ static int ptp_adjfine(struct ptp *ptp, long scaled_ppm)
|
||||
static int ptp_get_clock(struct ptp *ptp, u64 *clk)
|
||||
{
|
||||
/* Return the current PTP clock */
|
||||
*clk = readq(ptp->reg_base + PTP_CLOCK_HI);
|
||||
*clk = ptp->read_ptp_tstmp(ptp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -166,7 +271,11 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
|
||||
writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_HI_INCR);
|
||||
writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_LO_INCR);
|
||||
|
||||
clock_comp = ((u64)1000000000ull << 32) / ptp->clock_rate;
|
||||
if (cn10k_ptp_errata(ptp))
|
||||
clock_comp = ptp_calc_adjusted_comp(ptp->clock_rate);
|
||||
else
|
||||
clock_comp = ((u64)1000000000ull << 32) / ptp->clock_rate;
|
||||
|
||||
/* Initial compensation value to start the nanosecs counter */
|
||||
writeq(clock_comp, ptp->reg_base + PTP_CLOCK_COMP);
|
||||
}
|
||||
@ -214,6 +323,12 @@ static int ptp_probe(struct pci_dev *pdev,
|
||||
if (!first_ptp_block)
|
||||
first_ptp_block = ptp;
|
||||
|
||||
spin_lock_init(&ptp->ptp_lock);
|
||||
if (is_ptp_tsfmt_sec_nsec(ptp))
|
||||
ptp->read_ptp_tstmp = &read_ptp_tstmp_sec_nsec;
|
||||
else
|
||||
ptp->read_ptp_tstmp = &read_ptp_tstmp_nsec;
|
||||
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
|
@ -15,6 +15,8 @@
|
||||
struct ptp {
|
||||
struct pci_dev *pdev;
|
||||
void __iomem *reg_base;
|
||||
u64 (*read_ptp_tstmp)(struct ptp *ptp);
|
||||
spinlock_t ptp_lock; /* lock */
|
||||
u32 clock_rate;
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/soc/marvell/octeontx2/asm.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/devlink.h>
|
||||
#include <linux/time64.h>
|
||||
|
||||
#include <mbox.h>
|
||||
#include <npc.h>
|
||||
@ -275,6 +276,8 @@ struct otx2_ptp {
|
||||
u64 thresh;
|
||||
|
||||
struct ptp_pin_desc extts_config;
|
||||
u64 (*convert_rx_ptp_tstmp)(u64 timestamp);
|
||||
u64 (*convert_tx_ptp_tstmp)(u64 timestamp);
|
||||
};
|
||||
|
||||
#define OTX2_HW_TIMESTAMP_LEN 8
|
||||
|
@ -294,6 +294,14 @@ int otx2_ptp_init(struct otx2_nic *pfvf)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (is_dev_otx2(pfvf->pdev)) {
|
||||
ptp_ptr->convert_rx_ptp_tstmp = &otx2_ptp_convert_rx_timestamp;
|
||||
ptp_ptr->convert_tx_ptp_tstmp = &otx2_ptp_convert_tx_timestamp;
|
||||
} else {
|
||||
ptp_ptr->convert_rx_ptp_tstmp = &cn10k_ptp_convert_timestamp;
|
||||
ptp_ptr->convert_tx_ptp_tstmp = &cn10k_ptp_convert_timestamp;
|
||||
}
|
||||
|
||||
pfvf->ptp = ptp_ptr;
|
||||
|
||||
error:
|
||||
|
@ -8,6 +8,21 @@
|
||||
#ifndef OTX2_PTP_H
|
||||
#define OTX2_PTP_H
|
||||
|
||||
static inline u64 otx2_ptp_convert_rx_timestamp(u64 timestamp)
|
||||
{
|
||||
return be64_to_cpu(*(__be64 *)×tamp);
|
||||
}
|
||||
|
||||
static inline u64 otx2_ptp_convert_tx_timestamp(u64 timestamp)
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
static inline u64 cn10k_ptp_convert_timestamp(u64 timestamp)
|
||||
{
|
||||
return ((timestamp >> 32) * NSEC_PER_SEC) + (timestamp & 0xFFFFFFFFUL);
|
||||
}
|
||||
|
||||
int otx2_ptp_init(struct otx2_nic *pfvf);
|
||||
void otx2_ptp_destroy(struct otx2_nic *pfvf);
|
||||
|
||||
|
@ -148,6 +148,7 @@ static void otx2_snd_pkt_handler(struct otx2_nic *pfvf,
|
||||
if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) {
|
||||
timestamp = ((u64 *)sq->timestamps->base)[snd_comp->sqe_id];
|
||||
if (timestamp != 1) {
|
||||
timestamp = pfvf->ptp->convert_tx_ptp_tstmp(timestamp);
|
||||
err = otx2_ptp_tstamp2time(pfvf, timestamp, &tsns);
|
||||
if (!err) {
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
@ -167,14 +168,15 @@ static void otx2_snd_pkt_handler(struct otx2_nic *pfvf,
|
||||
static void otx2_set_rxtstamp(struct otx2_nic *pfvf,
|
||||
struct sk_buff *skb, void *data)
|
||||
{
|
||||
u64 tsns;
|
||||
u64 timestamp, tsns;
|
||||
int err;
|
||||
|
||||
if (!(pfvf->flags & OTX2_FLAG_RX_TSTAMP_ENABLED))
|
||||
return;
|
||||
|
||||
timestamp = pfvf->ptp->convert_rx_ptp_tstmp(*(u64 *)data);
|
||||
/* The first 8 bytes is the timestamp */
|
||||
err = otx2_ptp_tstamp2time(pfvf, be64_to_cpu(*(__be64 *)data), &tsns);
|
||||
err = otx2_ptp_tstamp2time(pfvf, timestamp, &tsns);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user