18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* 10G controller driver for Samsung SoCs
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2013 Samsung Electronics Co., Ltd.
58c2ecf20Sopenharmony_ci *		http://www.samsung.com
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/io.h>
128c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/phy.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "sxgbe_common.h"
168c2ecf20Sopenharmony_ci#include "sxgbe_dma.h"
178c2ecf20Sopenharmony_ci#include "sxgbe_reg.h"
188c2ecf20Sopenharmony_ci#include "sxgbe_desc.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* DMA core initialization */
218c2ecf20Sopenharmony_cistatic int sxgbe_dma_init(void __iomem *ioaddr, int fix_burst, int burst_map)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	u32 reg_val;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	reg_val = readl(ioaddr + SXGBE_DMA_SYSBUS_MODE_REG);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	/* if fix_burst = 0, Set UNDEF = 1 of DMA_Sys_Mode Register.
288c2ecf20Sopenharmony_ci	 * if fix_burst = 1, Set UNDEF = 0 of DMA_Sys_Mode Register.
298c2ecf20Sopenharmony_ci	 * burst_map is bitmap for  BLEN[4, 8, 16, 32, 64, 128 and 256].
308c2ecf20Sopenharmony_ci	 * Set burst_map irrespective of fix_burst value.
318c2ecf20Sopenharmony_ci	 */
328c2ecf20Sopenharmony_ci	if (!fix_burst)
338c2ecf20Sopenharmony_ci		reg_val |= SXGBE_DMA_AXI_UNDEF_BURST;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* write burst len map */
368c2ecf20Sopenharmony_ci	reg_val |= (burst_map << SXGBE_DMA_BLENMAP_LSHIFT);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	writel(reg_val,	ioaddr + SXGBE_DMA_SYSBUS_MODE_REG);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	return 0;
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic void sxgbe_dma_channel_init(void __iomem *ioaddr, int cha_num,
448c2ecf20Sopenharmony_ci				   int fix_burst, int pbl, dma_addr_t dma_tx,
458c2ecf20Sopenharmony_ci				   dma_addr_t dma_rx, int t_rsize, int r_rsize)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	u32 reg_val;
488c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	reg_val = readl(ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num));
518c2ecf20Sopenharmony_ci	/* set the pbl */
528c2ecf20Sopenharmony_ci	if (fix_burst) {
538c2ecf20Sopenharmony_ci		reg_val |= SXGBE_DMA_PBL_X8MODE;
548c2ecf20Sopenharmony_ci		writel(reg_val, ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num));
558c2ecf20Sopenharmony_ci		/* program the TX pbl */
568c2ecf20Sopenharmony_ci		reg_val = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
578c2ecf20Sopenharmony_ci		reg_val |= (pbl << SXGBE_DMA_TXPBL_LSHIFT);
588c2ecf20Sopenharmony_ci		writel(reg_val, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
598c2ecf20Sopenharmony_ci		/* program the RX pbl */
608c2ecf20Sopenharmony_ci		reg_val = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num));
618c2ecf20Sopenharmony_ci		reg_val |= (pbl << SXGBE_DMA_RXPBL_LSHIFT);
628c2ecf20Sopenharmony_ci		writel(reg_val, ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num));
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* program desc registers */
668c2ecf20Sopenharmony_ci	writel(upper_32_bits(dma_tx),
678c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_TXDESC_HADD_REG(cha_num));
688c2ecf20Sopenharmony_ci	writel(lower_32_bits(dma_tx),
698c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_TXDESC_LADD_REG(cha_num));
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	writel(upper_32_bits(dma_rx),
728c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_RXDESC_HADD_REG(cha_num));
738c2ecf20Sopenharmony_ci	writel(lower_32_bits(dma_rx),
748c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num));
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/* program tail pointers */
778c2ecf20Sopenharmony_ci	/* assumption: upper 32 bits are constant and
788c2ecf20Sopenharmony_ci	 * same as TX/RX desc list
798c2ecf20Sopenharmony_ci	 */
808c2ecf20Sopenharmony_ci	dma_addr = dma_tx + ((t_rsize - 1) * SXGBE_DESC_SIZE_BYTES);
818c2ecf20Sopenharmony_ci	writel(lower_32_bits(dma_addr),
828c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_TXDESC_TAILPTR_REG(cha_num));
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	dma_addr = dma_rx + ((r_rsize - 1) * SXGBE_DESC_SIZE_BYTES);
858c2ecf20Sopenharmony_ci	writel(lower_32_bits(dma_addr),
868c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num));
878c2ecf20Sopenharmony_ci	/* program the ring sizes */
888c2ecf20Sopenharmony_ci	writel(t_rsize - 1, ioaddr + SXGBE_DMA_CHA_TXDESC_RINGLEN_REG(cha_num));
898c2ecf20Sopenharmony_ci	writel(r_rsize - 1, ioaddr + SXGBE_DMA_CHA_RXDESC_RINGLEN_REG(cha_num));
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* Enable TX/RX interrupts */
928c2ecf20Sopenharmony_ci	writel(SXGBE_DMA_ENA_INT,
938c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(cha_num));
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic void sxgbe_enable_dma_transmission(void __iomem *ioaddr, int cha_num)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	u32 tx_config;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	tx_config = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
1018c2ecf20Sopenharmony_ci	tx_config |= SXGBE_TX_START_DMA;
1028c2ecf20Sopenharmony_ci	writel(tx_config, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic void sxgbe_enable_dma_irq(void __iomem *ioaddr, int dma_cnum)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	/* Enable TX/RX interrupts */
1088c2ecf20Sopenharmony_ci	writel(SXGBE_DMA_ENA_INT,
1098c2ecf20Sopenharmony_ci	       ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum));
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic void sxgbe_disable_dma_irq(void __iomem *ioaddr, int dma_cnum)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	/* Disable TX/RX interrupts */
1158c2ecf20Sopenharmony_ci	writel(0, ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum));
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic void sxgbe_dma_start_tx(void __iomem *ioaddr, int tchannels)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	int cnum;
1218c2ecf20Sopenharmony_ci	u32 tx_ctl_reg;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	for (cnum = 0; cnum < tchannels; cnum++) {
1248c2ecf20Sopenharmony_ci		tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
1258c2ecf20Sopenharmony_ci		tx_ctl_reg |= SXGBE_TX_ENABLE;
1268c2ecf20Sopenharmony_ci		writel(tx_ctl_reg,
1278c2ecf20Sopenharmony_ci		       ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void sxgbe_dma_start_tx_queue(void __iomem *ioaddr, int dma_cnum)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	u32 tx_ctl_reg;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
1368c2ecf20Sopenharmony_ci	tx_ctl_reg |= SXGBE_TX_ENABLE;
1378c2ecf20Sopenharmony_ci	writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic void sxgbe_dma_stop_tx_queue(void __iomem *ioaddr, int dma_cnum)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	u32 tx_ctl_reg;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
1458c2ecf20Sopenharmony_ci	tx_ctl_reg &= ~(SXGBE_TX_ENABLE);
1468c2ecf20Sopenharmony_ci	writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void sxgbe_dma_stop_tx(void __iomem *ioaddr, int tchannels)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	int cnum;
1528c2ecf20Sopenharmony_ci	u32 tx_ctl_reg;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	for (cnum = 0; cnum < tchannels; cnum++) {
1558c2ecf20Sopenharmony_ci		tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
1568c2ecf20Sopenharmony_ci		tx_ctl_reg &= ~(SXGBE_TX_ENABLE);
1578c2ecf20Sopenharmony_ci		writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic void sxgbe_dma_start_rx(void __iomem *ioaddr, int rchannels)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	int cnum;
1648c2ecf20Sopenharmony_ci	u32 rx_ctl_reg;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	for (cnum = 0; cnum < rchannels; cnum++) {
1678c2ecf20Sopenharmony_ci		rx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
1688c2ecf20Sopenharmony_ci		rx_ctl_reg |= SXGBE_RX_ENABLE;
1698c2ecf20Sopenharmony_ci		writel(rx_ctl_reg,
1708c2ecf20Sopenharmony_ci		       ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic void sxgbe_dma_stop_rx(void __iomem *ioaddr, int rchannels)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	int cnum;
1778c2ecf20Sopenharmony_ci	u32 rx_ctl_reg;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	for (cnum = 0; cnum < rchannels; cnum++) {
1808c2ecf20Sopenharmony_ci		rx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
1818c2ecf20Sopenharmony_ci		rx_ctl_reg &= ~(SXGBE_RX_ENABLE);
1828c2ecf20Sopenharmony_ci		writel(rx_ctl_reg, ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int sxgbe_tx_dma_int_status(void __iomem *ioaddr, int channel_no,
1878c2ecf20Sopenharmony_ci				   struct sxgbe_extra_stats *x)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	u32 int_status = readl(ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
1908c2ecf20Sopenharmony_ci	u32 clear_val = 0;
1918c2ecf20Sopenharmony_ci	u32 ret_val = 0;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* TX Normal Interrupt Summary */
1948c2ecf20Sopenharmony_ci	if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) {
1958c2ecf20Sopenharmony_ci		x->normal_irq_n++;
1968c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_TI) {
1978c2ecf20Sopenharmony_ci			ret_val |= handle_tx;
1988c2ecf20Sopenharmony_ci			x->tx_normal_irq_n++;
1998c2ecf20Sopenharmony_ci			clear_val |= SXGBE_DMA_INT_STATUS_TI;
2008c2ecf20Sopenharmony_ci		}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_TBU) {
2038c2ecf20Sopenharmony_ci			x->tx_underflow_irq++;
2048c2ecf20Sopenharmony_ci			ret_val |= tx_bump_tc;
2058c2ecf20Sopenharmony_ci			clear_val |= SXGBE_DMA_INT_STATUS_TBU;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci	} else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) {
2088c2ecf20Sopenharmony_ci		/* TX Abnormal Interrupt Summary */
2098c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_TPS) {
2108c2ecf20Sopenharmony_ci			ret_val |= tx_hard_error;
2118c2ecf20Sopenharmony_ci			clear_val |= SXGBE_DMA_INT_STATUS_TPS;
2128c2ecf20Sopenharmony_ci			x->tx_process_stopped_irq++;
2138c2ecf20Sopenharmony_ci		}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_FBE) {
2168c2ecf20Sopenharmony_ci			ret_val |= tx_hard_error;
2178c2ecf20Sopenharmony_ci			x->fatal_bus_error_irq++;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci			/* Assumption: FBE bit is the combination of
2208c2ecf20Sopenharmony_ci			 * all the bus access erros and cleared when
2218c2ecf20Sopenharmony_ci			 * the respective error bits cleared
2228c2ecf20Sopenharmony_ci			 */
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci			/* check for actual cause */
2258c2ecf20Sopenharmony_ci			if (int_status & SXGBE_DMA_INT_STATUS_TEB0) {
2268c2ecf20Sopenharmony_ci				x->tx_read_transfer_err++;
2278c2ecf20Sopenharmony_ci				clear_val |= SXGBE_DMA_INT_STATUS_TEB0;
2288c2ecf20Sopenharmony_ci			} else {
2298c2ecf20Sopenharmony_ci				x->tx_write_transfer_err++;
2308c2ecf20Sopenharmony_ci			}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci			if (int_status & SXGBE_DMA_INT_STATUS_TEB1) {
2338c2ecf20Sopenharmony_ci				x->tx_desc_access_err++;
2348c2ecf20Sopenharmony_ci				clear_val |= SXGBE_DMA_INT_STATUS_TEB1;
2358c2ecf20Sopenharmony_ci			} else {
2368c2ecf20Sopenharmony_ci				x->tx_buffer_access_err++;
2378c2ecf20Sopenharmony_ci			}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci			if (int_status & SXGBE_DMA_INT_STATUS_TEB2) {
2408c2ecf20Sopenharmony_ci				x->tx_data_transfer_err++;
2418c2ecf20Sopenharmony_ci				clear_val |= SXGBE_DMA_INT_STATUS_TEB2;
2428c2ecf20Sopenharmony_ci			}
2438c2ecf20Sopenharmony_ci		}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		/* context descriptor error */
2468c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_CTXTERR) {
2478c2ecf20Sopenharmony_ci			x->tx_ctxt_desc_err++;
2488c2ecf20Sopenharmony_ci			clear_val |= SXGBE_DMA_INT_STATUS_CTXTERR;
2498c2ecf20Sopenharmony_ci		}
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* clear the served bits */
2538c2ecf20Sopenharmony_ci	writel(clear_val, ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return ret_val;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic int sxgbe_rx_dma_int_status(void __iomem *ioaddr, int channel_no,
2598c2ecf20Sopenharmony_ci				   struct sxgbe_extra_stats *x)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	u32 int_status = readl(ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
2628c2ecf20Sopenharmony_ci	u32 clear_val = 0;
2638c2ecf20Sopenharmony_ci	u32 ret_val = 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	/* RX Normal Interrupt Summary */
2668c2ecf20Sopenharmony_ci	if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) {
2678c2ecf20Sopenharmony_ci		x->normal_irq_n++;
2688c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_RI) {
2698c2ecf20Sopenharmony_ci			ret_val |= handle_rx;
2708c2ecf20Sopenharmony_ci			x->rx_normal_irq_n++;
2718c2ecf20Sopenharmony_ci			clear_val |= SXGBE_DMA_INT_STATUS_RI;
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci	} else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) {
2748c2ecf20Sopenharmony_ci		/* RX Abnormal Interrupt Summary */
2758c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_RBU) {
2768c2ecf20Sopenharmony_ci			ret_val |= rx_bump_tc;
2778c2ecf20Sopenharmony_ci			clear_val |= SXGBE_DMA_INT_STATUS_RBU;
2788c2ecf20Sopenharmony_ci			x->rx_underflow_irq++;
2798c2ecf20Sopenharmony_ci		}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_RPS) {
2828c2ecf20Sopenharmony_ci			ret_val |= rx_hard_error;
2838c2ecf20Sopenharmony_ci			clear_val |= SXGBE_DMA_INT_STATUS_RPS;
2848c2ecf20Sopenharmony_ci			x->rx_process_stopped_irq++;
2858c2ecf20Sopenharmony_ci		}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		if (int_status & SXGBE_DMA_INT_STATUS_FBE) {
2888c2ecf20Sopenharmony_ci			ret_val |= rx_hard_error;
2898c2ecf20Sopenharmony_ci			x->fatal_bus_error_irq++;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci			/* Assumption: FBE bit is the combination of
2928c2ecf20Sopenharmony_ci			 * all the bus access erros and cleared when
2938c2ecf20Sopenharmony_ci			 * the respective error bits cleared
2948c2ecf20Sopenharmony_ci			 */
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci			/* check for actual cause */
2978c2ecf20Sopenharmony_ci			if (int_status & SXGBE_DMA_INT_STATUS_REB0) {
2988c2ecf20Sopenharmony_ci				x->rx_read_transfer_err++;
2998c2ecf20Sopenharmony_ci				clear_val |= SXGBE_DMA_INT_STATUS_REB0;
3008c2ecf20Sopenharmony_ci			} else {
3018c2ecf20Sopenharmony_ci				x->rx_write_transfer_err++;
3028c2ecf20Sopenharmony_ci			}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci			if (int_status & SXGBE_DMA_INT_STATUS_REB1) {
3058c2ecf20Sopenharmony_ci				x->rx_desc_access_err++;
3068c2ecf20Sopenharmony_ci				clear_val |= SXGBE_DMA_INT_STATUS_REB1;
3078c2ecf20Sopenharmony_ci			} else {
3088c2ecf20Sopenharmony_ci				x->rx_buffer_access_err++;
3098c2ecf20Sopenharmony_ci			}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci			if (int_status & SXGBE_DMA_INT_STATUS_REB2) {
3128c2ecf20Sopenharmony_ci				x->rx_data_transfer_err++;
3138c2ecf20Sopenharmony_ci				clear_val |= SXGBE_DMA_INT_STATUS_REB2;
3148c2ecf20Sopenharmony_ci			}
3158c2ecf20Sopenharmony_ci		}
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* clear the served bits */
3198c2ecf20Sopenharmony_ci	writel(clear_val, ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return ret_val;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci/* Program the HW RX Watchdog */
3258c2ecf20Sopenharmony_cistatic void sxgbe_dma_rx_watchdog(void __iomem *ioaddr, u32 riwt)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	u32 que_num;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, que_num) {
3308c2ecf20Sopenharmony_ci		writel(riwt,
3318c2ecf20Sopenharmony_ci		       ioaddr + SXGBE_DMA_CHA_INT_RXWATCHTMR_REG(que_num));
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic void sxgbe_enable_tso(void __iomem *ioaddr, u8 chan_num)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	u32 ctrl;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	ctrl = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num));
3408c2ecf20Sopenharmony_ci	ctrl |= SXGBE_DMA_CHA_TXCTL_TSE_ENABLE;
3418c2ecf20Sopenharmony_ci	writel(ctrl, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num));
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic const struct sxgbe_dma_ops sxgbe_dma_ops = {
3458c2ecf20Sopenharmony_ci	.init				= sxgbe_dma_init,
3468c2ecf20Sopenharmony_ci	.cha_init			= sxgbe_dma_channel_init,
3478c2ecf20Sopenharmony_ci	.enable_dma_transmission	= sxgbe_enable_dma_transmission,
3488c2ecf20Sopenharmony_ci	.enable_dma_irq			= sxgbe_enable_dma_irq,
3498c2ecf20Sopenharmony_ci	.disable_dma_irq		= sxgbe_disable_dma_irq,
3508c2ecf20Sopenharmony_ci	.start_tx			= sxgbe_dma_start_tx,
3518c2ecf20Sopenharmony_ci	.start_tx_queue			= sxgbe_dma_start_tx_queue,
3528c2ecf20Sopenharmony_ci	.stop_tx			= sxgbe_dma_stop_tx,
3538c2ecf20Sopenharmony_ci	.stop_tx_queue			= sxgbe_dma_stop_tx_queue,
3548c2ecf20Sopenharmony_ci	.start_rx			= sxgbe_dma_start_rx,
3558c2ecf20Sopenharmony_ci	.stop_rx			= sxgbe_dma_stop_rx,
3568c2ecf20Sopenharmony_ci	.tx_dma_int_status		= sxgbe_tx_dma_int_status,
3578c2ecf20Sopenharmony_ci	.rx_dma_int_status		= sxgbe_rx_dma_int_status,
3588c2ecf20Sopenharmony_ci	.rx_watchdog			= sxgbe_dma_rx_watchdog,
3598c2ecf20Sopenharmony_ci	.enable_tso			= sxgbe_enable_tso,
3608c2ecf20Sopenharmony_ci};
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ciconst struct sxgbe_dma_ops *sxgbe_get_dma_ops(void)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	return &sxgbe_dma_ops;
3658c2ecf20Sopenharmony_ci}
366