Commit bdf79b12 authored by Sai Krishna's avatar Sai Krishna Committed by David S. Miller

octeontx2-pf: Use PTP HW timestamp counter atomic update feature

Some of the newer silicon versions in CN10K series supports a feature
where in the current PTP timestamp in HW can be updated atomically
without losing any cpu cycles unlike read/modify/write register.
This patch uses this feature so that PTP accuracy can be improved
while adjusting the master offset in HW. There is no need for SW
timecounter when using this feature. So removed references to SW
timecounter wherever appropriate.
Signed-off-by: default avatarSai Krishna <saikrishnag@marvell.com>
Signed-off-by: default avatarNaveen Mamindlapalli <naveenm@marvell.com>
Signed-off-by: default avatarSunil Kovvuri Goutham <sgoutham@marvell.com>
Reviewed-by: default avatarKalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Reviewed-by: default avatarLeon Romanovsky <leonro@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6176b8c4
...@@ -136,6 +136,7 @@ M(GET_HW_CAP, 0x008, get_hw_cap, msg_req, get_hw_cap_rsp) \ ...@@ -136,6 +136,7 @@ M(GET_HW_CAP, 0x008, get_hw_cap, msg_req, get_hw_cap_rsp) \
M(LMTST_TBL_SETUP, 0x00a, lmtst_tbl_setup, lmtst_tbl_setup_req, \ M(LMTST_TBL_SETUP, 0x00a, lmtst_tbl_setup, lmtst_tbl_setup_req, \
msg_rsp) \ msg_rsp) \
M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \ M(SET_VF_PERM, 0x00b, set_vf_perm, set_vf_perm, msg_rsp) \
M(PTP_GET_CAP, 0x00c, ptp_get_cap, msg_req, ptp_get_cap_rsp) \
/* CGX mbox IDs (range 0x200 - 0x3FF) */ \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \
M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \ M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \
M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \ M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \
...@@ -1437,6 +1438,12 @@ struct npc_get_kex_cfg_rsp { ...@@ -1437,6 +1438,12 @@ struct npc_get_kex_cfg_rsp {
u8 mkex_pfl_name[MKEX_NAME_LEN]; u8 mkex_pfl_name[MKEX_NAME_LEN];
}; };
struct ptp_get_cap_rsp {
struct mbox_msghdr hdr;
#define PTP_CAP_HW_ATOMIC_UPDATE BIT_ULL(0)
u64 cap;
};
struct flow_msg { struct flow_msg {
unsigned char dmac[6]; unsigned char dmac[6];
unsigned char smac[6]; unsigned char smac[6];
...@@ -1568,6 +1575,8 @@ enum ptp_op { ...@@ -1568,6 +1575,8 @@ enum ptp_op {
PTP_OP_GET_TSTMP = 2, PTP_OP_GET_TSTMP = 2,
PTP_OP_SET_THRESH = 3, PTP_OP_SET_THRESH = 3,
PTP_OP_EXTTS_ON = 4, PTP_OP_EXTTS_ON = 4,
PTP_OP_ADJTIME = 5,
PTP_OP_SET_CLOCK = 6,
}; };
struct ptp_req { struct ptp_req {
...@@ -1576,11 +1585,14 @@ struct ptp_req { ...@@ -1576,11 +1585,14 @@ struct ptp_req {
s64 scaled_ppm; s64 scaled_ppm;
u64 thresh; u64 thresh;
int extts_on; int extts_on;
s64 delta;
u64 clk;
}; };
struct ptp_rsp { struct ptp_rsp {
struct mbox_msghdr hdr; struct mbox_msghdr hdr;
u64 clk; u64 clk;
u64 tsc;
}; };
struct npc_get_field_status_req { struct npc_get_field_status_req {
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/ktime.h> #include <linux/ktime.h>
#include "ptp.h"
#include "mbox.h" #include "mbox.h"
#include "ptp.h"
#include "rvu.h" #include "rvu.h"
#define DRV_NAME "Marvell PTP Driver" #define DRV_NAME "Marvell PTP Driver"
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define PTP_CLOCK_CFG_TSTMP_EDGE BIT_ULL(9) #define PTP_CLOCK_CFG_TSTMP_EDGE BIT_ULL(9)
#define PTP_CLOCK_CFG_TSTMP_EN BIT_ULL(8) #define PTP_CLOCK_CFG_TSTMP_EN BIT_ULL(8)
#define PTP_CLOCK_CFG_TSTMP_IN_MASK GENMASK_ULL(15, 10) #define PTP_CLOCK_CFG_TSTMP_IN_MASK GENMASK_ULL(15, 10)
#define PTP_CLOCK_CFG_ATOMIC_OP_MASK GENMASK_ULL(28, 26)
#define PTP_CLOCK_CFG_PPS_EN BIT_ULL(30) #define PTP_CLOCK_CFG_PPS_EN BIT_ULL(30)
#define PTP_CLOCK_CFG_PPS_INV BIT_ULL(31) #define PTP_CLOCK_CFG_PPS_INV BIT_ULL(31)
...@@ -53,36 +54,62 @@ ...@@ -53,36 +54,62 @@
#define PTP_TIMESTAMP 0xF20ULL #define PTP_TIMESTAMP 0xF20ULL
#define PTP_CLOCK_SEC 0xFD0ULL #define PTP_CLOCK_SEC 0xFD0ULL
#define PTP_SEC_ROLLOVER 0xFD8ULL #define PTP_SEC_ROLLOVER 0xFD8ULL
/* Atomic update related CSRs */
#define PTP_FRNS_TIMESTAMP 0xFE0ULL
#define PTP_NXT_ROLLOVER_SET 0xFE8ULL
#define PTP_CURR_ROLLOVER_SET 0xFF0ULL
#define PTP_NANO_TIMESTAMP 0xFF8ULL
#define PTP_SEC_TIMESTAMP 0x1000ULL
#define CYCLE_MULT 1000 #define CYCLE_MULT 1000
#define is_rev_A0(ptp) (((ptp)->pdev->revision & 0x0F) == 0x0)
#define is_rev_A1(ptp) (((ptp)->pdev->revision & 0x0F) == 0x1)
/* PTP atomic update operation type */
enum atomic_opcode {
ATOMIC_SET = 1,
ATOMIC_INC = 3,
ATOMIC_DEC = 4
};
static struct ptp *first_ptp_block; static struct ptp *first_ptp_block;
static const struct pci_device_id ptp_id_table[]; static const struct pci_device_id ptp_id_table[];
static bool is_ptp_dev_cnf10kb(struct ptp *ptp) static bool is_ptp_dev_cnf10ka(struct ptp *ptp)
{ {
return ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_B_PTP; return ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP;
} }
static bool is_ptp_dev_cn10k(struct ptp *ptp) static bool is_ptp_dev_cn10ka(struct ptp *ptp)
{ {
return ptp->pdev->device == PCI_DEVID_CN10K_PTP; return ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP;
} }
static bool cn10k_ptp_errata(struct ptp *ptp) static bool cn10k_ptp_errata(struct ptp *ptp)
{ {
if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP || if ((is_ptp_dev_cn10ka(ptp) || is_ptp_dev_cnf10ka(ptp)) &&
ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP) (is_rev_A0(ptp) || is_rev_A1(ptp)))
return true; return true;
return false; return false;
} }
static bool is_ptp_tsfmt_sec_nsec(struct ptp *ptp) static bool is_tstmp_atomic_update_supported(struct rvu *rvu)
{ {
if (ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CN10K_A_PTP || struct ptp *ptp = rvu->ptp;
ptp->pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A_PTP)
return true; if (is_rvu_otx2(rvu))
return false; return false;
/* On older silicon variants of CN10K, atomic update feature
* is not available.
*/
if ((is_ptp_dev_cn10ka(ptp) || is_ptp_dev_cnf10ka(ptp)) &&
(is_rev_A0(ptp) || is_rev_A1(ptp)))
return false;
return true;
} }
static enum hrtimer_restart ptp_reset_thresh(struct hrtimer *hrtimer) static enum hrtimer_restart ptp_reset_thresh(struct hrtimer *hrtimer)
...@@ -222,6 +249,65 @@ void ptp_put(struct ptp *ptp) ...@@ -222,6 +249,65 @@ void ptp_put(struct ptp *ptp)
pci_dev_put(ptp->pdev); pci_dev_put(ptp->pdev);
} }
static void ptp_atomic_update(struct ptp *ptp, u64 timestamp)
{
u64 regval, curr_rollover_set, nxt_rollover_set;
/* First setup NSECs and SECs */
writeq(timestamp, ptp->reg_base + PTP_NANO_TIMESTAMP);
writeq(0, ptp->reg_base + PTP_FRNS_TIMESTAMP);
writeq(timestamp / NSEC_PER_SEC,
ptp->reg_base + PTP_SEC_TIMESTAMP);
nxt_rollover_set = roundup(timestamp, NSEC_PER_SEC);
curr_rollover_set = nxt_rollover_set - NSEC_PER_SEC;
writeq(nxt_rollover_set, ptp->reg_base + PTP_NXT_ROLLOVER_SET);
writeq(curr_rollover_set, ptp->reg_base + PTP_CURR_ROLLOVER_SET);
/* Now, initiate atomic update */
regval = readq(ptp->reg_base + PTP_CLOCK_CFG);
regval &= ~PTP_CLOCK_CFG_ATOMIC_OP_MASK;
regval |= (ATOMIC_SET << 26);
writeq(regval, ptp->reg_base + PTP_CLOCK_CFG);
}
static void ptp_atomic_adjtime(struct ptp *ptp, s64 delta)
{
bool neg_adj = false, atomic_inc_dec = false;
u64 regval, ptp_clock_hi;
if (delta < 0) {
delta = -delta;
neg_adj = true;
}
/* use atomic inc/dec when delta < 1 second */
if (delta < NSEC_PER_SEC)
atomic_inc_dec = true;
if (!atomic_inc_dec) {
ptp_clock_hi = readq(ptp->reg_base + PTP_CLOCK_HI);
if (neg_adj) {
if (ptp_clock_hi > delta)
ptp_clock_hi -= delta;
else
ptp_clock_hi = delta - ptp_clock_hi;
} else {
ptp_clock_hi += delta;
}
ptp_atomic_update(ptp, ptp_clock_hi);
} else {
writeq(delta, ptp->reg_base + PTP_NANO_TIMESTAMP);
writeq(0, ptp->reg_base + PTP_FRNS_TIMESTAMP);
/* initiate atomic inc/dec */
regval = readq(ptp->reg_base + PTP_CLOCK_CFG);
regval &= ~PTP_CLOCK_CFG_ATOMIC_OP_MASK;
regval |= neg_adj ? (ATOMIC_DEC << 26) : (ATOMIC_INC << 26);
writeq(regval, ptp->reg_base + PTP_CLOCK_CFG);
}
}
static int ptp_adjfine(struct ptp *ptp, long scaled_ppm) static int ptp_adjfine(struct ptp *ptp, long scaled_ppm)
{ {
bool neg_adj = false; bool neg_adj = false;
...@@ -277,8 +363,9 @@ static int ptp_get_clock(struct ptp *ptp, u64 *clk) ...@@ -277,8 +363,9 @@ static int ptp_get_clock(struct ptp *ptp, u64 *clk)
return 0; return 0;
} }
void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts) void ptp_start(struct rvu *rvu, u64 sclk, u32 ext_clk_freq, u32 extts)
{ {
struct ptp *ptp = rvu->ptp;
struct pci_dev *pdev; struct pci_dev *pdev;
u64 clock_comp; u64 clock_comp;
u64 clock_cfg; u64 clock_cfg;
...@@ -297,8 +384,14 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts) ...@@ -297,8 +384,14 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
ptp->clock_rate = sclk * 1000000; ptp->clock_rate = sclk * 1000000;
/* Program the seconds rollover value to 1 second */ /* Program the seconds rollover value to 1 second */
if (is_ptp_dev_cnf10kb(ptp)) if (is_tstmp_atomic_update_supported(rvu)) {
writeq(0, ptp->reg_base + PTP_NANO_TIMESTAMP);
writeq(0, ptp->reg_base + PTP_FRNS_TIMESTAMP);
writeq(0, ptp->reg_base + PTP_SEC_TIMESTAMP);
writeq(0, ptp->reg_base + PTP_CURR_ROLLOVER_SET);
writeq(0x3b9aca00, ptp->reg_base + PTP_NXT_ROLLOVER_SET);
writeq(0x3b9aca00, ptp->reg_base + PTP_SEC_ROLLOVER); writeq(0x3b9aca00, ptp->reg_base + PTP_SEC_ROLLOVER);
}
/* Enable PTP clock */ /* Enable PTP clock */
clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG); clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG);
...@@ -320,6 +413,10 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts) ...@@ -320,6 +413,10 @@ void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts)
clock_cfg |= PTP_CLOCK_CFG_PTP_EN; clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
clock_cfg |= PTP_CLOCK_CFG_PPS_EN | PTP_CLOCK_CFG_PPS_INV; clock_cfg |= PTP_CLOCK_CFG_PPS_EN | PTP_CLOCK_CFG_PPS_INV;
writeq(clock_cfg, ptp->reg_base + PTP_CLOCK_CFG); writeq(clock_cfg, ptp->reg_base + PTP_CLOCK_CFG);
clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG);
clock_cfg &= ~PTP_CLOCK_CFG_ATOMIC_OP_MASK;
clock_cfg |= (ATOMIC_SET << 26);
writeq(clock_cfg, ptp->reg_base + PTP_CLOCK_CFG);
/* Set 50% duty cycle for 1Hz output */ /* Set 50% duty cycle for 1Hz output */
writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_HI_INCR); writeq(0x1dcd650000000000, ptp->reg_base + PTP_PPS_HI_INCR);
...@@ -350,7 +447,7 @@ static int ptp_get_tstmp(struct ptp *ptp, u64 *clk) ...@@ -350,7 +447,7 @@ static int ptp_get_tstmp(struct ptp *ptp, u64 *clk)
{ {
u64 timestamp; u64 timestamp;
if (is_ptp_dev_cn10k(ptp)) { if (is_ptp_dev_cn10ka(ptp) || is_ptp_dev_cnf10ka(ptp)) {
timestamp = readq(ptp->reg_base + PTP_TIMESTAMP); timestamp = readq(ptp->reg_base + PTP_TIMESTAMP);
*clk = (timestamp >> 32) * NSEC_PER_SEC + (timestamp & 0xFFFFFFFF); *clk = (timestamp >> 32) * NSEC_PER_SEC + (timestamp & 0xFFFFFFFF);
} else { } else {
...@@ -414,14 +511,12 @@ static int ptp_probe(struct pci_dev *pdev, ...@@ -414,14 +511,12 @@ static int ptp_probe(struct pci_dev *pdev,
first_ptp_block = ptp; first_ptp_block = ptp;
spin_lock_init(&ptp->ptp_lock); 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;
if (cn10k_ptp_errata(ptp)) { if (cn10k_ptp_errata(ptp)) {
ptp->read_ptp_tstmp = &read_ptp_tstmp_sec_nsec;
hrtimer_init(&ptp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hrtimer_init(&ptp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ptp->hrtimer.function = ptp_reset_thresh; ptp->hrtimer.function = ptp_reset_thresh;
} else {
ptp->read_ptp_tstmp = &read_ptp_tstmp_nsec;
} }
return 0; return 0;
...@@ -521,6 +616,12 @@ int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req, ...@@ -521,6 +616,12 @@ int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req,
case PTP_OP_EXTTS_ON: case PTP_OP_EXTTS_ON:
err = ptp_extts_on(rvu->ptp, req->extts_on); err = ptp_extts_on(rvu->ptp, req->extts_on);
break; break;
case PTP_OP_ADJTIME:
ptp_atomic_adjtime(rvu->ptp, req->delta);
break;
case PTP_OP_SET_CLOCK:
ptp_atomic_update(rvu->ptp, (u64)req->clk);
break;
default: default:
err = -EINVAL; err = -EINVAL;
break; break;
...@@ -528,3 +629,17 @@ int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req, ...@@ -528,3 +629,17 @@ int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req,
return err; return err;
} }
int rvu_mbox_handler_ptp_get_cap(struct rvu *rvu, struct msg_req *req,
struct ptp_get_cap_rsp *rsp)
{
if (!rvu->ptp)
return -ENODEV;
if (is_tstmp_atomic_update_supported(rvu))
rsp->cap |= PTP_CAP_HW_ATOMIC_UPDATE;
else
rsp->cap &= ~BIT_ULL_MASK(0);
return 0;
}
...@@ -23,9 +23,10 @@ struct ptp { ...@@ -23,9 +23,10 @@ struct ptp {
u32 clock_period; u32 clock_period;
}; };
struct rvu;
struct ptp *ptp_get(void); struct ptp *ptp_get(void);
void ptp_put(struct ptp *ptp); void ptp_put(struct ptp *ptp);
void ptp_start(struct ptp *ptp, u64 sclk, u32 ext_clk_freq, u32 extts); void ptp_start(struct rvu *rvu, u64 sclk, u32 ext_clk_freq, u32 extts);
extern struct pci_driver ptp_driver; extern struct pci_driver ptp_driver;
......
...@@ -3322,7 +3322,7 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -3322,7 +3322,7 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&rvu->rswitch.switch_lock); mutex_init(&rvu->rswitch.switch_lock);
if (rvu->fwdata) if (rvu->fwdata)
ptp_start(rvu->ptp, rvu->fwdata->sclk, rvu->fwdata->ptp_ext_clk_rate, ptp_start(rvu, rvu->fwdata->sclk, rvu->fwdata->ptp_ext_clk_rate,
rvu->fwdata->ptp_ext_tstamp); rvu->fwdata->ptp_ext_tstamp);
return 0; return 0;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "mbox.h" #include "mbox.h"
#include "npc.h" #include "npc.h"
#include "rvu_reg.h" #include "rvu_reg.h"
#include "ptp.h"
/* PCI device IDs */ /* PCI device IDs */
#define PCI_DEVID_OCTEONTX2_RVU_AF 0xA065 #define PCI_DEVID_OCTEONTX2_RVU_AF 0xA065
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
#define PCI_SUBSYS_DEVID_98XX 0xB100 #define PCI_SUBSYS_DEVID_98XX 0xB100
#define PCI_SUBSYS_DEVID_96XX 0xB200 #define PCI_SUBSYS_DEVID_96XX 0xB200
#define PCI_SUBSYS_DEVID_CN10K_A 0xB900 #define PCI_SUBSYS_DEVID_CN10K_A 0xB900
#define PCI_SUBSYS_DEVID_CNF10K_A 0xBA00
#define PCI_SUBSYS_DEVID_CNF10K_B 0xBC00 #define PCI_SUBSYS_DEVID_CNF10K_B 0xBC00
#define PCI_SUBSYS_DEVID_CN10K_B 0xBD00 #define PCI_SUBSYS_DEVID_CN10K_B 0xBD00
...@@ -634,6 +636,16 @@ static inline bool is_rvu_otx2(struct rvu *rvu) ...@@ -634,6 +636,16 @@ static inline bool is_rvu_otx2(struct rvu *rvu)
midr == PCI_REVISION_ID_95XXMM || midr == PCI_REVISION_ID_95XXO); midr == PCI_REVISION_ID_95XXMM || midr == PCI_REVISION_ID_95XXO);
} }
static inline bool is_cnf10ka_a0(struct rvu *rvu)
{
struct pci_dev *pdev = rvu->pdev;
if (pdev->subsystem_device == PCI_SUBSYS_DEVID_CNF10K_A &&
(pdev->revision & 0x0F) == 0x0)
return true;
return false;
}
static inline bool is_rvu_npc_hash_extract_en(struct rvu *rvu) static inline bool is_rvu_npc_hash_extract_en(struct rvu *rvu)
{ {
u64 npc_const3; u64 npc_const3;
......
...@@ -326,6 +326,7 @@ struct otx2_ptp { ...@@ -326,6 +326,7 @@ struct otx2_ptp {
struct ptp_pin_desc extts_config; struct ptp_pin_desc extts_config;
u64 (*convert_rx_ptp_tstmp)(u64 timestamp); u64 (*convert_rx_ptp_tstmp)(u64 timestamp);
u64 (*convert_tx_ptp_tstmp)(u64 timestamp); u64 (*convert_tx_ptp_tstmp)(u64 timestamp);
u64 (*ptp_tstamp2nsec)(const struct timecounter *time_counter, u64 timestamp);
struct delayed_work synctstamp_work; struct delayed_work synctstamp_work;
u64 tstamp; u64 tstamp;
u32 base_ns; u32 base_ns;
......
...@@ -10,6 +10,65 @@ ...@@ -10,6 +10,65 @@
#include "otx2_common.h" #include "otx2_common.h"
#include "otx2_ptp.h" #include "otx2_ptp.h"
static bool is_tstmp_atomic_update_supported(struct otx2_ptp *ptp)
{
struct ptp_get_cap_rsp *rsp;
struct msg_req *req;
int err;
if (!ptp->nic)
return false;
mutex_lock(&ptp->nic->mbox.lock);
req = otx2_mbox_alloc_msg_ptp_get_cap(&ptp->nic->mbox);
if (!req) {
mutex_unlock(&ptp->nic->mbox.lock);
return false;
}
err = otx2_sync_mbox_msg(&ptp->nic->mbox);
if (err) {
mutex_unlock(&ptp->nic->mbox.lock);
return false;
}
rsp = (struct ptp_get_cap_rsp *)otx2_mbox_get_rsp(&ptp->nic->mbox.mbox, 0,
&req->hdr);
mutex_unlock(&ptp->nic->mbox.lock);
if (IS_ERR(rsp))
return false;
if (rsp->cap & PTP_CAP_HW_ATOMIC_UPDATE)
return true;
return false;
}
static int otx2_ptp_hw_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
{
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info);
struct otx2_nic *pfvf = ptp->nic;
struct ptp_req *req;
int rc;
if (!ptp->nic)
return -ENODEV;
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}
req->op = PTP_OP_ADJTIME;
req->delta = delta;
rc = otx2_sync_mbox_msg(&ptp->nic->mbox);
mutex_unlock(&pfvf->mbox.lock);
return rc;
}
static u64 otx2_ptp_get_clock(struct otx2_ptp *ptp) static u64 otx2_ptp_get_clock(struct otx2_ptp *ptp)
{ {
struct ptp_req *req; struct ptp_req *req;
...@@ -37,6 +96,49 @@ static u64 otx2_ptp_get_clock(struct otx2_ptp *ptp) ...@@ -37,6 +96,49 @@ static u64 otx2_ptp_get_clock(struct otx2_ptp *ptp)
return rsp->clk; return rsp->clk;
} }
static int otx2_ptp_hw_gettime(struct ptp_clock_info *ptp_info,
struct timespec64 *ts)
{
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info);
u64 tstamp;
tstamp = otx2_ptp_get_clock(ptp);
*ts = ns_to_timespec64(tstamp);
return 0;
}
static int otx2_ptp_hw_settime(struct ptp_clock_info *ptp_info,
const struct timespec64 *ts)
{
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info);
struct otx2_nic *pfvf = ptp->nic;
struct ptp_req *req;
u64 nsec;
int rc;
if (!ptp->nic)
return -ENODEV;
nsec = timespec64_to_ns(ts);
mutex_lock(&pfvf->mbox.lock);
req = otx2_mbox_alloc_msg_ptp_op(&ptp->nic->mbox);
if (!req) {
mutex_unlock(&pfvf->mbox.lock);
return -ENOMEM;
}
req->op = PTP_OP_SET_CLOCK;
req->clk = nsec;
rc = otx2_sync_mbox_msg(&ptp->nic->mbox);
mutex_unlock(&pfvf->mbox.lock);
return rc;
}
static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) static int otx2_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
{ {
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
...@@ -124,16 +226,7 @@ static u64 ptp_tstmp_read(struct otx2_ptp *ptp) ...@@ -124,16 +226,7 @@ static u64 ptp_tstmp_read(struct otx2_ptp *ptp)
return rsp->clk; return rsp->clk;
} }
static void otx2_get_ptpclock(struct otx2_ptp *ptp, u64 *tstamp) static int otx2_ptp_tc_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
{
struct otx2_nic *pfvf = ptp->nic;
mutex_lock(&pfvf->mbox.lock);
*tstamp = timecounter_read(&ptp->time_counter);
mutex_unlock(&pfvf->mbox.lock);
}
static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
{ {
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info); ptp_info);
...@@ -146,32 +239,33 @@ static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta) ...@@ -146,32 +239,33 @@ static int otx2_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
return 0; return 0;
} }
static int otx2_ptp_gettime(struct ptp_clock_info *ptp_info, static int otx2_ptp_tc_gettime(struct ptp_clock_info *ptp_info,
struct timespec64 *ts) struct timespec64 *ts)
{ {
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info); ptp_info);
u64 tstamp; u64 tstamp;
otx2_get_ptpclock(ptp, &tstamp); mutex_lock(&ptp->nic->mbox.lock);
tstamp = timecounter_read(&ptp->time_counter);
mutex_unlock(&ptp->nic->mbox.lock);
*ts = ns_to_timespec64(tstamp); *ts = ns_to_timespec64(tstamp);
return 0; return 0;
} }
static int otx2_ptp_settime(struct ptp_clock_info *ptp_info, static int otx2_ptp_tc_settime(struct ptp_clock_info *ptp_info,
const struct timespec64 *ts) const struct timespec64 *ts)
{ {
struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp, struct otx2_ptp *ptp = container_of(ptp_info, struct otx2_ptp,
ptp_info); ptp_info);
struct otx2_nic *pfvf = ptp->nic;
u64 nsec; u64 nsec;
nsec = timespec64_to_ns(ts); nsec = timespec64_to_ns(ts);
mutex_lock(&pfvf->mbox.lock); mutex_lock(&ptp->nic->mbox.lock);
timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec); timecounter_init(&ptp->time_counter, &ptp->cycle_counter, nsec);
mutex_unlock(&pfvf->mbox.lock); mutex_unlock(&ptp->nic->mbox.lock);
return 0; return 0;
} }
...@@ -190,6 +284,12 @@ static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, ...@@ -190,6 +284,12 @@ static int otx2_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
return 0; return 0;
} }
static u64 otx2_ptp_hw_tstamp2time(const struct timecounter *time_counter, u64 tstamp)
{
/* On HW which supports atomic updates, timecounter is not initialized */
return tstamp;
}
static void otx2_ptp_extts_check(struct work_struct *work) static void otx2_ptp_extts_check(struct work_struct *work)
{ {
struct otx2_ptp *ptp = container_of(work, struct otx2_ptp, struct otx2_ptp *ptp = container_of(work, struct otx2_ptp,
...@@ -204,7 +304,7 @@ static void otx2_ptp_extts_check(struct work_struct *work) ...@@ -204,7 +304,7 @@ static void otx2_ptp_extts_check(struct work_struct *work)
if (tstmp != ptp->last_extts) { if (tstmp != ptp->last_extts) {
event.type = PTP_CLOCK_EXTTS; event.type = PTP_CLOCK_EXTTS;
event.index = 0; event.index = 0;
event.timestamp = timecounter_cyc2time(&ptp->time_counter, tstmp); event.timestamp = ptp->ptp_tstamp2nsec(&ptp->time_counter, tstmp);
ptp_clock_event(ptp->ptp_clock, &event); ptp_clock_event(ptp->ptp_clock, &event);
new_thresh = tstmp % 500000000; new_thresh = tstmp % 500000000;
if (ptp->thresh != new_thresh) { if (ptp->thresh != new_thresh) {
...@@ -229,7 +329,7 @@ static void otx2_sync_tstamp(struct work_struct *work) ...@@ -229,7 +329,7 @@ static void otx2_sync_tstamp(struct work_struct *work)
tstamp = otx2_ptp_get_clock(ptp); tstamp = otx2_ptp_get_clock(ptp);
mutex_unlock(&pfvf->mbox.lock); mutex_unlock(&pfvf->mbox.lock);
ptp->tstamp = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp); ptp->tstamp = ptp->ptp_tstamp2nsec(&ptp->time_counter, tstamp);
ptp->base_ns = tstamp % NSEC_PER_SEC; ptp->base_ns = tstamp % NSEC_PER_SEC;
schedule_delayed_work(&ptp->synctstamp_work, msecs_to_jiffies(250)); schedule_delayed_work(&ptp->synctstamp_work, msecs_to_jiffies(250));
...@@ -302,15 +402,6 @@ int otx2_ptp_init(struct otx2_nic *pfvf) ...@@ -302,15 +402,6 @@ int otx2_ptp_init(struct otx2_nic *pfvf)
ptp_ptr->nic = pfvf; ptp_ptr->nic = pfvf;
cc = &ptp_ptr->cycle_counter;
cc->read = ptp_cc_read;
cc->mask = CYCLECOUNTER_MASK(64);
cc->mult = 1;
cc->shift = 0;
timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
ktime_to_ns(ktime_get_real()));
snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP"); snprintf(ptp_ptr->extts_config.name, sizeof(ptp_ptr->extts_config.name), "TSTAMP");
ptp_ptr->extts_config.index = 0; ptp_ptr->extts_config.index = 0;
ptp_ptr->extts_config.func = PTP_PF_NONE; ptp_ptr->extts_config.func = PTP_PF_NONE;
...@@ -324,13 +415,33 @@ int otx2_ptp_init(struct otx2_nic *pfvf) ...@@ -324,13 +415,33 @@ int otx2_ptp_init(struct otx2_nic *pfvf)
.pps = 0, .pps = 0,
.pin_config = &ptp_ptr->extts_config, .pin_config = &ptp_ptr->extts_config,
.adjfine = otx2_ptp_adjfine, .adjfine = otx2_ptp_adjfine,
.adjtime = otx2_ptp_adjtime,
.gettime64 = otx2_ptp_gettime,
.settime64 = otx2_ptp_settime,
.enable = otx2_ptp_enable, .enable = otx2_ptp_enable,
.verify = otx2_ptp_verify_pin, .verify = otx2_ptp_verify_pin,
}; };
/* Check whether hardware supports atomic updates to timestamp */
if (is_tstmp_atomic_update_supported(ptp_ptr)) {
ptp_ptr->ptp_info.adjtime = otx2_ptp_hw_adjtime;
ptp_ptr->ptp_info.gettime64 = otx2_ptp_hw_gettime;
ptp_ptr->ptp_info.settime64 = otx2_ptp_hw_settime;
ptp_ptr->ptp_tstamp2nsec = otx2_ptp_hw_tstamp2time;
} else {
ptp_ptr->ptp_info.adjtime = otx2_ptp_tc_adjtime;
ptp_ptr->ptp_info.gettime64 = otx2_ptp_tc_gettime;
ptp_ptr->ptp_info.settime64 = otx2_ptp_tc_settime;
cc = &ptp_ptr->cycle_counter;
cc->read = ptp_cc_read;
cc->mask = CYCLECOUNTER_MASK(64);
cc->mult = 1;
cc->shift = 0;
ptp_ptr->ptp_tstamp2nsec = timecounter_cyc2time;
timecounter_init(&ptp_ptr->time_counter, &ptp_ptr->cycle_counter,
ktime_to_ns(ktime_get_real()));
}
INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check); INIT_DELAYED_WORK(&ptp_ptr->extts_work, otx2_ptp_extts_check);
ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev); ptp_ptr->ptp_clock = ptp_clock_register(&ptp_ptr->ptp_info, pfvf->dev);
...@@ -387,7 +498,7 @@ int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns) ...@@ -387,7 +498,7 @@ int otx2_ptp_tstamp2time(struct otx2_nic *pfvf, u64 tstamp, u64 *tsns)
if (!pfvf->ptp) if (!pfvf->ptp)
return -ENODEV; return -ENODEV;
*tsns = timecounter_cyc2time(&pfvf->ptp->time_counter, tstamp); *tsns = pfvf->ptp->ptp_tstamp2nsec(&pfvf->ptp->time_counter, tstamp);
return 0; return 0;
} }
......
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