cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stmmac_hwtstamp.c (5498B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*******************************************************************************
      3  Copyright (C) 2013  Vayavya Labs Pvt Ltd
      4
      5  This implements all the API for managing HW timestamp & PTP.
      6
      7
      8  Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
      9  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
     10*******************************************************************************/
     11
     12#include <linux/io.h>
     13#include <linux/iopoll.h>
     14#include <linux/delay.h>
     15#include <linux/ptp_clock_kernel.h>
     16#include "common.h"
     17#include "stmmac_ptp.h"
     18#include "dwmac4.h"
     19#include "stmmac.h"
     20
     21static void config_hw_tstamping(void __iomem *ioaddr, u32 data)
     22{
     23	writel(data, ioaddr + PTP_TCR);
     24}
     25
     26static void config_sub_second_increment(void __iomem *ioaddr,
     27		u32 ptp_clock, int gmac4, u32 *ssinc)
     28{
     29	u32 value = readl(ioaddr + PTP_TCR);
     30	unsigned long data;
     31	u32 reg_value;
     32
     33	/* For GMAC3.x, 4.x versions, in "fine adjustement mode" set sub-second
     34	 * increment to twice the number of nanoseconds of a clock cycle.
     35	 * The calculation of the default_addend value by the caller will set it
     36	 * to mid-range = 2^31 when the remainder of this division is zero,
     37	 * which will make the accumulator overflow once every 2 ptp_clock
     38	 * cycles, adding twice the number of nanoseconds of a clock cycle :
     39	 * 2000000000ULL / ptp_clock.
     40	 */
     41	if (value & PTP_TCR_TSCFUPDT)
     42		data = (2000000000ULL / ptp_clock);
     43	else
     44		data = (1000000000ULL / ptp_clock);
     45
     46	/* 0.465ns accuracy */
     47	if (!(value & PTP_TCR_TSCTRLSSR))
     48		data = (data * 1000) / 465;
     49
     50	data &= PTP_SSIR_SSINC_MASK;
     51
     52	reg_value = data;
     53	if (gmac4)
     54		reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT;
     55
     56	writel(reg_value, ioaddr + PTP_SSIR);
     57
     58	if (ssinc)
     59		*ssinc = data;
     60}
     61
     62static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
     63{
     64	u32 value;
     65
     66	writel(sec, ioaddr + PTP_STSUR);
     67	writel(nsec, ioaddr + PTP_STNSUR);
     68	/* issue command to initialize the system time value */
     69	value = readl(ioaddr + PTP_TCR);
     70	value |= PTP_TCR_TSINIT;
     71	writel(value, ioaddr + PTP_TCR);
     72
     73	/* wait for present system time initialize to complete */
     74	return readl_poll_timeout_atomic(ioaddr + PTP_TCR, value,
     75				 !(value & PTP_TCR_TSINIT),
     76				 10, 100000);
     77}
     78
     79static int config_addend(void __iomem *ioaddr, u32 addend)
     80{
     81	u32 value;
     82	int limit;
     83
     84	writel(addend, ioaddr + PTP_TAR);
     85	/* issue command to update the addend value */
     86	value = readl(ioaddr + PTP_TCR);
     87	value |= PTP_TCR_TSADDREG;
     88	writel(value, ioaddr + PTP_TCR);
     89
     90	/* wait for present addend update to complete */
     91	limit = 10;
     92	while (limit--) {
     93		if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
     94			break;
     95		mdelay(10);
     96	}
     97	if (limit < 0)
     98		return -EBUSY;
     99
    100	return 0;
    101}
    102
    103static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
    104		int add_sub, int gmac4)
    105{
    106	u32 value;
    107	int limit;
    108
    109	if (add_sub) {
    110		/* If the new sec value needs to be subtracted with
    111		 * the system time, then MAC_STSUR reg should be
    112		 * programmed with (2^32 – <new_sec_value>)
    113		 */
    114		if (gmac4)
    115			sec = -sec;
    116
    117		value = readl(ioaddr + PTP_TCR);
    118		if (value & PTP_TCR_TSCTRLSSR)
    119			nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec);
    120		else
    121			nsec = (PTP_BINARY_ROLLOVER_MODE - nsec);
    122	}
    123
    124	writel(sec, ioaddr + PTP_STSUR);
    125	value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec;
    126	writel(value, ioaddr + PTP_STNSUR);
    127
    128	/* issue command to initialize the system time value */
    129	value = readl(ioaddr + PTP_TCR);
    130	value |= PTP_TCR_TSUPDT;
    131	writel(value, ioaddr + PTP_TCR);
    132
    133	/* wait for present system time adjust/update to complete */
    134	limit = 10;
    135	while (limit--) {
    136		if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
    137			break;
    138		mdelay(10);
    139	}
    140	if (limit < 0)
    141		return -EBUSY;
    142
    143	return 0;
    144}
    145
    146static void get_systime(void __iomem *ioaddr, u64 *systime)
    147{
    148	u64 ns, sec0, sec1;
    149
    150	/* Get the TSS value */
    151	sec1 = readl_relaxed(ioaddr + PTP_STSR);
    152	do {
    153		sec0 = sec1;
    154		/* Get the TSSS value */
    155		ns = readl_relaxed(ioaddr + PTP_STNSR);
    156		/* Get the TSS value */
    157		sec1 = readl_relaxed(ioaddr + PTP_STSR);
    158	} while (sec0 != sec1);
    159
    160	if (systime)
    161		*systime = ns + (sec1 * 1000000000ULL);
    162}
    163
    164static void get_ptptime(void __iomem *ptpaddr, u64 *ptp_time)
    165{
    166	u64 ns;
    167
    168	ns = readl(ptpaddr + PTP_ATNR);
    169	ns += readl(ptpaddr + PTP_ATSR) * NSEC_PER_SEC;
    170
    171	*ptp_time = ns;
    172}
    173
    174static void timestamp_interrupt(struct stmmac_priv *priv)
    175{
    176	u32 num_snapshot, ts_status, tsync_int;
    177	struct ptp_clock_event event;
    178	unsigned long flags;
    179	u64 ptp_time;
    180	int i;
    181
    182	tsync_int = readl(priv->ioaddr + GMAC_INT_STATUS) & GMAC_INT_TSIE;
    183
    184	if (!tsync_int)
    185		return;
    186
    187	/* Read timestamp status to clear interrupt from either external
    188	 * timestamp or start/end of PPS.
    189	 */
    190	ts_status = readl(priv->ioaddr + GMAC_TIMESTAMP_STATUS);
    191
    192	if (!priv->plat->ext_snapshot_en)
    193		return;
    194
    195	num_snapshot = (ts_status & GMAC_TIMESTAMP_ATSNS_MASK) >>
    196		       GMAC_TIMESTAMP_ATSNS_SHIFT;
    197
    198	for (i = 0; i < num_snapshot; i++) {
    199		read_lock_irqsave(&priv->ptp_lock, flags);
    200		get_ptptime(priv->ptpaddr, &ptp_time);
    201		read_unlock_irqrestore(&priv->ptp_lock, flags);
    202		event.type = PTP_CLOCK_EXTTS;
    203		event.index = 0;
    204		event.timestamp = ptp_time;
    205		ptp_clock_event(priv->ptp_clock, &event);
    206	}
    207}
    208
    209const struct stmmac_hwtimestamp stmmac_ptp = {
    210	.config_hw_tstamping = config_hw_tstamping,
    211	.init_systime = init_systime,
    212	.config_sub_second_increment = config_sub_second_increment,
    213	.config_addend = config_addend,
    214	.adjust_systime = adjust_systime,
    215	.get_systime = get_systime,
    216	.get_ptptime = get_ptptime,
    217	.timestamp_interrupt = timestamp_interrupt,
    218};