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