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 "common.h" 26 27static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, 28 struct dma_desc *p, unsigned long ioaddr) 29{ 30 int ret = 0; 31 struct net_device_stats *stats = (struct net_device_stats *)data; 32 33 if (unlikely(p->des01.tx.error_summary)) { 34 if (unlikely(p->des01.tx.underflow_error)) { 35 x->tx_underflow++; 36 stats->tx_fifo_errors++; 37 } 38 if (unlikely(p->des01.tx.no_carrier)) { 39 x->tx_carrier++; 40 stats->tx_carrier_errors++; 41 } 42 if (unlikely(p->des01.tx.loss_carrier)) { 43 x->tx_losscarrier++; 44 stats->tx_carrier_errors++; 45 } 46 if (unlikely((p->des01.tx.excessive_deferral) || 47 (p->des01.tx.excessive_collisions) || 48 (p->des01.tx.late_collision))) 49 stats->collisions += p->des01.tx.collision_count; 50 ret = -1; 51 } 52 if (unlikely(p->des01.tx.heartbeat_fail)) { 53 x->tx_heartbeat++; 54 stats->tx_heartbeat_errors++; 55 ret = -1; 56 } 57 if (unlikely(p->des01.tx.deferred)) 58 x->tx_deferred++; 59 60 return ret; 61} 62 63static int ndesc_get_tx_len(struct dma_desc *p) 64{ 65 return p->des01.tx.buffer1_size; 66} 67 68/* This function verifies if each incoming frame has some errors 69 * and, if required, updates the multicast statistics. 70 * In case of success, it returns csum_none becasue the device 71 * is not able to compute the csum in HW. */ 72static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, 73 struct dma_desc *p) 74{ 75 int ret = csum_none; 76 struct net_device_stats *stats = (struct net_device_stats *)data; 77 78 if (unlikely(p->des01.rx.last_descriptor == 0)) { 79 pr_warning("ndesc Error: Oversized Ethernet " 80 "frame spanned multiple buffers\n"); 81 stats->rx_length_errors++; 82 return discard_frame; 83 } 84 85 if (unlikely(p->des01.rx.error_summary)) { 86 if (unlikely(p->des01.rx.descriptor_error)) 87 x->rx_desc++; 88 if (unlikely(p->des01.rx.partial_frame_error)) 89 x->rx_partial++; 90 if (unlikely(p->des01.rx.run_frame)) 91 x->rx_runt++; 92 if (unlikely(p->des01.rx.frame_too_long)) 93 x->rx_toolong++; 94 if (unlikely(p->des01.rx.collision)) { 95 x->rx_collision++; 96 stats->collisions++; 97 } 98 if (unlikely(p->des01.rx.crc_error)) { 99 x->rx_crc++; 100 stats->rx_crc_errors++; 101 } 102 ret = discard_frame; 103 } 104 if (unlikely(p->des01.rx.dribbling)) 105 ret = discard_frame; 106 107 if (unlikely(p->des01.rx.length_error)) { 108 x->rx_length++; 109 ret = discard_frame; 110 } 111 if (unlikely(p->des01.rx.mii_error)) { 112 x->rx_mii++; 113 ret = discard_frame; 114 } 115 if (p->des01.rx.multicast_frame) { 116 x->rx_multicast++; 117 stats->multicast++; 118 } 119 return ret; 120} 121 122static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size, 123 int disable_rx_ic) 124{ 125 int i; 126 for (i = 0; i < ring_size; i++) { 127 p->des01.rx.own = 1; 128 p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1; 129 if (i == ring_size - 1) 130 p->des01.rx.end_ring = 1; 131 if (disable_rx_ic) 132 p->des01.rx.disable_ic = 1; 133 p++; 134 } 135} 136 137static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size) 138{ 139 int i; 140 for (i = 0; i < ring_size; i++) { 141 p->des01.tx.own = 0; 142 if (i == ring_size - 1) 143 p->des01.tx.end_ring = 1; 144 p++; 145 } 146} 147 148static int ndesc_get_tx_owner(struct dma_desc *p) 149{ 150 return p->des01.tx.own; 151} 152 153static int ndesc_get_rx_owner(struct dma_desc *p) 154{ 155 return p->des01.rx.own; 156} 157 158static void ndesc_set_tx_owner(struct dma_desc *p) 159{ 160 p->des01.tx.own = 1; 161} 162 163static void ndesc_set_rx_owner(struct dma_desc *p) 164{ 165 p->des01.rx.own = 1; 166} 167 168static int ndesc_get_tx_ls(struct dma_desc *p) 169{ 170 return p->des01.tx.last_segment; 171} 172 173static void ndesc_release_tx_desc(struct dma_desc *p) 174{ 175 int ter = p->des01.tx.end_ring; 176 177 /* clean field used within the xmit */ 178 p->des01.tx.first_segment = 0; 179 p->des01.tx.last_segment = 0; 180 p->des01.tx.buffer1_size = 0; 181 182 /* clean status reported */ 183 p->des01.tx.error_summary = 0; 184 p->des01.tx.underflow_error = 0; 185 p->des01.tx.no_carrier = 0; 186 p->des01.tx.loss_carrier = 0; 187 p->des01.tx.excessive_deferral = 0; 188 p->des01.tx.excessive_collisions = 0; 189 p->des01.tx.late_collision = 0; 190 p->des01.tx.heartbeat_fail = 0; 191 p->des01.tx.deferred = 0; 192 193 /* set termination field */ 194 p->des01.tx.end_ring = ter; 195} 196 197static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, 198 int csum_flag) 199{ 200 p->des01.tx.first_segment = is_fs; 201 p->des01.tx.buffer1_size = len; 202} 203 204static void ndesc_clear_tx_ic(struct dma_desc *p) 205{ 206 p->des01.tx.interrupt = 0; 207} 208 209static void ndesc_close_tx_desc(struct dma_desc *p) 210{ 211 p->des01.tx.last_segment = 1; 212 p->des01.tx.interrupt = 1; 213} 214 215static int ndesc_get_rx_frame_len(struct dma_desc *p) 216{ 217 return p->des01.rx.frame_length; 218} 219 220struct stmmac_desc_ops ndesc_ops = { 221 .tx_status = ndesc_get_tx_status, 222 .rx_status = ndesc_get_rx_status, 223 .get_tx_len = ndesc_get_tx_len, 224 .init_rx_desc = ndesc_init_rx_desc, 225 .init_tx_desc = ndesc_init_tx_desc, 226 .get_tx_owner = ndesc_get_tx_owner, 227 .get_rx_owner = ndesc_get_rx_owner, 228 .release_tx_desc = ndesc_release_tx_desc, 229 .prepare_tx_desc = ndesc_prepare_tx_desc, 230 .clear_tx_ic = ndesc_clear_tx_ic, 231 .close_tx_desc = ndesc_close_tx_desc, 232 .get_tx_ls = ndesc_get_tx_ls, 233 .set_tx_owner = ndesc_set_tx_owner, 234 .set_rx_owner = ndesc_set_rx_owner, 235 .get_rx_frame_len = ndesc_get_rx_frame_len, 236}; 237