]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/stmicro/stmmac/norm_desc.c
Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / stmicro / stmmac / norm_desc.c
CommitLineData
56b106ae
GC
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
56b106ae
GC
15 The full GNU General Public License is included in this distribution in
16 the file called "COPYING".
17
18 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
19*******************************************************************************/
20
38912bdb 21#include <linux/stmmac.h>
56b106ae 22#include "common.h"
286a8372 23#include "descs_com.h"
56b106ae
GC
24
25static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
ad01b7d4 26 struct dma_desc *p, void __iomem *ioaddr)
56b106ae 27{
56b106ae 28 struct net_device_stats *stats = (struct net_device_stats *)data;
f8be0d78
MW
29 unsigned int tdes0 = le32_to_cpu(p->des0);
30 unsigned int tdes1 = le32_to_cpu(p->des1);
c363b658
FG
31 int ret = tx_done;
32
33 /* Get tx owner first */
34 if (unlikely(tdes0 & TDES0_OWN))
35 return tx_dma_own;
36
37 /* Verify tx error by looking at the last segment. */
38 if (likely(!(tdes1 & TDES1_LAST_SEGMENT)))
39 return tx_not_ls;
56b106ae 40
293e4365
GC
41 if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
42 if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
56b106ae
GC
43 x->tx_underflow++;
44 stats->tx_fifo_errors++;
45 }
293e4365 46 if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
56b106ae
GC
47 x->tx_carrier++;
48 stats->tx_carrier_errors++;
49 }
293e4365 50 if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
56b106ae
GC
51 x->tx_losscarrier++;
52 stats->tx_carrier_errors++;
53 }
293e4365
GC
54 if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
55 (tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
56 (tdes0 & TDES0_LATE_COLLISION))) {
57 unsigned int collisions;
58
59 collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
60 stats->collisions += collisions;
61 }
c363b658 62 ret = tx_err;
56b106ae 63 }
3c20f72f 64
293e4365 65 if (tdes0 & TDES0_VLAN_FRAME)
3c20f72f 66 x->tx_vlan++;
3c20f72f 67
293e4365 68 if (unlikely(tdes0 & TDES0_DEFERRED))
56b106ae
GC
69 x->tx_deferred++;
70
71 return ret;
72}
73
74static int ndesc_get_tx_len(struct dma_desc *p)
75{
f8be0d78 76 return (le32_to_cpu(p->des1) & RDES1_BUFFER1_SIZE_MASK);
56b106ae
GC
77}
78
79/* This function verifies if each incoming frame has some errors
80 * and, if required, updates the multicast statistics.
3c20f72f
GC
81 * In case of success, it returns good_frame because the GMAC device
82 * is supposed to be able to compute the csum in HW. */
56b106ae
GC
83static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
84 struct dma_desc *p)
85{
3c20f72f 86 int ret = good_frame;
f8be0d78 87 unsigned int rdes0 = le32_to_cpu(p->des0);
56b106ae
GC
88 struct net_device_stats *stats = (struct net_device_stats *)data;
89
c1fa3212
FG
90 if (unlikely(rdes0 & RDES0_OWN))
91 return dma_own;
92
293e4365 93 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
ceb69499
GC
94 pr_warn("%s: Oversized frame spanned multiple buffers\n",
95 __func__);
56b106ae
GC
96 stats->rx_length_errors++;
97 return discard_frame;
98 }
99
293e4365
GC
100 if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
101 if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR))
56b106ae 102 x->rx_desc++;
293e4365 103 if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
3c20f72f 104 x->sa_filter_fail++;
293e4365 105 if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
3c20f72f 106 x->overflow_error++;
293e4365 107 if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
3c20f72f 108 x->ipc_csum_error++;
293e4365 109 if (unlikely(rdes0 & RDES0_COLLISION)) {
56b106ae
GC
110 x->rx_collision++;
111 stats->collisions++;
112 }
293e4365 113 if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
e0a76606 114 x->rx_crc_errors++;
56b106ae
GC
115 stats->rx_crc_errors++;
116 }
117 ret = discard_frame;
118 }
293e4365 119 if (unlikely(rdes0 & RDES0_DRIBBLING))
1cc5a735 120 x->dribbling_bit++;
56b106ae 121
293e4365 122 if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
56b106ae
GC
123 x->rx_length++;
124 ret = discard_frame;
125 }
293e4365 126 if (unlikely(rdes0 & RDES0_MII_ERROR)) {
56b106ae
GC
127 x->rx_mii++;
128 ret = discard_frame;
129 }
3c20f72f 130#ifdef STMMAC_VLAN_TAG_USED
293e4365 131 if (rdes0 & RDES0_VLAN_TAG)
3c20f72f
GC
132 x->vlan_tag++;
133#endif
56b106ae
GC
134 return ret;
135}
136
c24602ef
GC
137static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
138 int end)
56b106ae 139{
f8be0d78
MW
140 p->des0 |= cpu_to_le32(RDES0_OWN);
141 p->des1 |= cpu_to_le32((BUF_SIZE_2KiB - 1) & RDES1_BUFFER1_SIZE_MASK);
c24602ef
GC
142
143 if (mode == STMMAC_CHAIN_MODE)
144 ndesc_rx_set_on_chain(p, end);
145 else
146 ndesc_rx_set_on_ring(p, end);
147
148 if (disable_rx_ic)
f8be0d78 149 p->des1 |= cpu_to_le32(RDES1_DISABLE_IC);
56b106ae
GC
150}
151
c24602ef 152static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
56b106ae 153{
f8be0d78 154 p->des0 &= cpu_to_le32(~TDES0_OWN);
c24602ef 155 if (mode == STMMAC_CHAIN_MODE)
293e4365 156 ndesc_tx_set_on_chain(p);
c24602ef 157 else
293e4365 158 ndesc_end_tx_desc_on_ring(p, end);
56b106ae
GC
159}
160
161static int ndesc_get_tx_owner(struct dma_desc *p)
162{
f8be0d78 163 return (le32_to_cpu(p->des0) & TDES0_OWN) >> 31;
56b106ae
GC
164}
165
56b106ae
GC
166static void ndesc_set_tx_owner(struct dma_desc *p)
167{
f8be0d78 168 p->des0 |= cpu_to_le32(TDES0_OWN);
56b106ae
GC
169}
170
171static void ndesc_set_rx_owner(struct dma_desc *p)
172{
f8be0d78 173 p->des0 |= cpu_to_le32(RDES0_OWN);
56b106ae
GC
174}
175
176static int ndesc_get_tx_ls(struct dma_desc *p)
177{
f8be0d78 178 return (le32_to_cpu(p->des1) & TDES1_LAST_SEGMENT) >> 30;
56b106ae
GC
179}
180
4a7d666a 181static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
56b106ae 182{
f8be0d78 183 int ter = (le32_to_cpu(p->des1) & TDES1_END_RING) >> 25;
56b106ae 184
b71c7aaa 185 memset(p, 0, offsetof(struct dma_desc, des2));
4a7d666a 186 if (mode == STMMAC_CHAIN_MODE)
293e4365 187 ndesc_tx_set_on_chain(p);
4a7d666a
GC
188 else
189 ndesc_end_tx_desc_on_ring(p, ter);
56b106ae
GC
190}
191
192static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
be434d50 193 bool csum_flag, int mode, bool tx_own,
fe6af0e1 194 bool ls, unsigned int tot_pkt_len)
56b106ae 195{
f8be0d78 196 unsigned int tdes1 = le32_to_cpu(p->des1);
293e4365
GC
197
198 if (is_fs)
199 tdes1 |= TDES1_FIRST_SEGMENT;
200 else
201 tdes1 &= ~TDES1_FIRST_SEGMENT;
202
203 if (likely(csum_flag))
204 tdes1 |= (TX_CIC_FULL) << TDES1_CHECKSUM_INSERTION_SHIFT;
205 else
206 tdes1 &= ~(TX_CIC_FULL << TDES1_CHECKSUM_INSERTION_SHIFT);
207
0e80bdc9
GC
208 if (ls)
209 tdes1 |= TDES1_LAST_SEGMENT;
210
f8be0d78 211 p->des1 = cpu_to_le32(tdes1);
a00e3ab6
GC
212
213 if (mode == STMMAC_CHAIN_MODE)
214 norm_set_tx_desc_len_on_chain(p, len);
215 else
216 norm_set_tx_desc_len_on_ring(p, len);
217
218 if (tx_own)
f8be0d78 219 p->des0 |= cpu_to_le32(TDES0_OWN);
56b106ae
GC
220}
221
0e80bdc9 222static void ndesc_set_tx_ic(struct dma_desc *p)
56b106ae 223{
f8be0d78 224 p->des1 |= cpu_to_le32(TDES1_INTERRUPT);
56b106ae
GC
225}
226
38912bdb 227static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
56b106ae 228{
293e4365
GC
229 unsigned int csum = 0;
230
38912bdb
DS
231 /* The type-1 checksum offload engines append the checksum at
232 * the end of frame and the two bytes of checksum are added in
233 * the length.
234 * Adjust for that in the framelen for type-1 checksum offload
293e4365
GC
235 * engines
236 */
38912bdb 237 if (rx_coe_type == STMMAC_RX_COE_TYPE1)
293e4365
GC
238 csum = 2;
239
f8be0d78
MW
240 return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
241 >> RDES0_FRAME_LEN_SHIFT) -
293e4365
GC
242 csum);
243
56b106ae
GC
244}
245
891434b1
RK
246static void ndesc_enable_tx_timestamp(struct dma_desc *p)
247{
f8be0d78 248 p->des1 |= cpu_to_le32(TDES1_TIME_STAMP_ENABLE);
891434b1
RK
249}
250
251static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
252{
f8be0d78 253 return (le32_to_cpu(p->des0) & TDES0_TIME_STAMP_STATUS) >> 17;
891434b1
RK
254}
255
256static u64 ndesc_get_timestamp(void *desc, u32 ats)
257{
258 struct dma_desc *p = (struct dma_desc *)desc;
259 u64 ns;
260
f8be0d78 261 ns = le32_to_cpu(p->des2);
891434b1 262 /* convert high/sec time stamp value to nanosecond */
f8be0d78 263 ns += le32_to_cpu(p->des3) * 1000000000ULL;
891434b1
RK
264
265 return ns;
266}
267
a1762456 268static int ndesc_get_rx_timestamp_status(void *desc, void *next_desc, u32 ats)
891434b1
RK
269{
270 struct dma_desc *p = (struct dma_desc *)desc;
271
f8be0d78
MW
272 if ((le32_to_cpu(p->des2) == 0xffffffff) &&
273 (le32_to_cpu(p->des3) == 0xffffffff))
891434b1
RK
274 /* timestamp is corrupted, hence don't store it */
275 return 0;
276 else
277 return 1;
278}
279
d0225e7d
AT
280static void ndesc_display_ring(void *head, unsigned int size, bool rx)
281{
282 struct dma_desc *p = (struct dma_desc *)head;
283 int i;
284
285 pr_info("%s descriptor ring:\n", rx ? "RX" : "TX");
286
287 for (i = 0; i < size; i++) {
288 u64 x;
289
290 x = *(u64 *)p;
291 pr_info("%d [0x%x]: 0x%x 0x%x 0x%x 0x%x",
292 i, (unsigned int)virt_to_phys(p),
293 (unsigned int)x, (unsigned int)(x >> 32),
294 p->des2, p->des3);
295 p++;
296 }
297 pr_info("\n");
298}
299
cadb7924 300const struct stmmac_desc_ops ndesc_ops = {
56b106ae
GC
301 .tx_status = ndesc_get_tx_status,
302 .rx_status = ndesc_get_rx_status,
303 .get_tx_len = ndesc_get_tx_len,
304 .init_rx_desc = ndesc_init_rx_desc,
305 .init_tx_desc = ndesc_init_tx_desc,
306 .get_tx_owner = ndesc_get_tx_owner,
56b106ae
GC
307 .release_tx_desc = ndesc_release_tx_desc,
308 .prepare_tx_desc = ndesc_prepare_tx_desc,
0e80bdc9 309 .set_tx_ic = ndesc_set_tx_ic,
56b106ae
GC
310 .get_tx_ls = ndesc_get_tx_ls,
311 .set_tx_owner = ndesc_set_tx_owner,
312 .set_rx_owner = ndesc_set_rx_owner,
313 .get_rx_frame_len = ndesc_get_rx_frame_len,
891434b1
RK
314 .enable_tx_timestamp = ndesc_enable_tx_timestamp,
315 .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
316 .get_timestamp = ndesc_get_timestamp,
317 .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
d0225e7d 318 .display_ring = ndesc_display_ring,
56b106ae 319};