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