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