linux/drivers/net/ethernet/stmicro/stmmac/norm_desc.c
<<
>>
Prefs
   1/*******************************************************************************
   2  This contains the functions to handle the normal descriptors.
   3
   4  Copyright (C) 2007-2009  STMicroelectronics Ltd
   5
   6  This program is free software; you can redistribute it and/or modify it
   7  under the terms and conditions of the GNU General Public License,
   8  version 2, as published by the Free Software Foundation.
   9
  10  This program is distributed in the hope it will be useful, but WITHOUT
  11  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13  more details.
  14
  15  You should have received a copy of the GNU General Public License along with
  16  this program; if not, write to the Free Software Foundation, Inc.,
  17  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  18
  19  The full GNU General Public License is included in this distribution in
  20  the file called "COPYING".
  21
  22  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
  23*******************************************************************************/
  24
  25#include <linux/stmmac.h>
  26#include "common.h"
  27#include "descs_com.h"
  28
  29static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
  30                               struct dma_desc *p, void __iomem *ioaddr)
  31{
  32        int ret = 0;
  33        struct net_device_stats *stats = (struct net_device_stats *)data;
  34
  35        if (unlikely(p->des01.tx.error_summary)) {
  36                if (unlikely(p->des01.tx.underflow_error)) {
  37                        x->tx_underflow++;
  38                        stats->tx_fifo_errors++;
  39                }
  40                if (unlikely(p->des01.tx.no_carrier)) {
  41                        x->tx_carrier++;
  42                        stats->tx_carrier_errors++;
  43                }
  44                if (unlikely(p->des01.tx.loss_carrier)) {
  45                        x->tx_losscarrier++;
  46                        stats->tx_carrier_errors++;
  47                }
  48                if (unlikely((p->des01.tx.excessive_deferral) ||
  49                             (p->des01.tx.excessive_collisions) ||
  50                             (p->des01.tx.late_collision)))
  51                        stats->collisions += p->des01.tx.collision_count;
  52                ret = -1;
  53        }
  54
  55        if (p->des01.etx.vlan_frame) {
  56                CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
  57                x->tx_vlan++;
  58        }
  59
  60        if (unlikely(p->des01.tx.deferred))
  61                x->tx_deferred++;
  62
  63        return ret;
  64}
  65
  66static int ndesc_get_tx_len(struct dma_desc *p)
  67{
  68        return p->des01.tx.buffer1_size;
  69}
  70
  71/* This function verifies if each incoming frame has some errors
  72 * and, if required, updates the multicast statistics.
  73 * In case of success, it returns good_frame because the GMAC device
  74 * is supposed to be able to compute the csum in HW. */
  75static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
  76                               struct dma_desc *p)
  77{
  78        int ret = good_frame;
  79        struct net_device_stats *stats = (struct net_device_stats *)data;
  80
  81        if (unlikely(p->des01.rx.last_descriptor == 0)) {
  82                pr_warn("%s: Oversized frame spanned multiple buffers\n",
  83                        __func__);
  84                stats->rx_length_errors++;
  85                return discard_frame;
  86        }
  87
  88        if (unlikely(p->des01.rx.error_summary)) {
  89                if (unlikely(p->des01.rx.descriptor_error))
  90                        x->rx_desc++;
  91                if (unlikely(p->des01.rx.sa_filter_fail))
  92                        x->sa_filter_fail++;
  93                if (unlikely(p->des01.rx.overflow_error))
  94                        x->overflow_error++;
  95                if (unlikely(p->des01.rx.ipc_csum_error))
  96                        x->ipc_csum_error++;
  97                if (unlikely(p->des01.rx.collision)) {
  98                        x->rx_collision++;
  99                        stats->collisions++;
 100                }
 101                if (unlikely(p->des01.rx.crc_error)) {
 102                        x->rx_crc++;
 103                        stats->rx_crc_errors++;
 104                }
 105                ret = discard_frame;
 106        }
 107        if (unlikely(p->des01.rx.dribbling))
 108                x->dribbling_bit++;
 109
 110        if (unlikely(p->des01.rx.length_error)) {
 111                x->rx_length++;
 112                ret = discard_frame;
 113        }
 114        if (unlikely(p->des01.rx.mii_error)) {
 115                x->rx_mii++;
 116                ret = discard_frame;
 117        }
 118#ifdef STMMAC_VLAN_TAG_USED
 119        if (p->des01.rx.vlan_tag)
 120                x->vlan_tag++;
 121#endif
 122        return ret;
 123}
 124
 125static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
 126                               int end)
 127{
 128        p->des01.rx.own = 1;
 129        p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
 130
 131        if (mode == STMMAC_CHAIN_MODE)
 132                ndesc_rx_set_on_chain(p, end);
 133        else
 134                ndesc_rx_set_on_ring(p, end);
 135
 136        if (disable_rx_ic)
 137                p->des01.rx.disable_ic = 1;
 138}
 139
 140static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
 141{
 142        p->des01.tx.own = 0;
 143        if (mode == STMMAC_CHAIN_MODE)
 144                ndesc_tx_set_on_chain(p, end);
 145        else
 146                ndesc_tx_set_on_ring(p, end);
 147}
 148
 149static int ndesc_get_tx_owner(struct dma_desc *p)
 150{
 151        return p->des01.tx.own;
 152}
 153
 154static int ndesc_get_rx_owner(struct dma_desc *p)
 155{
 156        return p->des01.rx.own;
 157}
 158
 159static void ndesc_set_tx_owner(struct dma_desc *p)
 160{
 161        p->des01.tx.own = 1;
 162}
 163
 164static void ndesc_set_rx_owner(struct dma_desc *p)
 165{
 166        p->des01.rx.own = 1;
 167}
 168
 169static int ndesc_get_tx_ls(struct dma_desc *p)
 170{
 171        return p->des01.tx.last_segment;
 172}
 173
 174static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
 175{
 176        int ter = p->des01.tx.end_ring;
 177
 178        memset(p, 0, offsetof(struct dma_desc, des2));
 179        if (mode == STMMAC_CHAIN_MODE)
 180                ndesc_end_tx_desc_on_chain(p, ter);
 181        else
 182                ndesc_end_tx_desc_on_ring(p, ter);
 183}
 184
 185static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 186                                  int csum_flag, int mode)
 187{
 188        p->des01.tx.first_segment = is_fs;
 189        if (mode == STMMAC_CHAIN_MODE)
 190                norm_set_tx_desc_len_on_chain(p, len);
 191        else
 192                norm_set_tx_desc_len_on_ring(p, len);
 193
 194        if (likely(csum_flag))
 195                p->des01.tx.checksum_insertion = cic_full;
 196}
 197
 198static void ndesc_clear_tx_ic(struct dma_desc *p)
 199{
 200        p->des01.tx.interrupt = 0;
 201}
 202
 203static void ndesc_close_tx_desc(struct dma_desc *p)
 204{
 205        p->des01.tx.last_segment = 1;
 206        p->des01.tx.interrupt = 1;
 207}
 208
 209static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
 210{
 211        /* The type-1 checksum offload engines append the checksum at
 212         * the end of frame and the two bytes of checksum are added in
 213         * the length.
 214         * Adjust for that in the framelen for type-1 checksum offload
 215         * engines. */
 216        if (rx_coe_type == STMMAC_RX_COE_TYPE1)
 217                return p->des01.rx.frame_length - 2;
 218        else
 219                return p->des01.rx.frame_length;
 220}
 221
 222static void ndesc_enable_tx_timestamp(struct dma_desc *p)
 223{
 224        p->des01.tx.time_stamp_enable = 1;
 225}
 226
 227static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
 228{
 229        return p->des01.tx.time_stamp_status;
 230}
 231
 232static u64 ndesc_get_timestamp(void *desc, u32 ats)
 233{
 234        struct dma_desc *p = (struct dma_desc *)desc;
 235        u64 ns;
 236
 237        ns = p->des2;
 238        /* convert high/sec time stamp value to nanosecond */
 239        ns += p->des3 * 1000000000ULL;
 240
 241        return ns;
 242}
 243
 244static int ndesc_get_rx_timestamp_status(void *desc, u32 ats)
 245{
 246        struct dma_desc *p = (struct dma_desc *)desc;
 247
 248        if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
 249                /* timestamp is corrupted, hence don't store it */
 250                return 0;
 251        else
 252                return 1;
 253}
 254
 255const struct stmmac_desc_ops ndesc_ops = {
 256        .tx_status = ndesc_get_tx_status,
 257        .rx_status = ndesc_get_rx_status,
 258        .get_tx_len = ndesc_get_tx_len,
 259        .init_rx_desc = ndesc_init_rx_desc,
 260        .init_tx_desc = ndesc_init_tx_desc,
 261        .get_tx_owner = ndesc_get_tx_owner,
 262        .get_rx_owner = ndesc_get_rx_owner,
 263        .release_tx_desc = ndesc_release_tx_desc,
 264        .prepare_tx_desc = ndesc_prepare_tx_desc,
 265        .clear_tx_ic = ndesc_clear_tx_ic,
 266        .close_tx_desc = ndesc_close_tx_desc,
 267        .get_tx_ls = ndesc_get_tx_ls,
 268        .set_tx_owner = ndesc_set_tx_owner,
 269        .set_rx_owner = ndesc_set_rx_owner,
 270        .get_rx_frame_len = ndesc_get_rx_frame_len,
 271        .enable_tx_timestamp = ndesc_enable_tx_timestamp,
 272        .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
 273        .get_timestamp = ndesc_get_timestamp,
 274        .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
 275};
 276