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