xref: /openbmc/linux/drivers/net/ethernet/stmicro/stmmac/norm_desc.c (revision ce932d0c5589e9766e089c22c66890dfc48fbd94)
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