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

dwmac5.c (20611B)


      1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
      2// Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
      3// stmmac Support for 5.xx Ethernet QoS cores
      4
      5#include <linux/bitops.h>
      6#include <linux/iopoll.h>
      7#include "common.h"
      8#include "dwmac4.h"
      9#include "dwmac5.h"
     10#include "stmmac.h"
     11#include "stmmac_ptp.h"
     12
     13struct dwmac5_error_desc {
     14	bool valid;
     15	const char *desc;
     16	const char *detailed_desc;
     17};
     18
     19#define STAT_OFF(field)		offsetof(struct stmmac_safety_stats, field)
     20
     21static void dwmac5_log_error(struct net_device *ndev, u32 value, bool corr,
     22		const char *module_name, const struct dwmac5_error_desc *desc,
     23		unsigned long field_offset, struct stmmac_safety_stats *stats)
     24{
     25	unsigned long loc, mask;
     26	u8 *bptr = (u8 *)stats;
     27	unsigned long *ptr;
     28
     29	ptr = (unsigned long *)(bptr + field_offset);
     30
     31	mask = value;
     32	for_each_set_bit(loc, &mask, 32) {
     33		netdev_err(ndev, "Found %s error in %s: '%s: %s'\n", corr ?
     34				"correctable" : "uncorrectable", module_name,
     35				desc[loc].desc, desc[loc].detailed_desc);
     36
     37		/* Update counters */
     38		ptr[loc]++;
     39	}
     40}
     41
     42static const struct dwmac5_error_desc dwmac5_mac_errors[32]= {
     43	{ true, "ATPES", "Application Transmit Interface Parity Check Error" },
     44	{ true, "TPES", "TSO Data Path Parity Check Error" },
     45	{ true, "RDPES", "Read Descriptor Parity Check Error" },
     46	{ true, "MPES", "MTL Data Path Parity Check Error" },
     47	{ true, "MTSPES", "MTL TX Status Data Path Parity Check Error" },
     48	{ true, "ARPES", "Application Receive Interface Data Path Parity Check Error" },
     49	{ true, "CWPES", "CSR Write Data Path Parity Check Error" },
     50	{ true, "ASRPES", "AXI Slave Read Data Path Parity Check Error" },
     51	{ true, "TTES", "TX FSM Timeout Error" },
     52	{ true, "RTES", "RX FSM Timeout Error" },
     53	{ true, "CTES", "CSR FSM Timeout Error" },
     54	{ true, "ATES", "APP FSM Timeout Error" },
     55	{ true, "PTES", "PTP FSM Timeout Error" },
     56	{ true, "T125ES", "TX125 FSM Timeout Error" },
     57	{ true, "R125ES", "RX125 FSM Timeout Error" },
     58	{ true, "RVCTES", "REV MDC FSM Timeout Error" },
     59	{ true, "MSTTES", "Master Read/Write Timeout Error" },
     60	{ true, "SLVTES", "Slave Read/Write Timeout Error" },
     61	{ true, "ATITES", "Application Timeout on ATI Interface Error" },
     62	{ true, "ARITES", "Application Timeout on ARI Interface Error" },
     63	{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
     64	{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
     65	{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
     66	{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
     67	{ true, "FSMPES", "FSM State Parity Error" },
     68	{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
     69	{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
     70	{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
     71	{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
     72	{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
     73	{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
     74	{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
     75};
     76
     77static void dwmac5_handle_mac_err(struct net_device *ndev,
     78		void __iomem *ioaddr, bool correctable,
     79		struct stmmac_safety_stats *stats)
     80{
     81	u32 value;
     82
     83	value = readl(ioaddr + MAC_DPP_FSM_INT_STATUS);
     84	writel(value, ioaddr + MAC_DPP_FSM_INT_STATUS);
     85
     86	dwmac5_log_error(ndev, value, correctable, "MAC", dwmac5_mac_errors,
     87			STAT_OFF(mac_errors), stats);
     88}
     89
     90static const struct dwmac5_error_desc dwmac5_mtl_errors[32]= {
     91	{ true, "TXCES", "MTL TX Memory Error" },
     92	{ true, "TXAMS", "MTL TX Memory Address Mismatch Error" },
     93	{ true, "TXUES", "MTL TX Memory Error" },
     94	{ false, "UNKNOWN", "Unknown Error" }, /* 3 */
     95	{ true, "RXCES", "MTL RX Memory Error" },
     96	{ true, "RXAMS", "MTL RX Memory Address Mismatch Error" },
     97	{ true, "RXUES", "MTL RX Memory Error" },
     98	{ false, "UNKNOWN", "Unknown Error" }, /* 7 */
     99	{ true, "ECES", "MTL EST Memory Error" },
    100	{ true, "EAMS", "MTL EST Memory Address Mismatch Error" },
    101	{ true, "EUES", "MTL EST Memory Error" },
    102	{ false, "UNKNOWN", "Unknown Error" }, /* 11 */
    103	{ true, "RPCES", "MTL RX Parser Memory Error" },
    104	{ true, "RPAMS", "MTL RX Parser Memory Address Mismatch Error" },
    105	{ true, "RPUES", "MTL RX Parser Memory Error" },
    106	{ false, "UNKNOWN", "Unknown Error" }, /* 15 */
    107	{ false, "UNKNOWN", "Unknown Error" }, /* 16 */
    108	{ false, "UNKNOWN", "Unknown Error" }, /* 17 */
    109	{ false, "UNKNOWN", "Unknown Error" }, /* 18 */
    110	{ false, "UNKNOWN", "Unknown Error" }, /* 19 */
    111	{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
    112	{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
    113	{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
    114	{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
    115	{ false, "UNKNOWN", "Unknown Error" }, /* 24 */
    116	{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
    117	{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
    118	{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
    119	{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
    120	{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
    121	{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
    122	{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
    123};
    124
    125static void dwmac5_handle_mtl_err(struct net_device *ndev,
    126		void __iomem *ioaddr, bool correctable,
    127		struct stmmac_safety_stats *stats)
    128{
    129	u32 value;
    130
    131	value = readl(ioaddr + MTL_ECC_INT_STATUS);
    132	writel(value, ioaddr + MTL_ECC_INT_STATUS);
    133
    134	dwmac5_log_error(ndev, value, correctable, "MTL", dwmac5_mtl_errors,
    135			STAT_OFF(mtl_errors), stats);
    136}
    137
    138static const struct dwmac5_error_desc dwmac5_dma_errors[32]= {
    139	{ true, "TCES", "DMA TSO Memory Error" },
    140	{ true, "TAMS", "DMA TSO Memory Address Mismatch Error" },
    141	{ true, "TUES", "DMA TSO Memory Error" },
    142	{ false, "UNKNOWN", "Unknown Error" }, /* 3 */
    143	{ false, "UNKNOWN", "Unknown Error" }, /* 4 */
    144	{ false, "UNKNOWN", "Unknown Error" }, /* 5 */
    145	{ false, "UNKNOWN", "Unknown Error" }, /* 6 */
    146	{ false, "UNKNOWN", "Unknown Error" }, /* 7 */
    147	{ false, "UNKNOWN", "Unknown Error" }, /* 8 */
    148	{ false, "UNKNOWN", "Unknown Error" }, /* 9 */
    149	{ false, "UNKNOWN", "Unknown Error" }, /* 10 */
    150	{ false, "UNKNOWN", "Unknown Error" }, /* 11 */
    151	{ false, "UNKNOWN", "Unknown Error" }, /* 12 */
    152	{ false, "UNKNOWN", "Unknown Error" }, /* 13 */
    153	{ false, "UNKNOWN", "Unknown Error" }, /* 14 */
    154	{ false, "UNKNOWN", "Unknown Error" }, /* 15 */
    155	{ false, "UNKNOWN", "Unknown Error" }, /* 16 */
    156	{ false, "UNKNOWN", "Unknown Error" }, /* 17 */
    157	{ false, "UNKNOWN", "Unknown Error" }, /* 18 */
    158	{ false, "UNKNOWN", "Unknown Error" }, /* 19 */
    159	{ false, "UNKNOWN", "Unknown Error" }, /* 20 */
    160	{ false, "UNKNOWN", "Unknown Error" }, /* 21 */
    161	{ false, "UNKNOWN", "Unknown Error" }, /* 22 */
    162	{ false, "UNKNOWN", "Unknown Error" }, /* 23 */
    163	{ false, "UNKNOWN", "Unknown Error" }, /* 24 */
    164	{ false, "UNKNOWN", "Unknown Error" }, /* 25 */
    165	{ false, "UNKNOWN", "Unknown Error" }, /* 26 */
    166	{ false, "UNKNOWN", "Unknown Error" }, /* 27 */
    167	{ false, "UNKNOWN", "Unknown Error" }, /* 28 */
    168	{ false, "UNKNOWN", "Unknown Error" }, /* 29 */
    169	{ false, "UNKNOWN", "Unknown Error" }, /* 30 */
    170	{ false, "UNKNOWN", "Unknown Error" }, /* 31 */
    171};
    172
    173static void dwmac5_handle_dma_err(struct net_device *ndev,
    174		void __iomem *ioaddr, bool correctable,
    175		struct stmmac_safety_stats *stats)
    176{
    177	u32 value;
    178
    179	value = readl(ioaddr + DMA_ECC_INT_STATUS);
    180	writel(value, ioaddr + DMA_ECC_INT_STATUS);
    181
    182	dwmac5_log_error(ndev, value, correctable, "DMA", dwmac5_dma_errors,
    183			STAT_OFF(dma_errors), stats);
    184}
    185
    186int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp,
    187			      struct stmmac_safety_feature_cfg *safety_feat_cfg)
    188{
    189	u32 value;
    190
    191	if (!asp)
    192		return -EINVAL;
    193
    194	/* 1. Enable Safety Features */
    195	value = readl(ioaddr + MTL_ECC_CONTROL);
    196	value |= MEEAO; /* MTL ECC Error Addr Status Override */
    197	if (safety_feat_cfg->tsoee)
    198		value |= TSOEE; /* TSO ECC */
    199	if (safety_feat_cfg->mrxpee)
    200		value |= MRXPEE; /* MTL RX Parser ECC */
    201	if (safety_feat_cfg->mestee)
    202		value |= MESTEE; /* MTL EST ECC */
    203	if (safety_feat_cfg->mrxee)
    204		value |= MRXEE; /* MTL RX FIFO ECC */
    205	if (safety_feat_cfg->mtxee)
    206		value |= MTXEE; /* MTL TX FIFO ECC */
    207	writel(value, ioaddr + MTL_ECC_CONTROL);
    208
    209	/* 2. Enable MTL Safety Interrupts */
    210	value = readl(ioaddr + MTL_ECC_INT_ENABLE);
    211	value |= RPCEIE; /* RX Parser Memory Correctable Error */
    212	value |= ECEIE; /* EST Memory Correctable Error */
    213	value |= RXCEIE; /* RX Memory Correctable Error */
    214	value |= TXCEIE; /* TX Memory Correctable Error */
    215	writel(value, ioaddr + MTL_ECC_INT_ENABLE);
    216
    217	/* 3. Enable DMA Safety Interrupts */
    218	value = readl(ioaddr + DMA_ECC_INT_ENABLE);
    219	value |= TCEIE; /* TSO Memory Correctable Error */
    220	writel(value, ioaddr + DMA_ECC_INT_ENABLE);
    221
    222	/* Only ECC Protection for External Memory feature is selected */
    223	if (asp <= 0x1)
    224		return 0;
    225
    226	/* 5. Enable Parity and Timeout for FSM */
    227	value = readl(ioaddr + MAC_FSM_CONTROL);
    228	if (safety_feat_cfg->prtyen)
    229		value |= PRTYEN; /* FSM Parity Feature */
    230	if (safety_feat_cfg->tmouten)
    231		value |= TMOUTEN; /* FSM Timeout Feature */
    232	writel(value, ioaddr + MAC_FSM_CONTROL);
    233
    234	/* 4. Enable Data Parity Protection */
    235	value = readl(ioaddr + MTL_DPP_CONTROL);
    236	if (safety_feat_cfg->edpp)
    237		value |= EDPP;
    238	writel(value, ioaddr + MTL_DPP_CONTROL);
    239
    240	/*
    241	 * All the Automotive Safety features are selected without the "Parity
    242	 * Port Enable for external interface" feature.
    243	 */
    244	if (asp <= 0x2)
    245		return 0;
    246
    247	if (safety_feat_cfg->epsi)
    248		value |= EPSI;
    249	writel(value, ioaddr + MTL_DPP_CONTROL);
    250	return 0;
    251}
    252
    253int dwmac5_safety_feat_irq_status(struct net_device *ndev,
    254		void __iomem *ioaddr, unsigned int asp,
    255		struct stmmac_safety_stats *stats)
    256{
    257	bool err, corr;
    258	u32 mtl, dma;
    259	int ret = 0;
    260
    261	if (!asp)
    262		return -EINVAL;
    263
    264	mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS);
    265	dma = readl(ioaddr + DMA_SAFETY_INT_STATUS);
    266
    267	err = (mtl & MCSIS) || (dma & MCSIS);
    268	corr = false;
    269	if (err) {
    270		dwmac5_handle_mac_err(ndev, ioaddr, corr, stats);
    271		ret |= !corr;
    272	}
    273
    274	err = (mtl & (MEUIS | MECIS)) || (dma & (MSUIS | MSCIS));
    275	corr = (mtl & MECIS) || (dma & MSCIS);
    276	if (err) {
    277		dwmac5_handle_mtl_err(ndev, ioaddr, corr, stats);
    278		ret |= !corr;
    279	}
    280
    281	err = dma & (DEUIS | DECIS);
    282	corr = dma & DECIS;
    283	if (err) {
    284		dwmac5_handle_dma_err(ndev, ioaddr, corr, stats);
    285		ret |= !corr;
    286	}
    287
    288	return ret;
    289}
    290
    291static const struct dwmac5_error {
    292	const struct dwmac5_error_desc *desc;
    293} dwmac5_all_errors[] = {
    294	{ dwmac5_mac_errors },
    295	{ dwmac5_mtl_errors },
    296	{ dwmac5_dma_errors },
    297};
    298
    299int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
    300			int index, unsigned long *count, const char **desc)
    301{
    302	int module = index / 32, offset = index % 32;
    303	unsigned long *ptr = (unsigned long *)stats;
    304
    305	if (module >= ARRAY_SIZE(dwmac5_all_errors))
    306		return -EINVAL;
    307	if (!dwmac5_all_errors[module].desc[offset].valid)
    308		return -EINVAL;
    309	if (count)
    310		*count = *(ptr + index);
    311	if (desc)
    312		*desc = dwmac5_all_errors[module].desc[offset].desc;
    313	return 0;
    314}
    315
    316static int dwmac5_rxp_disable(void __iomem *ioaddr)
    317{
    318	u32 val;
    319
    320	val = readl(ioaddr + MTL_OPERATION_MODE);
    321	val &= ~MTL_FRPE;
    322	writel(val, ioaddr + MTL_OPERATION_MODE);
    323
    324	return readl_poll_timeout(ioaddr + MTL_RXP_CONTROL_STATUS, val,
    325			val & RXPI, 1, 10000);
    326}
    327
    328static void dwmac5_rxp_enable(void __iomem *ioaddr)
    329{
    330	u32 val;
    331
    332	val = readl(ioaddr + MTL_OPERATION_MODE);
    333	val |= MTL_FRPE;
    334	writel(val, ioaddr + MTL_OPERATION_MODE);
    335}
    336
    337static int dwmac5_rxp_update_single_entry(void __iomem *ioaddr,
    338					  struct stmmac_tc_entry *entry,
    339					  int pos)
    340{
    341	int ret, i;
    342
    343	for (i = 0; i < (sizeof(entry->val) / sizeof(u32)); i++) {
    344		int real_pos = pos * (sizeof(entry->val) / sizeof(u32)) + i;
    345		u32 val;
    346
    347		/* Wait for ready */
    348		ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
    349				val, !(val & STARTBUSY), 1, 10000);
    350		if (ret)
    351			return ret;
    352
    353		/* Write data */
    354		val = *((u32 *)&entry->val + i);
    355		writel(val, ioaddr + MTL_RXP_IACC_DATA);
    356
    357		/* Write pos */
    358		val = real_pos & ADDR;
    359		writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
    360
    361		/* Write OP */
    362		val |= WRRDN;
    363		writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
    364
    365		/* Start Write */
    366		val |= STARTBUSY;
    367		writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
    368
    369		/* Wait for done */
    370		ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
    371				val, !(val & STARTBUSY), 1, 10000);
    372		if (ret)
    373			return ret;
    374	}
    375
    376	return 0;
    377}
    378
    379static struct stmmac_tc_entry *
    380dwmac5_rxp_get_next_entry(struct stmmac_tc_entry *entries, unsigned int count,
    381			  u32 curr_prio)
    382{
    383	struct stmmac_tc_entry *entry;
    384	u32 min_prio = ~0x0;
    385	int i, min_prio_idx;
    386	bool found = false;
    387
    388	for (i = count - 1; i >= 0; i--) {
    389		entry = &entries[i];
    390
    391		/* Do not update unused entries */
    392		if (!entry->in_use)
    393			continue;
    394		/* Do not update already updated entries (i.e. fragments) */
    395		if (entry->in_hw)
    396			continue;
    397		/* Let last entry be updated last */
    398		if (entry->is_last)
    399			continue;
    400		/* Do not return fragments */
    401		if (entry->is_frag)
    402			continue;
    403		/* Check if we already checked this prio */
    404		if (entry->prio < curr_prio)
    405			continue;
    406		/* Check if this is the minimum prio */
    407		if (entry->prio < min_prio) {
    408			min_prio = entry->prio;
    409			min_prio_idx = i;
    410			found = true;
    411		}
    412	}
    413
    414	if (found)
    415		return &entries[min_prio_idx];
    416	return NULL;
    417}
    418
    419int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
    420		      unsigned int count)
    421{
    422	struct stmmac_tc_entry *entry, *frag;
    423	int i, ret, nve = 0;
    424	u32 curr_prio = 0;
    425	u32 old_val, val;
    426
    427	/* Force disable RX */
    428	old_val = readl(ioaddr + GMAC_CONFIG);
    429	val = old_val & ~GMAC_CONFIG_RE;
    430	writel(val, ioaddr + GMAC_CONFIG);
    431
    432	/* Disable RX Parser */
    433	ret = dwmac5_rxp_disable(ioaddr);
    434	if (ret)
    435		goto re_enable;
    436
    437	/* Set all entries as NOT in HW */
    438	for (i = 0; i < count; i++) {
    439		entry = &entries[i];
    440		entry->in_hw = false;
    441	}
    442
    443	/* Update entries by reverse order */
    444	while (1) {
    445		entry = dwmac5_rxp_get_next_entry(entries, count, curr_prio);
    446		if (!entry)
    447			break;
    448
    449		curr_prio = entry->prio;
    450		frag = entry->frag_ptr;
    451
    452		/* Set special fragment requirements */
    453		if (frag) {
    454			entry->val.af = 0;
    455			entry->val.rf = 0;
    456			entry->val.nc = 1;
    457			entry->val.ok_index = nve + 2;
    458		}
    459
    460		ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
    461		if (ret)
    462			goto re_enable;
    463
    464		entry->table_pos = nve++;
    465		entry->in_hw = true;
    466
    467		if (frag && !frag->in_hw) {
    468			ret = dwmac5_rxp_update_single_entry(ioaddr, frag, nve);
    469			if (ret)
    470				goto re_enable;
    471			frag->table_pos = nve++;
    472			frag->in_hw = true;
    473		}
    474	}
    475
    476	if (!nve)
    477		goto re_enable;
    478
    479	/* Update all pass entry */
    480	for (i = 0; i < count; i++) {
    481		entry = &entries[i];
    482		if (!entry->is_last)
    483			continue;
    484
    485		ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
    486		if (ret)
    487			goto re_enable;
    488
    489		entry->table_pos = nve++;
    490	}
    491
    492	/* Assume n. of parsable entries == n. of valid entries */
    493	val = (nve << 16) & NPE;
    494	val |= nve & NVE;
    495	writel(val, ioaddr + MTL_RXP_CONTROL_STATUS);
    496
    497	/* Enable RX Parser */
    498	dwmac5_rxp_enable(ioaddr);
    499
    500re_enable:
    501	/* Re-enable RX */
    502	writel(old_val, ioaddr + GMAC_CONFIG);
    503	return ret;
    504}
    505
    506int dwmac5_flex_pps_config(void __iomem *ioaddr, int index,
    507			   struct stmmac_pps_cfg *cfg, bool enable,
    508			   u32 sub_second_inc, u32 systime_flags)
    509{
    510	u32 tnsec = readl(ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
    511	u32 val = readl(ioaddr + MAC_PPS_CONTROL);
    512	u64 period;
    513
    514	if (!cfg->available)
    515		return -EINVAL;
    516	if (tnsec & TRGTBUSY0)
    517		return -EBUSY;
    518	if (!sub_second_inc || !systime_flags)
    519		return -EINVAL;
    520
    521	val &= ~PPSx_MASK(index);
    522
    523	if (!enable) {
    524		val |= PPSCMDx(index, 0x5);
    525		val |= PPSEN0;
    526		writel(val, ioaddr + MAC_PPS_CONTROL);
    527		return 0;
    528	}
    529
    530	val |= PPSCMDx(index, 0x2);
    531	val |= TRGTMODSELx(index, 0x2);
    532	val |= PPSEN0;
    533
    534	writel(cfg->start.tv_sec, ioaddr + MAC_PPSx_TARGET_TIME_SEC(index));
    535
    536	if (!(systime_flags & PTP_TCR_TSCTRLSSR))
    537		cfg->start.tv_nsec = (cfg->start.tv_nsec * 1000) / 465;
    538	writel(cfg->start.tv_nsec, ioaddr + MAC_PPSx_TARGET_TIME_NSEC(index));
    539
    540	period = cfg->period.tv_sec * 1000000000;
    541	period += cfg->period.tv_nsec;
    542
    543	do_div(period, sub_second_inc);
    544
    545	if (period <= 1)
    546		return -EINVAL;
    547
    548	writel(period - 1, ioaddr + MAC_PPSx_INTERVAL(index));
    549
    550	period >>= 1;
    551	if (period <= 1)
    552		return -EINVAL;
    553
    554	writel(period - 1, ioaddr + MAC_PPSx_WIDTH(index));
    555
    556	/* Finally, activate it */
    557	writel(val, ioaddr + MAC_PPS_CONTROL);
    558	return 0;
    559}
    560
    561static int dwmac5_est_write(void __iomem *ioaddr, u32 reg, u32 val, bool gcl)
    562{
    563	u32 ctrl;
    564
    565	writel(val, ioaddr + MTL_EST_GCL_DATA);
    566
    567	ctrl = (reg << ADDR_SHIFT);
    568	ctrl |= gcl ? 0 : GCRR;
    569
    570	writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
    571
    572	ctrl |= SRWO;
    573	writel(ctrl, ioaddr + MTL_EST_GCL_CONTROL);
    574
    575	return readl_poll_timeout(ioaddr + MTL_EST_GCL_CONTROL,
    576				  ctrl, !(ctrl & SRWO), 100, 5000);
    577}
    578
    579int dwmac5_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
    580			 unsigned int ptp_rate)
    581{
    582	int i, ret = 0x0;
    583	u32 ctrl;
    584
    585	ret |= dwmac5_est_write(ioaddr, BTR_LOW, cfg->btr[0], false);
    586	ret |= dwmac5_est_write(ioaddr, BTR_HIGH, cfg->btr[1], false);
    587	ret |= dwmac5_est_write(ioaddr, TER, cfg->ter, false);
    588	ret |= dwmac5_est_write(ioaddr, LLR, cfg->gcl_size, false);
    589	ret |= dwmac5_est_write(ioaddr, CTR_LOW, cfg->ctr[0], false);
    590	ret |= dwmac5_est_write(ioaddr, CTR_HIGH, cfg->ctr[1], false);
    591	if (ret)
    592		return ret;
    593
    594	for (i = 0; i < cfg->gcl_size; i++) {
    595		ret = dwmac5_est_write(ioaddr, i, cfg->gcl[i], true);
    596		if (ret)
    597			return ret;
    598	}
    599
    600	ctrl = readl(ioaddr + MTL_EST_CONTROL);
    601	ctrl &= ~PTOV;
    602	ctrl |= ((1000000000 / ptp_rate) * 6) << PTOV_SHIFT;
    603	if (cfg->enable)
    604		ctrl |= EEST | SSWL;
    605	else
    606		ctrl &= ~EEST;
    607
    608	writel(ctrl, ioaddr + MTL_EST_CONTROL);
    609
    610	/* Configure EST interrupt */
    611	if (cfg->enable)
    612		ctrl = (IECGCE | IEHS | IEHF | IEBE | IECC);
    613	else
    614		ctrl = 0;
    615
    616	writel(ctrl, ioaddr + MTL_EST_INT_EN);
    617
    618	return 0;
    619}
    620
    621void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
    622			  struct stmmac_extra_stats *x, u32 txqcnt)
    623{
    624	u32 status, value, feqn, hbfq, hbfs, btrl;
    625	u32 txqcnt_mask = (1 << txqcnt) - 1;
    626
    627	status = readl(ioaddr + MTL_EST_STATUS);
    628
    629	value = (CGCE | HLBS | HLBF | BTRE | SWLC);
    630
    631	/* Return if there is no error */
    632	if (!(status & value))
    633		return;
    634
    635	if (status & CGCE) {
    636		/* Clear Interrupt */
    637		writel(CGCE, ioaddr + MTL_EST_STATUS);
    638
    639		x->mtl_est_cgce++;
    640	}
    641
    642	if (status & HLBS) {
    643		value = readl(ioaddr + MTL_EST_SCH_ERR);
    644		value &= txqcnt_mask;
    645
    646		x->mtl_est_hlbs++;
    647
    648		/* Clear Interrupt */
    649		writel(value, ioaddr + MTL_EST_SCH_ERR);
    650
    651		/* Collecting info to shows all the queues that has HLBS
    652		 * issue. The only way to clear this is to clear the
    653		 * statistic
    654		 */
    655		if (net_ratelimit())
    656			netdev_err(dev, "EST: HLB(sched) Queue 0x%x\n", value);
    657	}
    658
    659	if (status & HLBF) {
    660		value = readl(ioaddr + MTL_EST_FRM_SZ_ERR);
    661		feqn = value & txqcnt_mask;
    662
    663		value = readl(ioaddr + MTL_EST_FRM_SZ_CAP);
    664		hbfq = (value & SZ_CAP_HBFQ_MASK(txqcnt)) >> SZ_CAP_HBFQ_SHIFT;
    665		hbfs = value & SZ_CAP_HBFS_MASK;
    666
    667		x->mtl_est_hlbf++;
    668
    669		/* Clear Interrupt */
    670		writel(feqn, ioaddr + MTL_EST_FRM_SZ_ERR);
    671
    672		if (net_ratelimit())
    673			netdev_err(dev, "EST: HLB(size) Queue %u Size %u\n",
    674				   hbfq, hbfs);
    675	}
    676
    677	if (status & BTRE) {
    678		if ((status & BTRL) == BTRL_MAX)
    679			x->mtl_est_btrlm++;
    680		else
    681			x->mtl_est_btre++;
    682
    683		btrl = (status & BTRL) >> BTRL_SHIFT;
    684
    685		if (net_ratelimit())
    686			netdev_info(dev, "EST: BTR Error Loop Count %u\n",
    687				    btrl);
    688
    689		writel(BTRE, ioaddr + MTL_EST_STATUS);
    690	}
    691
    692	if (status & SWLC) {
    693		writel(SWLC, ioaddr + MTL_EST_STATUS);
    694		netdev_info(dev, "EST: SWOL has been switched\n");
    695	}
    696}
    697
    698void dwmac5_fpe_configure(void __iomem *ioaddr, u32 num_txq, u32 num_rxq,
    699			  bool enable)
    700{
    701	u32 value;
    702
    703	if (!enable) {
    704		value = readl(ioaddr + MAC_FPE_CTRL_STS);
    705
    706		value &= ~EFPE;
    707
    708		writel(value, ioaddr + MAC_FPE_CTRL_STS);
    709		return;
    710	}
    711
    712	value = readl(ioaddr + GMAC_RXQ_CTRL1);
    713	value &= ~GMAC_RXQCTRL_FPRQ;
    714	value |= (num_rxq - 1) << GMAC_RXQCTRL_FPRQ_SHIFT;
    715	writel(value, ioaddr + GMAC_RXQ_CTRL1);
    716
    717	value = readl(ioaddr + MAC_FPE_CTRL_STS);
    718	value |= EFPE;
    719	writel(value, ioaddr + MAC_FPE_CTRL_STS);
    720}
    721
    722int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
    723{
    724	u32 value;
    725	int status;
    726
    727	status = FPE_EVENT_UNKNOWN;
    728
    729	value = readl(ioaddr + MAC_FPE_CTRL_STS);
    730
    731	if (value & TRSP) {
    732		status |= FPE_EVENT_TRSP;
    733		netdev_info(dev, "FPE: Respond mPacket is transmitted\n");
    734	}
    735
    736	if (value & TVER) {
    737		status |= FPE_EVENT_TVER;
    738		netdev_info(dev, "FPE: Verify mPacket is transmitted\n");
    739	}
    740
    741	if (value & RRSP) {
    742		status |= FPE_EVENT_RRSP;
    743		netdev_info(dev, "FPE: Respond mPacket is received\n");
    744	}
    745
    746	if (value & RVER) {
    747		status |= FPE_EVENT_RVER;
    748		netdev_info(dev, "FPE: Verify mPacket is received\n");
    749	}
    750
    751	return status;
    752}
    753
    754void dwmac5_fpe_send_mpacket(void __iomem *ioaddr, enum stmmac_mpacket_type type)
    755{
    756	u32 value;
    757
    758	value = readl(ioaddr + MAC_FPE_CTRL_STS);
    759
    760	if (type == MPACKET_VERIFY) {
    761		value &= ~SRSP;
    762		value |= SVER;
    763	} else {
    764		value &= ~SVER;
    765		value |= SRSP;
    766	}
    767
    768	writel(value, ioaddr + MAC_FPE_CTRL_STS);
    769}