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                x->tx_vlan++;
  57
  58        if (unlikely(p->des01.tx.deferred))
  59                x->tx_deferred++;
  60
  61        return ret;
  62}
  63
  64static int ndesc_get_tx_len(struct dma_desc *p)
  65{
  66        return p->des01.tx.buffer1_size;
  67}
  68
  69/* This function verifies if each incoming frame has some errors
  70 * and, if required, updates the multicast statistics.
  71 * In case of success, it returns good_frame because the GMAC device
  72 * is supposed to be able to compute the csum in HW. */
  73static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
  74                               struct dma_desc *p)
  75{
  76        int ret = good_frame;
  77        struct net_device_stats *stats = (struct net_device_stats *)data;
  78
  79        if (unlikely(p->des01.rx.last_descriptor == 0)) {
  80                pr_warn("%s: Oversized frame spanned multiple buffers\n",
  81                        __func__);
  82                stats->rx_length_errors++;
  83                return discard_frame;
  84        }
  85
  86        if (unlikely(p->des01.rx.error_summary)) {
  87                if (unlikely(p->des01.rx.descriptor_error))
  88                        x->rx_desc++;
  89                if (unlikely(p->des01.rx.sa_filter_fail))
  90                        x->sa_filter_fail++;
  91                if (unlikely(p->des01.rx.overflow_error))
  92                        x->overflow_error++;
  93                if (unlikely(p->des01.rx.ipc_csum_error))
  94                        x->ipc_csum_error++;
  95                if (unlikely(p->des01.rx.collision)) {
  96                        x->rx_collision++;
  97                        stats->collisions++;
  98                }
  99                if (unlikely(p->des01.rx.crc_error)) {
 100                        x->rx_crc++;
 101                        stats->rx_crc_errors++;
 102                }
 103                ret = discard_frame;
 104        }
 105        if (unlikely(p->des01.rx.dribbling))
 106                x->dribbling_bit++;
 107
 108        if (unlikely(p->des01.rx.length_error)) {
 109                x->rx_length++;
 110                ret = discard_frame;
 111        }
 112        if (unlikely(p->des01.rx.mii_error)) {
 113                x->rx_mii++;
 114                ret = discard_frame;
 115        }
 116#ifdef STMMAC_VLAN_TAG_USED
 117        if (p->des01.rx.vlan_tag)
 118                x->vlan_tag++;
 119#endif
 120        return ret;
 121}
 122
 123static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
 124                               int end)
 125{
 126        p->des01.rx.own = 1;
 127        p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
 128
 129        if (mode == STMMAC_CHAIN_MODE)
 130                ndesc_rx_set_on_chain(p, end);
 131        else
 132                ndesc_rx_set_on_ring(p, end);
 133
 134        if (disable_rx_ic)
 135                p->des01.rx.disable_ic = 1;
 136}
 137
 138static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
 139{
 140        p->des01.tx.own = 0;
 141        if (mode == STMMAC_CHAIN_MODE)
 142                ndesc_tx_set_on_chain(p, end);
 143        else
 144                ndesc_tx_set_on_ring(p, end);
 145}
 146
 147static int ndesc_get_tx_owner(struct dma_desc *p)
 148{
 149        return p->des01.tx.own;
 150}
 151
 152static int ndesc_get_rx_owner(struct dma_desc *p)
 153{
 154        return p->des01.rx.own;
 155}
 156
 157static void ndesc_set_tx_owner(struct dma_desc *p)
 158{
 159        p->des01.tx.own = 1;
 160}
 161
 162static void ndesc_set_rx_owner(struct dma_desc *p)
 163{
 164        p->des01.rx.own = 1;
 165}
 166
 167static int ndesc_get_tx_ls(struct dma_desc *p)
 168{
 169        return p->des01.tx.last_segment;
 170}
 171
 172static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
 173{
 174        int ter = p->des01.tx.end_ring;
 175
 176        memset(p, 0, offsetof(struct dma_desc, des2));
 177        if (mode == STMMAC_CHAIN_MODE)
 178                ndesc_end_tx_desc_on_chain(p, ter);
 179        else
 180                ndesc_end_tx_desc_on_ring(p, ter);
 181}
 182
 183static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
 184                                  int csum_flag, int mode)
 185{
 186        p->des01.tx.first_segment = is_fs;
 187        if (mode == STMMAC_CHAIN_MODE)
 188                norm_set_tx_desc_len_on_chain(p, len);
 189        else
 190                norm_set_tx_desc_len_on_ring(p, len);
 191
 192        if (likely(csum_flag))
 193                p->des01.tx.checksum_insertion = cic_full;
 194}
 195
 196static void ndesc_clear_tx_ic(struct dma_desc *p)
 197{
 198        p->des01.tx.interrupt = 0;
 199}
 200
 201static void ndesc_close_tx_desc(struct dma_desc *p)
 202{
 203        p->des01.tx.last_segment = 1;
 204        p->des01.tx.interrupt = 1;
 205}
 206
 207static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
 208{
 209        /* The type-1 checksum offload engines append the checksum at
 210         * the end of frame and the two bytes of checksum are added in
 211         * the length.
 212         * Adjust for that in the framelen for type-1 checksum offload
 213         * engines. */
 214        if (rx_coe_type == STMMAC_RX_COE_TYPE1)
 215                return p->des01.rx.frame_length - 2;
 216        else
 217                return p->des01.rx.frame_length;
 218}
 219
 220static void ndesc_enable_tx_timestamp(struct dma_desc *p)
 221{
 222        p->des01.tx.time_stamp_enable = 1;
 223}
 224
 225static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
 226{
 227        return p->des01.tx.time_stamp_status;
 228}
 229
 230static u64 ndesc_get_timestamp(void *desc, u32 ats)
 231{
 232        struct dma_desc *p = (struct dma_desc *)desc;
 233        u64 ns;
 234
 235        ns = p->des2;
 236        /* convert high/sec time stamp value to nanosecond */
 237        ns += p->des3 * 1000000000ULL;
 238
 239        return ns;
 240}
 241
 242static int ndesc_get_rx_timestamp_status(void *desc, u32 ats)
 243{
 244        struct dma_desc *p = (struct dma_desc *)desc;
 245
 246        if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
 247                /* timestamp is corrupted, hence don't store it */
 248                return 0;
 249        else
 250                return 1;
 251}
 252
 253const struct stmmac_desc_ops ndesc_ops = {
 254        .tx_status = ndesc_get_tx_status,
 255        .rx_status = ndesc_get_rx_status,
 256        .get_tx_len = ndesc_get_tx_len,
 257        .init_rx_desc = ndesc_init_rx_desc,
 258        .init_tx_desc = ndesc_init_tx_desc,
 259        .get_tx_owner = ndesc_get_tx_owner,
 260        .get_rx_owner = ndesc_get_rx_owner,
 261        .release_tx_desc = ndesc_release_tx_desc,
 262        .prepare_tx_desc = ndesc_prepare_tx_desc,
 263        .clear_tx_ic = ndesc_clear_tx_ic,
 264        .close_tx_desc = ndesc_close_tx_desc,
 265        .get_tx_ls = ndesc_get_tx_ls,
 266        .set_tx_owner = ndesc_set_tx_owner,
 267        .set_rx_owner = ndesc_set_rx_owner,
 268        .get_rx_frame_len = ndesc_get_rx_frame_len,
 269        .enable_tx_timestamp = ndesc_enable_tx_timestamp,
 270        .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
 271        .get_timestamp = ndesc_get_timestamp,
 272        .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
 273};
 274