xref: /openbmc/linux/drivers/net/ethernet/stmicro/stmmac/chain_mode.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
14fa9c49fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2286a8372SGiuseppe CAVALLARO /*******************************************************************************
3286a8372SGiuseppe CAVALLARO   Specialised functions for managing Chained mode
4286a8372SGiuseppe CAVALLARO 
5286a8372SGiuseppe CAVALLARO   Copyright(C) 2011  STMicroelectronics Ltd
6286a8372SGiuseppe CAVALLARO 
7286a8372SGiuseppe CAVALLARO   It defines all the functions used to handle the normal/enhanced
8286a8372SGiuseppe CAVALLARO   descriptors in case of the DMA is configured to work in chained or
9286a8372SGiuseppe CAVALLARO   in ring mode.
10286a8372SGiuseppe CAVALLARO 
11286a8372SGiuseppe CAVALLARO 
12286a8372SGiuseppe CAVALLARO   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
13286a8372SGiuseppe CAVALLARO *******************************************************************************/
14286a8372SGiuseppe CAVALLARO 
15286a8372SGiuseppe CAVALLARO #include "stmmac.h"
16286a8372SGiuseppe CAVALLARO 
jumbo_frm(struct stmmac_tx_queue * tx_q,struct sk_buff * skb,int csum)17*0c3f3c4fSAndrew Halaney static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb,
18*0c3f3c4fSAndrew Halaney 		     int csum)
19286a8372SGiuseppe CAVALLARO {
20286a8372SGiuseppe CAVALLARO 	unsigned int nopaged_len = skb_headlen(skb);
21ce736788SJoao Pinto 	struct stmmac_priv *priv = tx_q->priv_data;
22ce736788SJoao Pinto 	unsigned int entry = tx_q->cur_tx;
23f8be0d78SMichael Weiser 	unsigned int bmax, des2;
24286a8372SGiuseppe CAVALLARO 	unsigned int i = 1, len;
25ce736788SJoao Pinto 	struct dma_desc *desc;
26ce736788SJoao Pinto 
27ce736788SJoao Pinto 	desc = tx_q->dma_tx + entry;
28286a8372SGiuseppe CAVALLARO 
29286a8372SGiuseppe CAVALLARO 	if (priv->plat->enh_desc)
30286a8372SGiuseppe CAVALLARO 		bmax = BUF_SIZE_8KiB;
31286a8372SGiuseppe CAVALLARO 	else
32286a8372SGiuseppe CAVALLARO 		bmax = BUF_SIZE_2KiB;
33286a8372SGiuseppe CAVALLARO 
34286a8372SGiuseppe CAVALLARO 	len = nopaged_len - bmax;
35286a8372SGiuseppe CAVALLARO 
36f8be0d78SMichael Weiser 	des2 = dma_map_single(priv->device, skb->data,
37286a8372SGiuseppe CAVALLARO 			      bmax, DMA_TO_DEVICE);
38f8be0d78SMichael Weiser 	desc->des2 = cpu_to_le32(des2);
39f8be0d78SMichael Weiser 	if (dma_mapping_error(priv->device, des2))
40362b37beSGiuseppe CAVALLARO 		return -1;
41ce736788SJoao Pinto 	tx_q->tx_skbuff_dma[entry].buf = des2;
42ce736788SJoao Pinto 	tx_q->tx_skbuff_dma[entry].len = bmax;
43be434d50SGiuseppe Cavallaro 	/* do not close the descriptor and do not set own bit */
4442de047dSJose Abreu 	stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, STMMAC_CHAIN_MODE,
45fe6af0e1SNiklas Cassel 			0, false, skb->len);
46286a8372SGiuseppe CAVALLARO 
47286a8372SGiuseppe CAVALLARO 	while (len != 0) {
48ce736788SJoao Pinto 		tx_q->tx_skbuff[entry] = NULL;
498531c808SChristian Marangi 		entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size);
50ce736788SJoao Pinto 		desc = tx_q->dma_tx + entry;
51286a8372SGiuseppe CAVALLARO 
52286a8372SGiuseppe CAVALLARO 		if (len > bmax) {
53f8be0d78SMichael Weiser 			des2 = dma_map_single(priv->device,
54286a8372SGiuseppe CAVALLARO 					      (skb->data + bmax * i),
55286a8372SGiuseppe CAVALLARO 					      bmax, DMA_TO_DEVICE);
56f8be0d78SMichael Weiser 			desc->des2 = cpu_to_le32(des2);
57f8be0d78SMichael Weiser 			if (dma_mapping_error(priv->device, des2))
58362b37beSGiuseppe CAVALLARO 				return -1;
59ce736788SJoao Pinto 			tx_q->tx_skbuff_dma[entry].buf = des2;
60ce736788SJoao Pinto 			tx_q->tx_skbuff_dma[entry].len = bmax;
6142de047dSJose Abreu 			stmmac_prepare_tx_desc(priv, desc, 0, bmax, csum,
6242de047dSJose Abreu 					STMMAC_CHAIN_MODE, 1, false, skb->len);
63286a8372SGiuseppe CAVALLARO 			len -= bmax;
64286a8372SGiuseppe CAVALLARO 			i++;
65286a8372SGiuseppe CAVALLARO 		} else {
66f8be0d78SMichael Weiser 			des2 = dma_map_single(priv->device,
67286a8372SGiuseppe CAVALLARO 					      (skb->data + bmax * i), len,
68286a8372SGiuseppe CAVALLARO 					      DMA_TO_DEVICE);
69f8be0d78SMichael Weiser 			desc->des2 = cpu_to_le32(des2);
70f8be0d78SMichael Weiser 			if (dma_mapping_error(priv->device, des2))
71362b37beSGiuseppe CAVALLARO 				return -1;
72ce736788SJoao Pinto 			tx_q->tx_skbuff_dma[entry].buf = des2;
73ce736788SJoao Pinto 			tx_q->tx_skbuff_dma[entry].len = len;
74be434d50SGiuseppe Cavallaro 			/* last descriptor can be set now */
7542de047dSJose Abreu 			stmmac_prepare_tx_desc(priv, desc, 0, len, csum,
7642de047dSJose Abreu 					STMMAC_CHAIN_MODE, 1, true, skb->len);
77286a8372SGiuseppe CAVALLARO 			len = 0;
78286a8372SGiuseppe CAVALLARO 		}
79286a8372SGiuseppe CAVALLARO 	}
80e3ad57c9SGiuseppe Cavallaro 
81ce736788SJoao Pinto 	tx_q->cur_tx = entry;
82e3ad57c9SGiuseppe Cavallaro 
83286a8372SGiuseppe CAVALLARO 	return entry;
84286a8372SGiuseppe CAVALLARO }
85286a8372SGiuseppe CAVALLARO 
is_jumbo_frm(int len,int enh_desc)862c520b1cSJose Abreu static unsigned int is_jumbo_frm(int len, int enh_desc)
87286a8372SGiuseppe CAVALLARO {
88286a8372SGiuseppe CAVALLARO 	unsigned int ret = 0;
89286a8372SGiuseppe CAVALLARO 
90286a8372SGiuseppe CAVALLARO 	if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
91286a8372SGiuseppe CAVALLARO 	    (!enh_desc && (len > BUF_SIZE_2KiB))) {
92286a8372SGiuseppe CAVALLARO 		ret = 1;
93286a8372SGiuseppe CAVALLARO 	}
94286a8372SGiuseppe CAVALLARO 
95286a8372SGiuseppe CAVALLARO 	return ret;
96286a8372SGiuseppe CAVALLARO }
97286a8372SGiuseppe CAVALLARO 
init_dma_chain(void * des,dma_addr_t phy_addr,unsigned int size,unsigned int extend_desc)982c520b1cSJose Abreu static void init_dma_chain(void *des, dma_addr_t phy_addr,
99c24602efSGiuseppe CAVALLARO 				  unsigned int size, unsigned int extend_desc)
100286a8372SGiuseppe CAVALLARO {
101286a8372SGiuseppe CAVALLARO 	/*
102286a8372SGiuseppe CAVALLARO 	 * In chained mode the des3 points to the next element in the ring.
103286a8372SGiuseppe CAVALLARO 	 * The latest element has to point to the head.
104286a8372SGiuseppe CAVALLARO 	 */
105286a8372SGiuseppe CAVALLARO 	int i;
106286a8372SGiuseppe CAVALLARO 	dma_addr_t dma_phy = phy_addr;
107286a8372SGiuseppe CAVALLARO 
108c24602efSGiuseppe CAVALLARO 	if (extend_desc) {
109c24602efSGiuseppe CAVALLARO 		struct dma_extended_desc *p = (struct dma_extended_desc *)des;
110c24602efSGiuseppe CAVALLARO 		for (i = 0; i < (size - 1); i++) {
111c24602efSGiuseppe CAVALLARO 			dma_phy += sizeof(struct dma_extended_desc);
112f8be0d78SMichael Weiser 			p->basic.des3 = cpu_to_le32((unsigned int)dma_phy);
113c24602efSGiuseppe CAVALLARO 			p++;
114c24602efSGiuseppe CAVALLARO 		}
115f8be0d78SMichael Weiser 		p->basic.des3 = cpu_to_le32((unsigned int)phy_addr);
116c24602efSGiuseppe CAVALLARO 
117c24602efSGiuseppe CAVALLARO 	} else {
118c24602efSGiuseppe CAVALLARO 		struct dma_desc *p = (struct dma_desc *)des;
119286a8372SGiuseppe CAVALLARO 		for (i = 0; i < (size - 1); i++) {
120286a8372SGiuseppe CAVALLARO 			dma_phy += sizeof(struct dma_desc);
121f8be0d78SMichael Weiser 			p->des3 = cpu_to_le32((unsigned int)dma_phy);
122286a8372SGiuseppe CAVALLARO 			p++;
123286a8372SGiuseppe CAVALLARO 		}
124f8be0d78SMichael Weiser 		p->des3 = cpu_to_le32((unsigned int)phy_addr);
125286a8372SGiuseppe CAVALLARO 	}
126c24602efSGiuseppe CAVALLARO }
127286a8372SGiuseppe CAVALLARO 
refill_desc3(struct stmmac_rx_queue * rx_q,struct dma_desc * p)128*0c3f3c4fSAndrew Halaney static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p)
129891434b1SRayagond Kokatanur {
13054139cf3SJoao Pinto 	struct stmmac_priv *priv = rx_q->priv_data;
131891434b1SRayagond Kokatanur 
132891434b1SRayagond Kokatanur 	if (priv->hwts_rx_en && !priv->extend_desc)
133891434b1SRayagond Kokatanur 		/* NOTE: Device will overwrite des3 with timestamp value if
134891434b1SRayagond Kokatanur 		 * 1588-2002 time stamping is enabled, hence reinitialize it
135891434b1SRayagond Kokatanur 		 * to keep explicit chaining in the descriptor.
136891434b1SRayagond Kokatanur 		 */
13754139cf3SJoao Pinto 		p->des3 = cpu_to_le32((unsigned int)(rx_q->dma_rx_phy +
13854139cf3SJoao Pinto 				      (((rx_q->dirty_rx) + 1) %
1398531c808SChristian Marangi 				       priv->dma_conf.dma_rx_size) *
140f8be0d78SMichael Weiser 				      sizeof(struct dma_desc)));
141891434b1SRayagond Kokatanur }
142891434b1SRayagond Kokatanur 
clean_desc3(struct stmmac_tx_queue * tx_q,struct dma_desc * p)143*0c3f3c4fSAndrew Halaney static void clean_desc3(struct stmmac_tx_queue *tx_q, struct dma_desc *p)
144891434b1SRayagond Kokatanur {
145ce736788SJoao Pinto 	struct stmmac_priv *priv = tx_q->priv_data;
146ce736788SJoao Pinto 	unsigned int entry = tx_q->dirty_tx;
147891434b1SRayagond Kokatanur 
148ce736788SJoao Pinto 	if (tx_q->tx_skbuff_dma[entry].last_segment && !priv->extend_desc &&
14996951366SGiuseppe Cavallaro 	    priv->hwts_tx_en)
150891434b1SRayagond Kokatanur 		/* NOTE: Device will overwrite des3 with timestamp value if
151891434b1SRayagond Kokatanur 		 * 1588-2002 time stamping is enabled, hence reinitialize it
152891434b1SRayagond Kokatanur 		 * to keep explicit chaining in the descriptor.
153891434b1SRayagond Kokatanur 		 */
154ce736788SJoao Pinto 		p->des3 = cpu_to_le32((unsigned int)((tx_q->dma_tx_phy +
155aa042f60SSong, Yoong Siang 				      ((tx_q->dirty_tx + 1) %
1568531c808SChristian Marangi 				       priv->dma_conf.dma_tx_size))
157f8be0d78SMichael Weiser 				      * sizeof(struct dma_desc)));
158891434b1SRayagond Kokatanur }
159891434b1SRayagond Kokatanur 
16029896a67SGiuseppe CAVALLARO const struct stmmac_mode_ops chain_mode_ops = {
1612c520b1cSJose Abreu 	.init = init_dma_chain,
1622c520b1cSJose Abreu 	.is_jumbo_frm = is_jumbo_frm,
1632c520b1cSJose Abreu 	.jumbo_frm = jumbo_frm,
1642c520b1cSJose Abreu 	.refill_desc3 = refill_desc3,
1652c520b1cSJose Abreu 	.clean_desc3 = clean_desc3,
166286a8372SGiuseppe CAVALLARO };
167