mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
net: stmmac: Add hardware supported cross-timestamp
Cross timestamping is supported on Integrated Ethernet Controller in Intel SoC such as EHL and TGL with Always Running Timer. The hardware cross-timestamp result is made available to applications through the PTP_SYS_OFFSET_PRECISE ioctl which calls stmmac_getcrosststamp(). Device time is stored in the MAC Auxiliary register. The 64-bit System time (ART timestamp) is stored in registers that are only addressable by using MDIO space. Signed-off-by: Tan Tee Min <tee.min.tan@intel.com> Co-developed-by: Wong Vee Khee <vee.khee.wong@linux.intel.com> Signed-off-by: Wong Vee Khee <vee.khee.wong@linux.intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bef32aa8e4
commit
341f67e424
9 changed files with 193 additions and 0 deletions
|
@ -388,6 +388,8 @@ struct dma_features {
|
|||
unsigned int estsel;
|
||||
unsigned int fpesel;
|
||||
unsigned int tbssel;
|
||||
/* Numbers of Auxiliary Snapshot Inputs */
|
||||
unsigned int aux_snapshot_n;
|
||||
};
|
||||
|
||||
/* RX Buffer size must be multiple of 4/8/16 bytes */
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "dwmac-intel.h"
|
||||
#include "dwmac4.h"
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
|
||||
#define INTEL_MGBE_ADHOC_ADDR 0x15
|
||||
#define INTEL_MGBE_XPCS_ADDR 0x16
|
||||
|
@ -240,6 +241,108 @@ static void intel_mgbe_ptp_clk_freq_config(void *npriv)
|
|||
writel(gpio_value, priv->ioaddr + GMAC_GPIO_STATUS);
|
||||
}
|
||||
|
||||
static void get_arttime(struct mii_bus *mii, int intel_adhoc_addr,
|
||||
u64 *art_time)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
ns = mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE3);
|
||||
ns <<= GMAC4_ART_TIME_SHIFT;
|
||||
ns |= mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE2);
|
||||
ns <<= GMAC4_ART_TIME_SHIFT;
|
||||
ns |= mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE1);
|
||||
ns <<= GMAC4_ART_TIME_SHIFT;
|
||||
ns |= mdiobus_read(mii, intel_adhoc_addr, PMC_ART_VALUE0);
|
||||
|
||||
*art_time = ns;
|
||||
}
|
||||
|
||||
static int intel_crosststamp(ktime_t *device,
|
||||
struct system_counterval_t *system,
|
||||
void *ctx)
|
||||
{
|
||||
struct intel_priv_data *intel_priv;
|
||||
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)ctx;
|
||||
void __iomem *ptpaddr = priv->ptpaddr;
|
||||
void __iomem *ioaddr = priv->hw->pcsr;
|
||||
unsigned long flags;
|
||||
u64 art_time = 0;
|
||||
u64 ptp_time = 0;
|
||||
u32 num_snapshot;
|
||||
u32 gpio_value;
|
||||
u32 acr_value;
|
||||
int ret;
|
||||
u32 v;
|
||||
int i;
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_ART))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
intel_priv = priv->plat->bsp_priv;
|
||||
|
||||
/* Enable Internal snapshot trigger */
|
||||
acr_value = readl(ptpaddr + PTP_ACR);
|
||||
acr_value &= ~PTP_ACR_MASK;
|
||||
switch (priv->plat->int_snapshot_num) {
|
||||
case AUX_SNAPSHOT0:
|
||||
acr_value |= PTP_ACR_ATSEN0;
|
||||
break;
|
||||
case AUX_SNAPSHOT1:
|
||||
acr_value |= PTP_ACR_ATSEN1;
|
||||
break;
|
||||
case AUX_SNAPSHOT2:
|
||||
acr_value |= PTP_ACR_ATSEN2;
|
||||
break;
|
||||
case AUX_SNAPSHOT3:
|
||||
acr_value |= PTP_ACR_ATSEN3;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
writel(acr_value, ptpaddr + PTP_ACR);
|
||||
|
||||
/* Clear FIFO */
|
||||
acr_value = readl(ptpaddr + PTP_ACR);
|
||||
acr_value |= PTP_ACR_ATSFC;
|
||||
writel(acr_value, ptpaddr + PTP_ACR);
|
||||
|
||||
/* Trigger Internal snapshot signal
|
||||
* Create a rising edge by just toggle the GPO1 to low
|
||||
* and back to high.
|
||||
*/
|
||||
gpio_value = readl(ioaddr + GMAC_GPIO_STATUS);
|
||||
gpio_value &= ~GMAC_GPO1;
|
||||
writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);
|
||||
gpio_value |= GMAC_GPO1;
|
||||
writel(gpio_value, ioaddr + GMAC_GPIO_STATUS);
|
||||
|
||||
/* Poll for time sync operation done */
|
||||
ret = readl_poll_timeout(priv->ioaddr + GMAC_INT_STATUS, v,
|
||||
(v & GMAC_INT_TSIE), 100, 10000);
|
||||
|
||||
if (ret == -ETIMEDOUT) {
|
||||
pr_err("%s: Wait for time sync operation timeout\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
num_snapshot = (readl(ioaddr + GMAC_TIMESTAMP_STATUS) &
|
||||
GMAC_TIMESTAMP_ATSNS_MASK) >>
|
||||
GMAC_TIMESTAMP_ATSNS_SHIFT;
|
||||
|
||||
/* Repeat until the timestamps are from the FIFO last segment */
|
||||
for (i = 0; i < num_snapshot; i++) {
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
stmmac_get_ptptime(priv, ptpaddr, &ptp_time);
|
||||
*device = ns_to_ktime(ptp_time);
|
||||
spin_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
get_arttime(priv->mii, intel_priv->mdio_adhoc_addr, &art_time);
|
||||
*system = convert_art_to_tsc(art_time);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void common_default_data(struct plat_stmmacenet_data *plat)
|
||||
{
|
||||
plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
|
||||
|
@ -384,6 +487,11 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
|
|||
plat->mdio_bus_data->phy_mask = 1 << INTEL_MGBE_ADHOC_ADDR;
|
||||
plat->mdio_bus_data->phy_mask |= 1 << INTEL_MGBE_XPCS_ADDR;
|
||||
|
||||
plat->int_snapshot_num = AUX_SNAPSHOT1;
|
||||
|
||||
plat->has_crossts = true;
|
||||
plat->crosststamp = intel_crosststamp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30)
|
||||
#define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30)
|
||||
#define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30)
|
||||
#define GMAC_TIMESTAMP_STATUS 0x00000b20
|
||||
|
||||
/* RX Queues Routing */
|
||||
#define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0)
|
||||
|
@ -144,6 +145,7 @@
|
|||
#define GMAC_INT_PCS_PHYIS BIT(3)
|
||||
#define GMAC_INT_PMT_EN BIT(4)
|
||||
#define GMAC_INT_LPI_EN BIT(5)
|
||||
#define GMAC_INT_TSIE BIT(12)
|
||||
|
||||
#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
|
||||
GMAC_INT_PCS_ANE)
|
||||
|
@ -260,6 +262,7 @@ enum power_event {
|
|||
#define GMAC_HW_RXFIFOSIZE GENMASK(4, 0)
|
||||
|
||||
/* MAC HW features2 bitmap */
|
||||
#define GMAC_HW_FEAT_AUXSNAPNUM GENMASK(30, 28)
|
||||
#define GMAC_HW_FEAT_PPSOUTNUM GENMASK(26, 24)
|
||||
#define GMAC_HW_FEAT_TXCHCNT GENMASK(21, 18)
|
||||
#define GMAC_HW_FEAT_RXCHCNT GENMASK(15, 12)
|
||||
|
@ -305,6 +308,11 @@ enum power_event {
|
|||
#define GMAC_L4DP0_SHIFT 16
|
||||
#define GMAC_L4SP0 GENMASK(15, 0)
|
||||
|
||||
/* MAC Timestamp Status */
|
||||
#define GMAC_TIMESTAMP_AUXTSTRIG BIT(2)
|
||||
#define GMAC_TIMESTAMP_ATSNS_MASK GENMASK(29, 25)
|
||||
#define GMAC_TIMESTAMP_ATSNS_SHIFT 25
|
||||
|
||||
/* MTL registers */
|
||||
#define MTL_OPERATION_MODE 0x00000c00
|
||||
#define MTL_FRPE BIT(15)
|
||||
|
|
|
@ -412,6 +412,8 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
|
|||
|
||||
/* IEEE 1588-2002 */
|
||||
dma_cap->time_stamp = 0;
|
||||
/* Number of Auxiliary Snapshot Inputs */
|
||||
dma_cap->aux_snapshot_n = (hw_cap & GMAC_HW_FEAT_AUXSNAPNUM) >> 28;
|
||||
|
||||
/* MAC HW feature3 */
|
||||
hw_cap = readl(ioaddr + GMAC_HW_FEATURE3);
|
||||
|
|
|
@ -508,6 +508,7 @@ struct stmmac_hwtimestamp {
|
|||
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub, int gmac4);
|
||||
void (*get_systime) (void __iomem *ioaddr, u64 *systime);
|
||||
void (*get_ptptime)(void __iomem *ioaddr, u64 *ptp_time);
|
||||
};
|
||||
|
||||
#define stmmac_config_hw_tstamping(__priv, __args...) \
|
||||
|
@ -522,6 +523,8 @@ struct stmmac_hwtimestamp {
|
|||
stmmac_do_callback(__priv, ptp, adjust_systime, __args)
|
||||
#define stmmac_get_systime(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, get_systime, __args)
|
||||
#define stmmac_get_ptptime(__priv, __args...) \
|
||||
stmmac_do_void_callback(__priv, ptp, get_ptptime, __args)
|
||||
|
||||
/* Helpers to manage the descriptors for chain and ring modes */
|
||||
struct stmmac_mode_ops {
|
||||
|
|
|
@ -153,6 +153,16 @@ static void get_systime(void __iomem *ioaddr, u64 *systime)
|
|||
*systime = ns;
|
||||
}
|
||||
|
||||
static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
ns = readl(ptpaddr + PTP_ATNR);
|
||||
ns += readl(ptpaddr + PTP_ATSR) * NSEC_PER_SEC;
|
||||
|
||||
*ptp_time = ns;
|
||||
}
|
||||
|
||||
const struct stmmac_hwtimestamp stmmac_ptp = {
|
||||
.config_hw_tstamping = config_hw_tstamping,
|
||||
.init_systime = init_systime,
|
||||
|
@ -160,4 +170,5 @@ const struct stmmac_hwtimestamp stmmac_ptp = {
|
|||
.config_addend = config_addend,
|
||||
.adjust_systime = adjust_systime,
|
||||
.get_systime = get_systime,
|
||||
.get_ptptime = get_ptptime,
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*******************************************************************************/
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
#include "dwmac4.h"
|
||||
|
||||
/**
|
||||
* stmmac_adjust_freq
|
||||
|
@ -165,6 +166,36 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_get_syncdevicetime
|
||||
* @device: current device time
|
||||
* @system: system counter value read synchronously with device time
|
||||
* @ctx: context provided by timekeeping code
|
||||
* Description: Read device and system clock simultaneously and return the
|
||||
* corrected clock values in ns.
|
||||
**/
|
||||
static int stmmac_get_syncdevicetime(ktime_t *device,
|
||||
struct system_counterval_t *system,
|
||||
void *ctx)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)ctx;
|
||||
|
||||
if (priv->plat->crosststamp)
|
||||
return priv->plat->crosststamp(device, system, ctx);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int stmmac_getcrosststamp(struct ptp_clock_info *ptp,
|
||||
struct system_device_crosststamp *xtstamp)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
|
||||
return get_device_system_crosststamp(stmmac_get_syncdevicetime,
|
||||
priv, NULL, xtstamp);
|
||||
}
|
||||
|
||||
/* structure describing a PTP hardware clock */
|
||||
static struct ptp_clock_info stmmac_ptp_clock_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -180,6 +211,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
|
|||
.gettime64 = stmmac_get_time,
|
||||
.settime64 = stmmac_set_time,
|
||||
.enable = stmmac_enable,
|
||||
.getcrosststamp = stmmac_getcrosststamp,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#define PTP_STSUR 0x10 /* System Time – Seconds Update Reg */
|
||||
#define PTP_STNSUR 0x14 /* System Time – Nanoseconds Update Reg */
|
||||
#define PTP_TAR 0x18 /* Timestamp Addend Reg */
|
||||
#define PTP_ACR 0x40 /* Auxiliary Control Reg */
|
||||
#define PTP_ATNR 0x48 /* Auxiliary Timestamp - Nanoseconds Reg */
|
||||
#define PTP_ATSR 0x4c /* Auxiliary Timestamp - Seconds Reg */
|
||||
|
||||
#define PTP_STNSUR_ADDSUB_SHIFT 31
|
||||
#define PTP_DIGITAL_ROLLOVER_MODE 0x3B9ACA00 /* 10e9-1 ns */
|
||||
|
@ -64,4 +67,24 @@
|
|||
#define PTP_SSIR_SSINC_MASK 0xff
|
||||
#define GMAC4_PTP_SSIR_SSINC_SHIFT 16
|
||||
|
||||
/* Auxiliary Control defines */
|
||||
#define PTP_ACR_ATSFC BIT(0) /* Auxiliary Snapshot FIFO Clear */
|
||||
#define PTP_ACR_ATSEN0 BIT(4) /* Auxiliary Snapshot 0 Enable */
|
||||
#define PTP_ACR_ATSEN1 BIT(5) /* Auxiliary Snapshot 1 Enable */
|
||||
#define PTP_ACR_ATSEN2 BIT(6) /* Auxiliary Snapshot 2 Enable */
|
||||
#define PTP_ACR_ATSEN3 BIT(7) /* Auxiliary Snapshot 3 Enable */
|
||||
#define PTP_ACR_MASK GENMASK(7, 4) /* Aux Snapshot Mask */
|
||||
#define PMC_ART_VALUE0 0x01 /* PMC_ART[15:0] timer value */
|
||||
#define PMC_ART_VALUE1 0x02 /* PMC_ART[31:16] timer value */
|
||||
#define PMC_ART_VALUE2 0x03 /* PMC_ART[47:32] timer value */
|
||||
#define PMC_ART_VALUE3 0x04 /* PMC_ART[63:48] timer value */
|
||||
#define GMAC4_ART_TIME_SHIFT 16 /* ART TIME 16-bits shift */
|
||||
|
||||
enum aux_snapshot {
|
||||
AUX_SNAPSHOT0 = 0x10,
|
||||
AUX_SNAPSHOT1 = 0x20,
|
||||
AUX_SNAPSHOT2 = 0x40,
|
||||
AUX_SNAPSHOT3 = 0x80,
|
||||
};
|
||||
|
||||
#endif /* __STMMAC_PTP_H__ */
|
||||
|
|
|
@ -186,6 +186,8 @@ struct plat_stmmacenet_data {
|
|||
void (*exit)(struct platform_device *pdev, void *priv);
|
||||
struct mac_device_info *(*setup)(void *priv);
|
||||
int (*clks_config)(void *priv, bool enabled);
|
||||
int (*crosststamp)(ktime_t *device, struct system_counterval_t *system,
|
||||
void *ctx);
|
||||
void *bsp_priv;
|
||||
struct clk *stmmac_clk;
|
||||
struct clk *pclk;
|
||||
|
@ -206,5 +208,7 @@ struct plat_stmmacenet_data {
|
|||
u8 vlan_fail_q;
|
||||
unsigned int eee_usecs_rate;
|
||||
struct pci_dev *pdev;
|
||||
bool has_crossts;
|
||||
int int_snapshot_num;
|
||||
};
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue