1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2017-2019 NXP */
3 
4 #include "enetc.h"
5 
6 int enetc_setup_cbdr(struct device *dev, struct enetc_hw *hw, int bd_count,
7 		     struct enetc_cbdr *cbdr)
8 {
9 	int size = bd_count * sizeof(struct enetc_cbd);
10 
11 	cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base,
12 					   GFP_KERNEL);
13 	if (!cbdr->bd_base)
14 		return -ENOMEM;
15 
16 	/* h/w requires 128B alignment */
17 	if (!IS_ALIGNED(cbdr->bd_dma_base, 128)) {
18 		dma_free_coherent(dev, size, cbdr->bd_base,
19 				  cbdr->bd_dma_base);
20 		return -EINVAL;
21 	}
22 
23 	cbdr->next_to_clean = 0;
24 	cbdr->next_to_use = 0;
25 	cbdr->dma_dev = dev;
26 	cbdr->bd_count = bd_count;
27 
28 	cbdr->pir = hw->reg + ENETC_SICBDRPIR;
29 	cbdr->cir = hw->reg + ENETC_SICBDRCIR;
30 	cbdr->mr = hw->reg + ENETC_SICBDRMR;
31 
32 	/* set CBDR cache attributes */
33 	enetc_wr(hw, ENETC_SICAR2,
34 		 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
35 
36 	enetc_wr(hw, ENETC_SICBDRBAR0, lower_32_bits(cbdr->bd_dma_base));
37 	enetc_wr(hw, ENETC_SICBDRBAR1, upper_32_bits(cbdr->bd_dma_base));
38 	enetc_wr(hw, ENETC_SICBDRLENR, ENETC_RTBLENR_LEN(cbdr->bd_count));
39 
40 	enetc_wr_reg(cbdr->pir, cbdr->next_to_clean);
41 	enetc_wr_reg(cbdr->cir, cbdr->next_to_use);
42 	/* enable ring */
43 	enetc_wr_reg(cbdr->mr, BIT(31));
44 
45 	return 0;
46 }
47 
48 void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
49 {
50 	int size = cbdr->bd_count * sizeof(struct enetc_cbd);
51 
52 	/* disable ring */
53 	enetc_wr_reg(cbdr->mr, 0);
54 
55 	dma_free_coherent(cbdr->dma_dev, size, cbdr->bd_base,
56 			  cbdr->bd_dma_base);
57 	cbdr->bd_base = NULL;
58 	cbdr->dma_dev = NULL;
59 }
60 
61 static void enetc_clean_cbdr(struct enetc_cbdr *ring)
62 {
63 	struct enetc_cbd *dest_cbd;
64 	int i, status;
65 
66 	i = ring->next_to_clean;
67 
68 	while (enetc_rd_reg(ring->cir) != i) {
69 		dest_cbd = ENETC_CBD(*ring, i);
70 		status = dest_cbd->status_flags & ENETC_CBD_STATUS_MASK;
71 		if (status)
72 			dev_warn(ring->dma_dev, "CMD err %04x for cmd %04x\n",
73 				 status, dest_cbd->cmd);
74 
75 		memset(dest_cbd, 0, sizeof(*dest_cbd));
76 
77 		i = (i + 1) % ring->bd_count;
78 	}
79 
80 	ring->next_to_clean = i;
81 }
82 
83 static int enetc_cbd_unused(struct enetc_cbdr *r)
84 {
85 	return (r->next_to_clean - r->next_to_use - 1 + r->bd_count) %
86 		r->bd_count;
87 }
88 
89 int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
90 {
91 	struct enetc_cbdr *ring = &si->cbd_ring;
92 	int timeout = ENETC_CBDR_TIMEOUT;
93 	struct enetc_cbd *dest_cbd;
94 	int i;
95 
96 	if (unlikely(!ring->bd_base))
97 		return -EIO;
98 
99 	if (unlikely(!enetc_cbd_unused(ring)))
100 		enetc_clean_cbdr(ring);
101 
102 	i = ring->next_to_use;
103 	dest_cbd = ENETC_CBD(*ring, i);
104 
105 	/* copy command to the ring */
106 	*dest_cbd = *cbd;
107 	i = (i + 1) % ring->bd_count;
108 
109 	ring->next_to_use = i;
110 	/* let H/W know BD ring has been updated */
111 	enetc_wr_reg(ring->pir, i);
112 
113 	do {
114 		if (enetc_rd_reg(ring->cir) == i)
115 			break;
116 		udelay(10); /* cannot sleep, rtnl_lock() */
117 		timeout -= 10;
118 	} while (timeout);
119 
120 	if (!timeout)
121 		return -EBUSY;
122 
123 	/* CBD may writeback data, feedback up level */
124 	*cbd = *dest_cbd;
125 
126 	enetc_clean_cbdr(ring);
127 
128 	return 0;
129 }
130 
131 int enetc_clear_mac_flt_entry(struct enetc_si *si, int index)
132 {
133 	struct enetc_cbd cbd;
134 
135 	memset(&cbd, 0, sizeof(cbd));
136 
137 	cbd.cls = 1;
138 	cbd.status_flags = ENETC_CBD_FLAGS_SF;
139 	cbd.index = cpu_to_le16(index);
140 
141 	return enetc_send_cmd(si, &cbd);
142 }
143 
144 int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
145 			    char *mac_addr, int si_map)
146 {
147 	struct enetc_cbd cbd;
148 	u32 upper;
149 	u16 lower;
150 
151 	memset(&cbd, 0, sizeof(cbd));
152 
153 	/* fill up the "set" descriptor */
154 	cbd.cls = 1;
155 	cbd.status_flags = ENETC_CBD_FLAGS_SF;
156 	cbd.index = cpu_to_le16(index);
157 	cbd.opt[3] = cpu_to_le32(si_map);
158 	/* enable entry */
159 	cbd.opt[0] = cpu_to_le32(BIT(31));
160 
161 	upper = *(const u32 *)mac_addr;
162 	lower = *(const u16 *)(mac_addr + 4);
163 	cbd.addr[0] = cpu_to_le32(upper);
164 	cbd.addr[1] = cpu_to_le32(lower);
165 
166 	return enetc_send_cmd(si, &cbd);
167 }
168 
169 #define RFSE_ALIGN	64
170 /* Set entry in RFS table */
171 int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
172 		       int index)
173 {
174 	struct enetc_cbdr *ring = &si->cbd_ring;
175 	struct enetc_cbd cbd = {.cmd = 0};
176 	dma_addr_t dma, dma_align;
177 	void *tmp, *tmp_align;
178 	int err;
179 
180 	/* fill up the "set" descriptor */
181 	cbd.cmd = 0;
182 	cbd.cls = 4;
183 	cbd.index = cpu_to_le16(index);
184 	cbd.length = cpu_to_le16(sizeof(*rfse));
185 	cbd.opt[3] = cpu_to_le32(0); /* SI */
186 
187 	tmp = dma_alloc_coherent(ring->dma_dev, sizeof(*rfse) + RFSE_ALIGN,
188 				 &dma, GFP_KERNEL);
189 	if (!tmp) {
190 		dev_err(ring->dma_dev, "DMA mapping of RFS entry failed!\n");
191 		return -ENOMEM;
192 	}
193 
194 	dma_align = ALIGN(dma, RFSE_ALIGN);
195 	tmp_align = PTR_ALIGN(tmp, RFSE_ALIGN);
196 	memcpy(tmp_align, rfse, sizeof(*rfse));
197 
198 	cbd.addr[0] = cpu_to_le32(lower_32_bits(dma_align));
199 	cbd.addr[1] = cpu_to_le32(upper_32_bits(dma_align));
200 
201 	err = enetc_send_cmd(si, &cbd);
202 	if (err)
203 		dev_err(ring->dma_dev, "FS entry add failed (%d)!", err);
204 
205 	dma_free_coherent(ring->dma_dev, sizeof(*rfse) + RFSE_ALIGN,
206 			  tmp, dma);
207 
208 	return err;
209 }
210 
211 #define RSSE_ALIGN	64
212 static int enetc_cmd_rss_table(struct enetc_si *si, u32 *table, int count,
213 			       bool read)
214 {
215 	struct enetc_cbdr *ring = &si->cbd_ring;
216 	struct enetc_cbd cbd = {.cmd = 0};
217 	dma_addr_t dma, dma_align;
218 	u8 *tmp, *tmp_align;
219 	int err, i;
220 
221 	if (count < RSSE_ALIGN)
222 		/* HW only takes in a full 64 entry table */
223 		return -EINVAL;
224 
225 	tmp = dma_alloc_coherent(ring->dma_dev, count + RSSE_ALIGN,
226 				 &dma, GFP_KERNEL);
227 	if (!tmp) {
228 		dev_err(ring->dma_dev, "DMA mapping of RSS table failed!\n");
229 		return -ENOMEM;
230 	}
231 	dma_align = ALIGN(dma, RSSE_ALIGN);
232 	tmp_align = PTR_ALIGN(tmp, RSSE_ALIGN);
233 
234 	if (!read)
235 		for (i = 0; i < count; i++)
236 			tmp_align[i] = (u8)(table[i]);
237 
238 	/* fill up the descriptor */
239 	cbd.cmd = read ? 2 : 1;
240 	cbd.cls = 3;
241 	cbd.length = cpu_to_le16(count);
242 
243 	cbd.addr[0] = cpu_to_le32(lower_32_bits(dma_align));
244 	cbd.addr[1] = cpu_to_le32(upper_32_bits(dma_align));
245 
246 	err = enetc_send_cmd(si, &cbd);
247 	if (err)
248 		dev_err(ring->dma_dev, "RSS cmd failed (%d)!", err);
249 
250 	if (read)
251 		for (i = 0; i < count; i++)
252 			table[i] = tmp_align[i];
253 
254 	dma_free_coherent(ring->dma_dev, count + RSSE_ALIGN, tmp, dma);
255 
256 	return err;
257 }
258 
259 /* Get RSS table */
260 int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count)
261 {
262 	return enetc_cmd_rss_table(si, table, count, true);
263 }
264 
265 /* Set RSS table */
266 int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count)
267 {
268 	return enetc_cmd_rss_table(si, (u32 *)table, count, false);
269 }
270