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