2026-01-29 22:25:33 +08:00

685 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: GPL-2.0
/* Copyright(c) 2022 - 2024 Mucse Corporation. */
#include <linux/netdevice.h>
#include <linux/ptp_classify.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include "rnpgbe.h"
#include "rnpgbe_regs.h"
#include "rnpgbe_ptp.h"
#include "rnpgbe_mbx.h"
/* PTP and HW Timer ops */
static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
{
writel(data, ioaddr + PTP_TCR);
}
static void config_sub_second_increment(void __iomem *ioaddr, u32 ptp_clock,
int gmac4, u32 *ssinc)
{
u32 value = readl(ioaddr + PTP_TCR);
unsigned long data;
u32 reg_value;
/* For GMAC3.x, 4.x versions, in "fine adjustement mode" set sub-second
* increment to twice the number of nanoseconds of a clock cycle.
* The calculation of the default_addend value by the caller will set it
* to mid-range = 2^31 when the remainder of this division is zero,
* which will make the accumulator overflow once every 2 ptp_clock
* cycles, adding twice the number of nanoseconds of a clock cycle :
* 2000000000ULL / ptp_clock.
*/
if (value & RNP_PTP_TCR_TSCFUPDT)
data = (2000000000ULL / ptp_clock);
else
data = (1000000000ULL / ptp_clock);
/* 0.465ns accuracy */
if (!(value & RNP_PTP_TCR_TSCTRLSSR))
data = (data * 1000) / 465;
data &= RNP_PTP_SSIR_SSINC_MASK;
reg_value = data;
if (gmac4)
reg_value <<= RNP_PTP_SSIR_SSINC_SHIFT;
writel(reg_value, ioaddr + PTP_SSIR);
if (ssinc)
*ssinc = data;
}
static int config_addend(void __iomem *ioaddr, u32 addend)
{
u32 value;
int limit;
writel(addend, ioaddr + PTP_TAR);
/* issue command to update the addend value */
value = readl(ioaddr + PTP_TCR);
value |= RNP_PTP_TCR_TSADDREG;
writel(value, ioaddr + PTP_TCR);
/* wait for present addend update to complete */
limit = 10;
while (limit--) {
if (!(readl(ioaddr + PTP_TCR) & RNP_PTP_TCR_TSADDREG))
break;
mdelay(10);
}
if (limit < 0)
return -EBUSY;
return 0;
}
static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
{
int limit;
u32 value;
writel(sec, ioaddr + PTP_STSUR);
writel(nsec, ioaddr + PTP_STNSUR);
/* issue command to initialize the system time value */
value = readl(ioaddr + PTP_TCR);
value |= RNP_PTP_TCR_TSINIT;
writel(value, ioaddr + PTP_TCR);
/* wait for present system time initialize to complete */
limit = 10;
while (limit--) {
if (!(readl(ioaddr + PTP_TCR) & RNP_PTP_TCR_TSINIT))
break;
mdelay(10);
}
if (limit < 0)
return -EBUSY;
return 0;
}
static void get_systime(void __iomem *ioaddr, u64 *systime)
{
u64 ns;
/* Get the TSSS value */
ns = readl(ioaddr + PTP_STNSR);
/* Get the TSS and convert sec time value to nanosecond */
ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
if (systime)
*systime = ns;
}
static void config_mac_interrupt_enable(void __iomem *ioaddr, bool on)
{
rnpgbe_wr_reg(ioaddr + RNP_MAC_INTERRUPT_ENABLE, on);
}
static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec, int add_sub,
int gmac4)
{
u32 value;
int limit;
if (add_sub) {
/* If the new sec value needs to be subtracted with
* the system time, then MAC_STSUR reg should be
* programmed with (2^32 <new_sec_value>)
*/
if (gmac4)
sec = -sec;
value = readl(ioaddr + PTP_TCR);
if (value & RNP_PTP_TCR_TSCTRLSSR)
nsec = (RNP_PTP_DIGITAL_ROLLOVER_MODE - nsec);
else
nsec = (RNP_PTP_BINARY_ROLLOVER_MODE - nsec);
}
writel(sec, ioaddr + PTP_STSUR);
value = (add_sub << RNP_PTP_STNSUR_ADDSUB_SHIFT) | nsec;
writel(value, ioaddr + PTP_STNSUR);
/* issue command to initialize the system time value */
value = readl(ioaddr + PTP_TCR);
value |= RNP_PTP_TCR_TSUPDT;
writel(value, ioaddr + PTP_TCR);
/* wait for present system time adjust/update to complete */
limit = 10;
while (limit--) {
if (!(readl(ioaddr + PTP_TCR) & RNP_PTP_TCR_TSUPDT))
break;
mdelay(10);
}
if (limit < 0)
return -EBUSY;
return 0;
}
const struct rnpgbe_hwtimestamp mac_ptp = {
.config_hw_tstamping = config_hw_tstamping,
.config_mac_irq_enable = config_mac_interrupt_enable,
.init_systime = init_systime,
.config_sub_second_increment = config_sub_second_increment,
.config_addend = config_addend,
.adjust_systime = adjust_systime,
.get_systime = get_systime,
};
static int rnpgbe_ptp_adjfreq(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct rnpgbe_adapter *pf =
container_of(ptp, struct rnpgbe_adapter, ptp_clock_ops);
unsigned long flags;
u32 addend;
if (!pf) {
printk(KERN_DEBUG "adapter_of contail is null\n");
return 0;
}
addend = adjust_by_scaled_ppm(pf->default_addend, scaled_ppm);
spin_lock_irqsave(&pf->ptp_lock, flags);
pf->hwts_ops->config_addend(pf->ptp_addr, addend);
spin_unlock_irqrestore(&pf->ptp_lock, flags);
return 0;
}
static int rnpgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct rnpgbe_adapter *pf =
container_of(ptp, struct rnpgbe_adapter, ptp_clock_ops);
unsigned long flags;
u32 sec, nsec;
u32 quotient, reminder;
int neg_adj = 0;
if (delta < 0) {
neg_adj = 1;
delta = -delta;
}
if (delta == 0)
return 0;
quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
sec = quotient;
nsec = reminder;
spin_lock_irqsave(&pf->ptp_lock, flags);
pf->hwts_ops->adjust_systime(pf->ptp_addr, sec, nsec, neg_adj,
pf->gmac4);
spin_unlock_irqrestore(&pf->ptp_lock, flags);
return 0;
}
static int rnpgbe_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
struct rnpgbe_adapter *pf =
container_of(ptp, struct rnpgbe_adapter, ptp_clock_ops);
unsigned long flags;
u64 ns = 0;
spin_lock_irqsave(&pf->ptp_lock, flags);
pf->hwts_ops->get_systime(pf->ptp_addr, &ns);
spin_unlock_irqrestore(&pf->ptp_lock, flags);
*ts = ns_to_timespec64(ns);
return 0;
}
static int rnpgbe_ptp_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
struct rnpgbe_adapter *pf =
container_of(ptp, struct rnpgbe_adapter, ptp_clock_ops);
unsigned long flags;
spin_lock_irqsave(&pf->ptp_lock, flags);
pf->hwts_ops->init_systime(pf->ptp_addr, ts->tv_sec, ts->tv_nsec);
spin_unlock_irqrestore(&pf->ptp_lock, flags);
return 0;
}
static int rnpgbe_ptp_feature_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
return -EOPNOTSUPP;
}
int rnpgbe_ptp_get_ts_config(struct rnpgbe_adapter *pf, struct ifreq *ifr)
{
struct hwtstamp_config *config = &pf->tstamp_config;
return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? -EFAULT :
0;
}
static int rnpgbe_ptp_setup_ptp(struct rnpgbe_adapter *pf, u32 value)
{
u32 sec_inc = 0;
u64 temp = 0;
struct timespec64 now;
/*For now just use extrnal clock(the kernel-system clock)*/
/* 1.Mask the Timestamp Trigger interrupt */
/* 2.enable time stamping */
/* 2.1 clear all bytes about time ctrl reg*/
pf->hwts_ops->config_hw_tstamping(pf->ptp_addr, value);
/* 3.Program the PTPclock frequency */
/* program Sub Second Increment reg
* we use kernel-system clock
*/
pf->hwts_ops->config_sub_second_increment(pf->ptp_addr,
pf->clk_ptp_rate, pf->gmac4, &sec_inc);
/* 4.If use fine correction approash then,
* Program MAC_Timestamp_Addend register
*/
if (sec_inc == 0) {
printk(KERN_DEBUG "%s:%d the sec_inc is zero this is a bug\n",
__func__, __LINE__);
return -EFAULT;
}
temp = div_u64(1000000000ULL, sec_inc);
/* Store sub second increment and flags for later use */
pf->sub_second_inc = sec_inc;
pf->systime_flags = value;
/* calculate default added value:
* formula is :
* addend = (2^32)/freq_div_ratio;
* where, freq_div_ratio = 1e9ns/sec_inc
*/
temp = (u64)(temp << 32);
if (pf->clk_ptp_rate == 0) {
pf->clk_ptp_rate = 1000;
printk(KERN_DEBUG "%s:%d clk_ptp_rate is zero\n", __func__,
__LINE__);
}
pf->default_addend = div_u64(temp, pf->clk_ptp_rate);
pf->hwts_ops->config_addend(pf->ptp_addr, pf->default_addend);
/* 5.Poll wait for the TCR Update Addend Register*/
/* 6.enabled Fine Update method */
/* 7.program the second and nanosecond register*/
/*TODO If we need to enable one-step timestamp */
/* initialize system time */
ktime_get_real_ts64(&now);
/* lower 32 bits of tv_sec are safe until y2106 */
pf->hwts_ops->init_systime(pf->ptp_addr, (u32)now.tv_sec, now.tv_nsec);
return 0;
}
int rnpgbe_ptp_set_ts_config(struct rnpgbe_adapter *pf, struct ifreq *ifr)
{
struct hwtstamp_config config;
u32 ptp_v2 = 0;
u32 tstamp_all = 0;
u32 ptp_over_ipv4_udp = 0;
u32 ptp_over_ipv6_udp = 0;
u32 ptp_over_ethernet = 0;
u32 snap_type_sel = 0;
u32 ts_master_en = 0;
u32 value = 0;
s32 ret = -1;
if (!(pf->flags2 & RNP_FLAG2_PTP_ENABLED)) {
pci_alert(pf->pdev, "No support for HW time stamping\n");
pf->ptp_tx_en = 0;
pf->ptp_tx_en = 0;
return -EOPNOTSUPP;
}
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT;
netdev_info(pf->netdev,
"%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
__func__, config.flags, config.tx_type, config.rx_filter);
/* reserved for future extensions */
if (config.flags)
return -EINVAL;
if (config.tx_type != HWTSTAMP_TX_OFF &&
config.tx_type != HWTSTAMP_TX_ON)
return -ERANGE;
switch (config.rx_filter) {
case HWTSTAMP_FILTER_NONE:
/* time stamp no incoming packet at all */
config.rx_filter = HWTSTAMP_FILTER_NONE;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
/* PTP v1, UDP, any kind of event packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
/* 'mac' hardware can support Sync, Pdelay_Req and
* Pdelay_resp by setting bit14 and bits17/16 to 01
* This leaves Delay_Req timestamps out.
* Enable all events *and* general purpose message
* timestamping
*/
snap_type_sel = RNP_PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
/* PTP v1, UDP, Sync packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC;
/* take time stamp for SYNC messages only */
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
/* PTP v1, UDP, Delay_req packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ;
/* take time stamp for Delay_Req messages only */
ts_master_en = RNP_PTP_TCR_TSMSTRENA;
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
/* PTP v2, UDP, any kind of event packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
ptp_v2 = RNP_PTP_TCR_TSVER2ENA;
/* take time stamp for all event messages */
snap_type_sel = RNP_PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
/* PTP v2, UDP, Sync packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC;
ptp_v2 = RNP_PTP_TCR_TSVER2ENA;
/* take time stamp for SYNC messages only */
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
/* PTP v2, UDP, Delay_req packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ;
ptp_v2 = RNP_PTP_TCR_TSVER2ENA;
/* take time stamp for Delay_Req messages only */
ts_master_en = RNP_PTP_TCR_TSMSTRENA;
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
/* PTP v2/802.AS1 any layer, any kind of event packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
ptp_v2 = RNP_PTP_TCR_TSVER2ENA;
snap_type_sel = RNP_PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
ptp_over_ethernet = RNP_PTP_TCR_TSIPENA;
break;
case HWTSTAMP_FILTER_PTP_V2_SYNC:
/* PTP v2/802.AS1, any layer, Sync packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
ptp_v2 = RNP_PTP_TCR_TSVER2ENA;
/* take time stamp for SYNC messages only */
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
ptp_over_ethernet = RNP_PTP_TCR_TSIPENA;
break;
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
/* PTP v2/802.AS1, any layer, Delay_req packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
ptp_v2 = RNP_PTP_TCR_TSVER2ENA;
/* take time stamp for Delay_Req messages only */
ts_master_en = RNP_PTP_TCR_TSMSTRENA;
ptp_over_ipv4_udp = RNP_PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = RNP_PTP_TCR_TSIPV6ENA;
ptp_over_ethernet = RNP_PTP_TCR_TSIPENA;
break;
#ifdef HWTSTAMP_FILTER_NTP_ALL
case HWTSTAMP_FILTER_NTP_ALL:
#endif
case HWTSTAMP_FILTER_ALL:
/* time stamp any incoming packet */
config.rx_filter = HWTSTAMP_FILTER_ALL;
tstamp_all = RNP_PTP_TCR_TSENALL;
break;
default:
return -ERANGE;
}
pf->ptp_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1);
pf->ptp_tx_en = config.tx_type == HWTSTAMP_TX_ON;
netdev_info(pf->netdev,
"ptp config rx filter 0x%.2x tx_type 0x%.2x rx_en[%d] tx_en[%d]\n",
config.rx_filter, config.tx_type, pf->ptp_rx_en, pf->ptp_tx_en);
if (!pf->ptp_rx_en && !pf->ptp_tx_en) {
/*rx and tx is not use hardware ts so clear the ptp register */
pf->hwts_ops->config_hw_tstamping(pf->ptp_addr, 0);
} else {
value = (RNP_PTP_TCR_TSENA | RNP_PTP_TCR_TSCFUPDT |
RNP_PTP_TCR_TSCTRLSSR | tstamp_all | ptp_v2 |
ptp_over_ethernet | ptp_over_ipv6_udp |
ptp_over_ipv4_udp | ts_master_en | snap_type_sel);
ret = rnpgbe_ptp_setup_ptp(pf, value);
if (ret < 0)
return ret;
}
pf->ptp_config_value = value;
memcpy(&pf->tstamp_config, &config, sizeof(config));
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT :
0;
}
/* structure describing a PTP hardware clock */
static struct ptp_clock_info rnpgbe_ptp_clock_ops = {
.owner = THIS_MODULE,
.name = "rnp ptp",
.max_adj = 50000000,
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 0, /* will be overwritten in stmmac_ptp_register */
.n_pins = 0, /*should be 0 if not set*/
.adjfine = rnpgbe_ptp_adjfreq,
.adjtime = rnpgbe_ptp_adjtime,
.gettime64 = rnpgbe_ptp_gettime,
.settime64 = rnpgbe_ptp_settime,
.enable = rnpgbe_ptp_feature_enable,
};
int rnpgbe_ptp_register(struct rnpgbe_adapter *pf)
{
pf->hwts_ops = &mac_ptp;
pf->ptp_tx_en = 0;
pf->ptp_rx_en = 0;
spin_lock_init(&pf->ptp_lock);
pf->flags2 |= RNP_FLAG2_PTP_ENABLED;
pf->ptp_clock_ops = rnpgbe_ptp_clock_ops;
/* default mac clock rate is 50Mhz */
pf->clk_ptp_rate = 50000000;
if (!pf->pdev)
printk(KERN_DEBUG "pdev dev is null\n");
pf->ptp_clock = ptp_clock_register(&pf->ptp_clock_ops, &pf->pdev->dev);
if (!pf->ptp_clock)
pci_err(pf->pdev, "ptp clock register failed\n");
if (IS_ERR(pf->ptp_clock)) {
pci_err(pf->pdev, "ptp_clock_register failed\n");
pf->ptp_clock = NULL;
} else {
pci_info(pf->pdev, "registered PTP clock\n");
}
return 0;
}
void rnpgbe_ptp_unregister(struct rnpgbe_adapter *pf)
{
/*1. stop the ptp module*/
if (pf->ptp_clock) {
ptp_clock_unregister(pf->ptp_clock);
pf->ptp_clock = NULL;
pr_debug("Removed PTP HW clock successfully on %s\n",
"rnpgbe_ptp");
}
}
void rnpgbe_tx_hwtstamp_work(struct work_struct *work)
{
struct rnpgbe_adapter *adapter =
container_of(work, struct rnpgbe_adapter, tx_hwtstamp_work);
#ifdef FW_UART_SHOW_TSTAMPS
struct rnpgbe_hw *hw = &adapter->hw;
#endif
void __iomem *ioaddr = adapter->hw.hw_addr;
/* 1. read port belone timestatmp status reg */
/* 2. status enabled read nsec and sec reg*/
/* 3. */
u64 nanosec = 0, sec = 0;
if (!adapter->ptp_tx_skb) {
clear_bit_unlock(__RNP_PTP_TX_IN_PROGRESS, &adapter->state);
return;
}
if (rnpgbe_rd_reg(ioaddr + RNP_ETH_PTP_TX_TSVALUE_STATUS(0)) & 0x01) {
struct sk_buff *skb = adapter->ptp_tx_skb;
struct skb_shared_hwtstamps shhwtstamps;
u64 txstmp = 0;
/* read and add nsec, sec turn to nsec*/
nanosec = rnpgbe_rd_reg(ioaddr + RNP_ETH_PTP_TX_LTIMES(0));
sec = rnpgbe_rd_reg(ioaddr + RNP_ETH_PTP_TX_HTIMES(0));
/* when we read the timestamp finish need to notice the hardware
* that the timestamp need to update via set tx_hwts_clear-reg
* from high to low
*/
rnpgbe_wr_reg(ioaddr + RNP_ETH_PTP_TX_CLEAR(0),
PTP_GET_TX_HWTS_FINISH);
rnpgbe_wr_reg(ioaddr + RNP_ETH_PTP_TX_CLEAR(0),
PTP_GET_TX_HWTS_UPDATE);
txstmp = nanosec & PTP_HWTX_TIME_VALUE_MASK;
txstmp += (sec & PTP_HWTX_TIME_VALUE_MASK) * 1000000000ULL;
/* Clear the global tx_hwtstamp_skb pointer and force writes
* prior to notifying the stack of a Tx timestamp.
*/
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = ns_to_ktime(txstmp);
adapter->ptp_tx_skb = NULL;
/* force write prior to skb_tstamp_tx
* because the xmit will re used the point to store ptp skb
*/
wmb();
skb_tstamp_tx(skb, &shhwtstamps);
dev_consume_skb_any(skb);
clear_bit_unlock(__RNP_PTP_TX_IN_PROGRESS, &adapter->state);
/* send tstamps to hw */
#ifdef FW_UART_SHOW_TSTAMPS
rnpgbe_mbx_tstamps_show(hw, sec, nanosec);
#endif
} else if (time_after(jiffies,
adapter->tx_hwtstamp_start +
adapter->tx_timeout_factor * HZ)) {
/* this function will mark the skb drop*/
if (adapter->ptp_tx_skb)
dev_kfree_skb_any(adapter->ptp_tx_skb);
adapter->ptp_tx_skb = NULL;
adapter->tx_hwtstamp_timeouts++;
clear_bit_unlock(__RNP_PTP_TX_IN_PROGRESS, &adapter->state);
netdev_warn(adapter->netdev, "clearing Tx timestamp hang\n");
} else {
/* reschedule to check later */
schedule_work(&adapter->tx_hwtstamp_work);
}
}
void rnpgbe_ptp_get_rx_hwstamp(struct rnpgbe_adapter *adapter,
union rnpgbe_rx_desc *desc, struct sk_buff *skb)
{
u64 ns = 0;
u64 tsvalueh = 0, tsvaluel = 0;
struct skb_shared_hwtstamps *hwtstamps = NULL;
if (!skb || !adapter->ptp_rx_en) {
netdev_dbg(adapter->netdev,
"hwstamp skb is null or rx_en iszero %u\n",
adapter->ptp_rx_en);
return;
}
if (likely(!(desc->wb.cmd & RNP_RXD_STAT_PTP)))
return;
hwtstamps = skb_hwtstamps(skb);
/* because of rx hwstamp store before the mac head
* skb->head and skb->data is point to same location when call alloc_skb
* so we must move 16 bytes the skb->data to the mac head location
* but for the head point if we need move the skb->head need to be diss
*/
/* low8bytes is null high8bytes is timestamp
* high32bit is seconds low32bits is nanoseconds
*/
skb_copy_from_linear_data_offset(skb, RNP_RX_TIME_RESERVE, &tsvalueh,
RNP_RX_SEC_SIZE);
skb_copy_from_linear_data_offset(skb,
RNP_RX_TIME_RESERVE + RNP_RX_SEC_SIZE,
&tsvaluel, RNP_RX_NANOSEC_SIZE);
skb_pull(skb, RNP_RX_HWTS_OFFSET);
tsvalueh = ntohl(tsvalueh);
tsvaluel = ntohl(tsvaluel);
ns = tsvaluel & RNP_RX_NSEC_MASK;
ns += ((tsvalueh & RNP_RX_SEC_MASK) * 1000000000ULL);
netdev_dbg(adapter->netdev,
"ptp get hardware ts-sec %llu ts-nanosec %llu\n", tsvalueh,
tsvaluel);
hwtstamps->hwtstamp = ns_to_ktime(ns);
}
void rnpgbe_ptp_reset(struct rnpgbe_adapter *adapter)
{
rnpgbe_ptp_setup_ptp(adapter, adapter->ptp_config_value);
}