brintos

brintos / linux-shallow public Read only

0
0
Text · 8.0 KiB · 4846bf4 Raw
302 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*******************************************************************************3  Copyright (C) 2007-2009  STMicroelectronics Ltd4 5 6  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>7*******************************************************************************/8 9#include <linux/io.h>10#include <linux/iopoll.h>11#include "common.h"12#include "dwmac_dma.h"13#include "stmmac.h"14 15#define GMAC_HI_REG_AE		0x8000000016 17int dwmac_dma_reset(void __iomem *ioaddr)18{19	u32 value = readl(ioaddr + DMA_BUS_MODE);20 21	/* DMA SW reset */22	value |= DMA_BUS_MODE_SFT_RESET;23	writel(value, ioaddr + DMA_BUS_MODE);24 25	return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value,26				 !(value & DMA_BUS_MODE_SFT_RESET),27				 10000, 200000);28}29 30/* CSR1 enables the transmit DMA to check for new descriptor */31void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan)32{33	writel(1, ioaddr + DMA_CHAN_XMT_POLL_DEMAND(chan));34}35 36void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,37			  u32 chan, bool rx, bool tx)38{39	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));40 41	if (rx)42		value |= DMA_INTR_DEFAULT_RX;43	if (tx)44		value |= DMA_INTR_DEFAULT_TX;45 46	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));47}48 49void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr,50			   u32 chan, bool rx, bool tx)51{52	u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(chan));53 54	if (rx)55		value &= ~DMA_INTR_DEFAULT_RX;56	if (tx)57		value &= ~DMA_INTR_DEFAULT_TX;58 59	writel(value, ioaddr + DMA_CHAN_INTR_ENA(chan));60}61 62void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr,63			u32 chan)64{65	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));66	value |= DMA_CONTROL_ST;67	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));68}69 70void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)71{72	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));73	value &= ~DMA_CONTROL_ST;74	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));75}76 77void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr,78			u32 chan)79{80	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));81	value |= DMA_CONTROL_SR;82	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));83}84 85void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan)86{87	u32 value = readl(ioaddr + DMA_CHAN_CONTROL(chan));88	value &= ~DMA_CONTROL_SR;89	writel(value, ioaddr + DMA_CHAN_CONTROL(chan));90}91 92#ifdef DWMAC_DMA_DEBUG93static void show_tx_process_state(unsigned int status)94{95	unsigned int state;96	state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;97 98	switch (state) {99	case 0:100		pr_debug("- TX (Stopped): Reset or Stop command\n");101		break;102	case 1:103		pr_debug("- TX (Running): Fetching the Tx desc\n");104		break;105	case 2:106		pr_debug("- TX (Running): Waiting for end of tx\n");107		break;108	case 3:109		pr_debug("- TX (Running): Reading the data "110		       "and queuing the data into the Tx buf\n");111		break;112	case 6:113		pr_debug("- TX (Suspended): Tx Buff Underflow "114		       "or an unavailable Transmit descriptor\n");115		break;116	case 7:117		pr_debug("- TX (Running): Closing Tx descriptor\n");118		break;119	default:120		break;121	}122}123 124static void show_rx_process_state(unsigned int status)125{126	unsigned int state;127	state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;128 129	switch (state) {130	case 0:131		pr_debug("- RX (Stopped): Reset or Stop command\n");132		break;133	case 1:134		pr_debug("- RX (Running): Fetching the Rx desc\n");135		break;136	case 2:137		pr_debug("- RX (Running): Checking for end of pkt\n");138		break;139	case 3:140		pr_debug("- RX (Running): Waiting for Rx pkt\n");141		break;142	case 4:143		pr_debug("- RX (Suspended): Unavailable Rx buf\n");144		break;145	case 5:146		pr_debug("- RX (Running): Closing Rx descriptor\n");147		break;148	case 6:149		pr_debug("- RX(Running): Flushing the current frame"150		       " from the Rx buf\n");151		break;152	case 7:153		pr_debug("- RX (Running): Queuing the Rx frame"154		       " from the Rx buf into memory\n");155		break;156	default:157		break;158	}159}160#endif161 162int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr,163			struct stmmac_extra_stats *x, u32 chan, u32 dir)164{165	struct stmmac_pcpu_stats *stats = this_cpu_ptr(priv->xstats.pcpu_stats);166	int ret = 0;167	/* read the status register (CSR5) */168	u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(chan));169 170#ifdef DWMAC_DMA_DEBUG171	/* Enable it to monitor DMA rx/tx status in case of critical problems */172	pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status);173	show_tx_process_state(intr_status);174	show_rx_process_state(intr_status);175#endif176 177	if (dir == DMA_DIR_RX)178		intr_status &= DMA_STATUS_MSK_RX;179	else if (dir == DMA_DIR_TX)180		intr_status &= DMA_STATUS_MSK_TX;181 182	/* ABNORMAL interrupts */183	if (unlikely(intr_status & DMA_STATUS_AIS)) {184		if (unlikely(intr_status & DMA_STATUS_UNF)) {185			ret = tx_hard_error_bump_tc;186			x->tx_undeflow_irq++;187		}188		if (unlikely(intr_status & DMA_STATUS_TJT))189			x->tx_jabber_irq++;190 191		if (unlikely(intr_status & DMA_STATUS_OVF))192			x->rx_overflow_irq++;193 194		if (unlikely(intr_status & DMA_STATUS_RU))195			x->rx_buf_unav_irq++;196		if (unlikely(intr_status & DMA_STATUS_RPS))197			x->rx_process_stopped_irq++;198		if (unlikely(intr_status & DMA_STATUS_RWT))199			x->rx_watchdog_irq++;200		if (unlikely(intr_status & DMA_STATUS_ETI))201			x->tx_early_irq++;202		if (unlikely(intr_status & DMA_STATUS_TPS)) {203			x->tx_process_stopped_irq++;204			ret = tx_hard_error;205		}206		if (unlikely(intr_status & DMA_STATUS_FBI)) {207			x->fatal_bus_error_irq++;208			ret = tx_hard_error;209		}210	}211	/* TX/RX NORMAL interrupts */212	if (likely(intr_status & DMA_STATUS_NIS)) {213		if (likely(intr_status & DMA_STATUS_RI)) {214			u32 value = readl(ioaddr + DMA_INTR_ENA);215			/* to schedule NAPI on real RIE event. */216			if (likely(value & DMA_INTR_ENA_RIE)) {217				u64_stats_update_begin(&stats->syncp);218				u64_stats_inc(&stats->rx_normal_irq_n[chan]);219				u64_stats_update_end(&stats->syncp);220				ret |= handle_rx;221			}222		}223		if (likely(intr_status & DMA_STATUS_TI)) {224			u64_stats_update_begin(&stats->syncp);225			u64_stats_inc(&stats->tx_normal_irq_n[chan]);226			u64_stats_update_end(&stats->syncp);227			ret |= handle_tx;228		}229		if (unlikely(intr_status & DMA_STATUS_ERI))230			x->rx_early_irq++;231	}232	/* Optional hardware blocks, interrupts should be disabled */233	if (unlikely(intr_status &234		     (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))235		pr_warn("%s: unexpected status %08x\n", __func__, intr_status);236 237	/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */238	writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);239 240	return ret;241}242 243void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)244{245	u32 csr6 = readl(ioaddr + DMA_CONTROL);246	writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);247 248	do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));249}250 251void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6],252			 unsigned int high, unsigned int low)253{254	unsigned long data;255 256	data = (addr[5] << 8) | addr[4];257	/* For MAC Addr registers we have to set the Address Enable (AE)258	 * bit that has no effect on the High Reg 0 where the bit 31 (MO)259	 * is RO.260	 */261	writel(data | GMAC_HI_REG_AE, ioaddr + high);262	data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];263	writel(data, ioaddr + low);264}265EXPORT_SYMBOL_GPL(stmmac_set_mac_addr);266 267/* Enable disable MAC RX/TX */268void stmmac_set_mac(void __iomem *ioaddr, bool enable)269{270	u32 old_val, value;271 272	old_val = readl(ioaddr + MAC_CTRL_REG);273	value = old_val;274 275	if (enable)276		value |= MAC_ENABLE_RX | MAC_ENABLE_TX;277	else278		value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX);279 280	if (value != old_val)281		writel(value, ioaddr + MAC_CTRL_REG);282}283 284void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,285			 unsigned int high, unsigned int low)286{287	unsigned int hi_addr, lo_addr;288 289	/* Read the MAC address from the hardware */290	hi_addr = readl(ioaddr + high);291	lo_addr = readl(ioaddr + low);292 293	/* Extract the MAC address from the high and low words */294	addr[0] = lo_addr & 0xff;295	addr[1] = (lo_addr >> 8) & 0xff;296	addr[2] = (lo_addr >> 16) & 0xff;297	addr[3] = (lo_addr >> 24) & 0xff;298	addr[4] = hi_addr & 0xff;299	addr[5] = (hi_addr >> 8) & 0xff;300}301EXPORT_SYMBOL_GPL(stmmac_get_mac_addr);302