File Index
Files and directories
Sign in
FILE

enetc_cbdr.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c C
  1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
  2/* Copyright 2017-2019 NXP */
  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	/* 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}
 47EXPORT_SYMBOL_GPL(enetc_setup_cbdr);
 48
 49void enetc_teardown_cbdr(struct enetc_cbdr *cbdr)
 50{
 51	int size = cbdr->bd_count * sizeof(struct enetc_cbd);
 52
 53	/* disable ring */
 54	enetc_wr_reg(cbdr->mr, 0);
 55
 56	dma_free_coherent(cbdr->dma_dev, size, cbdr->bd_base,
 57			  cbdr->bd_dma_base);
 58	cbdr->bd_base = NULL;
 59	cbdr->dma_dev = NULL;
 60}
 61EXPORT_SYMBOL_GPL(enetc_teardown_cbdr);
 62
 63int enetc4_setup_cbdr(struct enetc_si *si)
 64{
 65	struct ntmp_user *user = &si->ntmp_user;
 66	struct device *dev = &si->pdev->dev;
 67	struct enetc_hw *hw = &si->hw;
 68	struct netc_cbdr_regs regs;
 69
 70	user->cbdr_num = 1;
 71	user->dev = dev;
 72	user->ring = devm_kcalloc(dev, user->cbdr_num,
 73				  sizeof(struct netc_cbdr), GFP_KERNEL);
 74	if (!user->ring)
 75		return -ENOMEM;
 76
 77	regs.pir = hw->reg + ENETC_SICBDRPIR;
 78	regs.cir = hw->reg + ENETC_SICBDRCIR;
 79	regs.mr = hw->reg + ENETC_SICBDRMR;
 80	regs.bar0 = hw->reg + ENETC_SICBDRBAR0;
 81	regs.bar1 = hw->reg + ENETC_SICBDRBAR1;
 82	regs.lenr = hw->reg + ENETC_SICBDRLENR;
 83
 84	return ntmp_init_cbdr(user->ring, dev, &regs);
 85}
 86EXPORT_SYMBOL_GPL(enetc4_setup_cbdr);
 87
 88void enetc4_teardown_cbdr(struct enetc_si *si)
 89{
 90	struct ntmp_user *user = &si->ntmp_user;
 91
 92	ntmp_free_cbdr(user->ring);
 93	user->dev = NULL;
 94}
 95EXPORT_SYMBOL_GPL(enetc4_teardown_cbdr);
 96
 97static void enetc_clean_cbdr(struct enetc_cbdr *ring)
 98{
 99	struct enetc_cbd *dest_cbd;
100	int i, status;
101
102	i = ring->next_to_clean;
103
104	while (enetc_rd_reg(ring->cir) != i) {
105		dest_cbd = ENETC_CBD(*ring, i);
106		status = dest_cbd->status_flags & ENETC_CBD_STATUS_MASK;
107		if (status)
108			dev_warn(ring->dma_dev, "CMD err %04x for cmd %04x\n",
109				 status, dest_cbd->cmd);
110
111		memset(dest_cbd, 0, sizeof(*dest_cbd));
112
113		i = (i + 1) % ring->bd_count;
114	}
115
116	ring->next_to_clean = i;
117}
118
119static int enetc_cbd_unused(struct enetc_cbdr *r)
120{
121	return (r->next_to_clean - r->next_to_use - 1 + r->bd_count) %
122		r->bd_count;
123}
124
125int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd)
126{
127	struct enetc_cbdr *ring = &si->cbd_ring;
128	int timeout = ENETC_CBDR_TIMEOUT;
129	struct enetc_cbd *dest_cbd;
130	int i;
131
132	if (unlikely(!ring->bd_base))
133		return -EIO;
134
135	if (unlikely(!enetc_cbd_unused(ring)))
136		enetc_clean_cbdr(ring);
137
138	i = ring->next_to_use;
139	dest_cbd = ENETC_CBD(*ring, i);
140
141	/* copy command to the ring */
142	*dest_cbd = *cbd;
143	i = (i + 1) % ring->bd_count;
144
145	ring->next_to_use = i;
146	/* let H/W know BD ring has been updated */
147	enetc_wr_reg(ring->pir, i);
148
149	do {
150		if (enetc_rd_reg(ring->cir) == i)
151			break;
152		udelay(10); /* cannot sleep, rtnl_lock() */
153		timeout -= 10;
154	} while (timeout);
155
156	if (!timeout)
157		return -EBUSY;
158
159	/* CBD may writeback data, feedback up level */
160	*cbd = *dest_cbd;
161
162	enetc_clean_cbdr(ring);
163
164	return 0;
165}
166EXPORT_SYMBOL_GPL(enetc_send_cmd);
167
168int enetc_clear_mac_flt_entry(struct enetc_si *si, int index)
169{
170	struct enetc_cbd cbd;
171
172	memset(&cbd, 0, sizeof(cbd));
173
174	cbd.cls = 1;
175	cbd.status_flags = ENETC_CBD_FLAGS_SF;
176	cbd.index = cpu_to_le16(index);
177
178	return enetc_send_cmd(si, &cbd);
179}
180EXPORT_SYMBOL_GPL(enetc_clear_mac_flt_entry);
181
182int enetc_set_mac_flt_entry(struct enetc_si *si, int index,
183			    char *mac_addr, int si_map)
184{
185	struct enetc_cbd cbd;
186	u32 upper;
187	u16 lower;
188
189	memset(&cbd, 0, sizeof(cbd));
190
191	/* fill up the "set" descriptor */
192	cbd.cls = 1;
193	cbd.status_flags = ENETC_CBD_FLAGS_SF;
194	cbd.index = cpu_to_le16(index);
195	cbd.opt[3] = cpu_to_le32(si_map);
196	/* enable entry */
197	cbd.opt[0] = cpu_to_le32(BIT(31));
198
199	upper = *(const u32 *)mac_addr;
200	lower = *(const u16 *)(mac_addr + 4);
201	cbd.addr[0] = cpu_to_le32(upper);
202	cbd.addr[1] = cpu_to_le32(lower);
203
204	return enetc_send_cmd(si, &cbd);
205}
206EXPORT_SYMBOL_GPL(enetc_set_mac_flt_entry);
207
208/* Set entry in RFS table */
209int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse,
210		       int index)
211{
212	struct enetc_cbdr *ring = &si->cbd_ring;
213	struct enetc_cbd cbd = {.cmd = 0};
214	void *tmp, *tmp_align;
215	dma_addr_t dma;
216	int err;
217
218	/* fill up the "set" descriptor */
219	cbd.cmd = 0;
220	cbd.cls = 4;
221	cbd.index = cpu_to_le16(index);
222	cbd.opt[3] = cpu_to_le32(0); /* SI */
223
224	tmp = enetc_cbd_alloc_data_mem(si, &cbd, sizeof(*rfse),
225				       &dma, &tmp_align);
226	if (!tmp)
227		return -ENOMEM;
228
229	memcpy(tmp_align, rfse, sizeof(*rfse));
230
231	err = enetc_send_cmd(si, &cbd);
232	if (err)
233		dev_err(ring->dma_dev, "FS entry add failed (%d)!", err);
234
235	enetc_cbd_free_data_mem(si, sizeof(*rfse), tmp, &dma);
236
237	return err;
238}
239EXPORT_SYMBOL_GPL(enetc_set_fs_entry);
240
241static int enetc_cmd_rss_table(struct enetc_si *si, u32 *table, int count,
242			       bool read)
243{
244	struct enetc_cbdr *ring = &si->cbd_ring;
245	struct enetc_cbd cbd = {.cmd = 0};
246	u8 *tmp, *tmp_align;
247	dma_addr_t dma;
248	int err, i;
249
250	if (count < ENETC_CBD_DATA_MEM_ALIGN)
251		/* HW only takes in a full 64 entry table */
252		return -EINVAL;
253
254	tmp = enetc_cbd_alloc_data_mem(si, &cbd, count,
255				       &dma, (void *)&tmp_align);
256	if (!tmp)
257		return -ENOMEM;
258
259	if (!read)
260		for (i = 0; i < count; i++)
261			tmp_align[i] = (u8)(table[i]);
262
263	/* fill up the descriptor */
264	cbd.cmd = read ? 2 : 1;
265	cbd.cls = 3;
266
267	err = enetc_send_cmd(si, &cbd);
268	if (err)
269		dev_err(ring->dma_dev, "RSS cmd failed (%d)!", err);
270
271	if (read)
272		for (i = 0; i < count; i++)
273			table[i] = tmp_align[i];
274
275	enetc_cbd_free_data_mem(si, count, tmp, &dma);
276
277	return err;
278}
279
280/* Get RSS table */
281int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count)
282{
283	return enetc_cmd_rss_table(si, table, count, true);
284}
285EXPORT_SYMBOL_GPL(enetc_get_rss_table);
286
287/* Set RSS table */
288int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count)
289{
290	return enetc_cmd_rss_table(si, (u32 *)table, count, false);
291}
292EXPORT_SYMBOL_GPL(enetc_set_rss_table);
293
294int enetc4_get_rss_table(struct enetc_si *si, u32 *table, int count)
295{
296	return ntmp_rsst_query_entry(&si->ntmp_user, table, count);
297}
298EXPORT_SYMBOL_GPL(enetc4_get_rss_table);
299
300int enetc4_set_rss_table(struct enetc_si *si, const u32 *table, int count)
301{
302	return ntmp_rsst_update_entry(&si->ntmp_user, table, count);
303}
304EXPORT_SYMBOL_GPL(enetc4_set_rss_table);
~/ Read-only file preview.