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