Giuseppe CAVALLARO | 56b106a | 2010-04-13 20:21:12 +0000 | [diff] [blame] | 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 | |
| 27 | static 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 | |
| 63 | static 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. */ |
| 72 | static 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 | |
| 122 | static 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 | } |
Giuseppe CAVALLARO | 56b106a | 2010-04-13 20:21:12 +0000 | [diff] [blame] | 135 | } |
| 136 | |
| 137 | static 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 | } |
Giuseppe CAVALLARO | 56b106a | 2010-04-13 20:21:12 +0000 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | static int ndesc_get_tx_owner(struct dma_desc *p) |
| 149 | { |
| 150 | return p->des01.tx.own; |
| 151 | } |
| 152 | |
| 153 | static int ndesc_get_rx_owner(struct dma_desc *p) |
| 154 | { |
| 155 | return p->des01.rx.own; |
| 156 | } |
| 157 | |
| 158 | static void ndesc_set_tx_owner(struct dma_desc *p) |
| 159 | { |
| 160 | p->des01.tx.own = 1; |
| 161 | } |
| 162 | |
| 163 | static void ndesc_set_rx_owner(struct dma_desc *p) |
| 164 | { |
| 165 | p->des01.rx.own = 1; |
| 166 | } |
| 167 | |
| 168 | static int ndesc_get_tx_ls(struct dma_desc *p) |
| 169 | { |
| 170 | return p->des01.tx.last_segment; |
| 171 | } |
| 172 | |
| 173 | static 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; |
Giuseppe CAVALLARO | 56b106a | 2010-04-13 20:21:12 +0000 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | static 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 | |
| 204 | static void ndesc_clear_tx_ic(struct dma_desc *p) |
| 205 | { |
| 206 | p->des01.tx.interrupt = 0; |
| 207 | } |
| 208 | |
| 209 | static 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 | |
| 215 | static int ndesc_get_rx_frame_len(struct dma_desc *p) |
| 216 | { |
| 217 | return p->des01.rx.frame_length; |
| 218 | } |
| 219 | |
| 220 | struct 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 | }; |