1
2
3
4#include "enetc.h"
5
6int 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
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
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
43 enetc_wr_reg(cbdr->mr, BIT(31));
44
45 return 0;
46}
47
48void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
49{
50 int size = cbdr->bd_count * sizeof(struct enetc_cbd);
51
52
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
61static 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
83static 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
89int 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
106 *dest_cbd = *cbd;
107 i = (i + 1) % ring->bd_count;
108
109 ring->next_to_use = i;
110
111 enetc_wr_reg(ring->pir, i);
112
113 do {
114 if (enetc_rd_reg(ring->cir) == i)
115 break;
116 udelay(10);
117 timeout -= 10;
118 } while (timeout);
119
120 if (!timeout)
121 return -EBUSY;
122
123
124 *cbd = *dest_cbd;
125
126 enetc_clean_cbdr(ring);
127
128 return 0;
129}
130
131int 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
144int 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
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
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
171int 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
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);
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
212static 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
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
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
260int 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
266int 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