1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright Sunplus Technology Co., Ltd.
3  *       All rights reserved.
4  */
5 
6 #include <linux/platform_device.h>
7 #include <linux/netdevice.h>
8 #include <linux/of_mdio.h>
9 
10 #include "spl2sw_define.h"
11 #include "spl2sw_desc.h"
12 
13 void spl2sw_rx_descs_flush(struct spl2sw_common *comm)
14 {
15 	struct spl2sw_skb_info *rx_skbinfo;
16 	struct spl2sw_mac_desc *rx_desc;
17 	u32 i, j;
18 
19 	for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
20 		rx_desc = comm->rx_desc[i];
21 		rx_skbinfo = comm->rx_skb_info[i];
22 		for (j = 0; j < comm->rx_desc_num[i]; j++) {
23 			rx_desc[j].addr1 = rx_skbinfo[j].mapping;
24 			rx_desc[j].cmd2 = (j == comm->rx_desc_num[i] - 1) ?
25 					  RXD_EOR | comm->rx_desc_buff_size :
26 					  comm->rx_desc_buff_size;
27 			wmb();	/* Set RXD_OWN after other fields are ready. */
28 			rx_desc[j].cmd1 = RXD_OWN;
29 		}
30 	}
31 }
32 
33 void spl2sw_tx_descs_clean(struct spl2sw_common *comm)
34 {
35 	u32 i;
36 
37 	if (!comm->tx_desc)
38 		return;
39 
40 	for (i = 0; i < TX_DESC_NUM; i++) {
41 		comm->tx_desc[i].cmd1 = 0;
42 		wmb();	/* Clear TXD_OWN and then set other fields. */
43 		comm->tx_desc[i].cmd2 = 0;
44 		comm->tx_desc[i].addr1 = 0;
45 		comm->tx_desc[i].addr2 = 0;
46 
47 		if (comm->tx_temp_skb_info[i].mapping) {
48 			dma_unmap_single(&comm->pdev->dev, comm->tx_temp_skb_info[i].mapping,
49 					 comm->tx_temp_skb_info[i].skb->len, DMA_TO_DEVICE);
50 			comm->tx_temp_skb_info[i].mapping = 0;
51 		}
52 
53 		if (comm->tx_temp_skb_info[i].skb) {
54 			dev_kfree_skb_any(comm->tx_temp_skb_info[i].skb);
55 			comm->tx_temp_skb_info[i].skb = NULL;
56 		}
57 	}
58 }
59 
60 void spl2sw_rx_descs_clean(struct spl2sw_common *comm)
61 {
62 	struct spl2sw_skb_info *rx_skbinfo;
63 	struct spl2sw_mac_desc *rx_desc;
64 	u32 i, j;
65 
66 	for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
67 		if (!comm->rx_skb_info[i])
68 			continue;
69 
70 		rx_desc = comm->rx_desc[i];
71 		rx_skbinfo = comm->rx_skb_info[i];
72 		for (j = 0; j < comm->rx_desc_num[i]; j++) {
73 			rx_desc[j].cmd1 = 0;
74 			wmb();	/* Clear RXD_OWN and then set other fields. */
75 			rx_desc[j].cmd2 = 0;
76 			rx_desc[j].addr1 = 0;
77 
78 			if (rx_skbinfo[j].skb) {
79 				dma_unmap_single(&comm->pdev->dev, rx_skbinfo[j].mapping,
80 						 comm->rx_desc_buff_size, DMA_FROM_DEVICE);
81 				dev_kfree_skb_any(rx_skbinfo[j].skb);
82 				rx_skbinfo[j].skb = NULL;
83 				rx_skbinfo[j].mapping = 0;
84 			}
85 		}
86 
87 		kfree(rx_skbinfo);
88 		comm->rx_skb_info[i] = NULL;
89 	}
90 }
91 
92 void spl2sw_descs_clean(struct spl2sw_common *comm)
93 {
94 	spl2sw_rx_descs_clean(comm);
95 	spl2sw_tx_descs_clean(comm);
96 }
97 
98 void spl2sw_descs_free(struct spl2sw_common *comm)
99 {
100 	u32 i;
101 
102 	spl2sw_descs_clean(comm);
103 	comm->tx_desc = NULL;
104 	for (i = 0; i < RX_DESC_QUEUE_NUM; i++)
105 		comm->rx_desc[i] = NULL;
106 
107 	/*  Free descriptor area  */
108 	if (comm->desc_base) {
109 		dma_free_coherent(&comm->pdev->dev, comm->desc_size, comm->desc_base,
110 				  comm->desc_dma);
111 		comm->desc_base = NULL;
112 		comm->desc_dma = 0;
113 		comm->desc_size = 0;
114 	}
115 }
116 
117 void spl2sw_tx_descs_init(struct spl2sw_common *comm)
118 {
119 	memset(comm->tx_desc, '\0', sizeof(struct spl2sw_mac_desc) *
120 	       (TX_DESC_NUM + MAC_GUARD_DESC_NUM));
121 }
122 
123 int spl2sw_rx_descs_init(struct spl2sw_common *comm)
124 {
125 	struct spl2sw_skb_info *rx_skbinfo;
126 	struct spl2sw_mac_desc *rx_desc;
127 	struct sk_buff *skb;
128 	u32 mapping;
129 	u32 i, j;
130 
131 	for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
132 		comm->rx_skb_info[i] = kcalloc(comm->rx_desc_num[i], sizeof(*rx_skbinfo),
133 					       GFP_KERNEL | GFP_DMA);
134 		if (!comm->rx_skb_info[i])
135 			goto mem_alloc_fail;
136 
137 		rx_skbinfo = comm->rx_skb_info[i];
138 		rx_desc = comm->rx_desc[i];
139 		for (j = 0; j < comm->rx_desc_num[i]; j++) {
140 			skb = netdev_alloc_skb(NULL, comm->rx_desc_buff_size);
141 			if (!skb)
142 				goto mem_alloc_fail;
143 
144 			rx_skbinfo[j].skb = skb;
145 			mapping = dma_map_single(&comm->pdev->dev, skb->data,
146 						 comm->rx_desc_buff_size,
147 						 DMA_FROM_DEVICE);
148 			if (dma_mapping_error(&comm->pdev->dev, mapping))
149 				goto mem_alloc_fail;
150 
151 			rx_skbinfo[j].mapping = mapping;
152 			rx_desc[j].addr1 = mapping;
153 			rx_desc[j].addr2 = 0;
154 			rx_desc[j].cmd2 = (j == comm->rx_desc_num[i] - 1) ?
155 					  RXD_EOR | comm->rx_desc_buff_size :
156 					  comm->rx_desc_buff_size;
157 			wmb();	/* Set RXD_OWN after other fields are effective. */
158 			rx_desc[j].cmd1 = RXD_OWN;
159 		}
160 	}
161 
162 	return 0;
163 
164 mem_alloc_fail:
165 	spl2sw_rx_descs_clean(comm);
166 	return -ENOMEM;
167 }
168 
169 int spl2sw_descs_alloc(struct spl2sw_common *comm)
170 {
171 	s32 desc_size;
172 	u32 i;
173 
174 	/* Alloc descriptor area  */
175 	desc_size = (TX_DESC_NUM + MAC_GUARD_DESC_NUM) * sizeof(struct spl2sw_mac_desc);
176 	for (i = 0; i < RX_DESC_QUEUE_NUM; i++)
177 		desc_size += comm->rx_desc_num[i] * sizeof(struct spl2sw_mac_desc);
178 
179 	comm->desc_base = dma_alloc_coherent(&comm->pdev->dev, desc_size, &comm->desc_dma,
180 					     GFP_KERNEL);
181 	if (!comm->desc_base)
182 		return -ENOMEM;
183 
184 	comm->desc_size = desc_size;
185 
186 	/* Setup Tx descriptor */
187 	comm->tx_desc = comm->desc_base;
188 
189 	/* Setup Rx descriptor */
190 	comm->rx_desc[0] = &comm->tx_desc[TX_DESC_NUM + MAC_GUARD_DESC_NUM];
191 	for (i = 1; i < RX_DESC_QUEUE_NUM; i++)
192 		comm->rx_desc[i] = comm->rx_desc[i - 1] + comm->rx_desc_num[i - 1];
193 
194 	return 0;
195 }
196 
197 int spl2sw_descs_init(struct spl2sw_common *comm)
198 {
199 	u32 i, ret;
200 
201 	/* Initialize rx descriptor's data */
202 	comm->rx_desc_num[0] = RX_QUEUE0_DESC_NUM;
203 	comm->rx_desc_num[1] = RX_QUEUE1_DESC_NUM;
204 
205 	for (i = 0; i < RX_DESC_QUEUE_NUM; i++) {
206 		comm->rx_desc[i] = NULL;
207 		comm->rx_skb_info[i] = NULL;
208 		comm->rx_pos[i] = 0;
209 	}
210 	comm->rx_desc_buff_size = MAC_RX_LEN_MAX;
211 
212 	/* Initialize tx descriptor's data */
213 	comm->tx_done_pos = 0;
214 	comm->tx_desc = NULL;
215 	comm->tx_pos = 0;
216 	comm->tx_desc_full = 0;
217 	for (i = 0; i < TX_DESC_NUM; i++)
218 		comm->tx_temp_skb_info[i].skb = NULL;
219 
220 	/* Allocate tx & rx descriptors. */
221 	ret = spl2sw_descs_alloc(comm);
222 	if (ret)
223 		return ret;
224 
225 	spl2sw_tx_descs_init(comm);
226 
227 	return spl2sw_rx_descs_init(comm);
228 }
229