File Index
Files and directories
Sign in
FILE

ntmp.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/freescale/enetc/ntmp.c C
  1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
  2/*
  3 * NETC NTMP (NETC Table Management Protocol) 2.0 Library
  4 * Copyright 2025 NXP
  5 */
  6
  7#include <linux/dma-mapping.h>
  8#include <linux/fsl/netc_global.h>
  9#include <linux/iopoll.h>
 10
 11#include "ntmp_private.h"
 12
 13#define NETC_CBDR_TIMEOUT		1000 /* us */
 14#define NETC_CBDR_DELAY_US		10
 15#define NETC_CBDR_MR_EN			BIT(31)
 16
 17#define NTMP_BASE_ADDR_ALIGN		128
 18#define NTMP_DATA_ADDR_ALIGN		32
 19
 20/* Define NTMP Table ID */
 21#define NTMP_MAFT_ID			1
 22#define NTMP_RSST_ID			3
 23
 24/* Generic Update Actions for most tables */
 25#define NTMP_GEN_UA_CFGEU		BIT(0)
 26#define NTMP_GEN_UA_STSEU		BIT(1)
 27
 28#define NTMP_ENTRY_ID_SIZE		4
 29#define RSST_ENTRY_NUM			64
 30#define RSST_STSE_DATA_SIZE(n)		((n) * 8)
 31#define RSST_CFGE_DATA_SIZE(n)		(n)
 32
 33int ntmp_init_cbdr(struct netc_cbdr *cbdr, struct device *dev,
 34		   const struct netc_cbdr_regs *regs)
 35{
 36	int cbd_num = NETC_CBDR_BD_NUM;
 37	size_t size;
 38
 39	size = cbd_num * sizeof(union netc_cbd) + NTMP_BASE_ADDR_ALIGN;
 40	cbdr->addr_base = dma_alloc_coherent(dev, size, &cbdr->dma_base,
 41					     GFP_KERNEL);
 42	if (!cbdr->addr_base)
 43		return -ENOMEM;
 44
 45	cbdr->dma_size = size;
 46	cbdr->bd_num = cbd_num;
 47	cbdr->regs = *regs;
 48	cbdr->dev = dev;
 49
 50	/* The base address of the Control BD Ring must be 128 bytes aligned */
 51	cbdr->dma_base_align =  ALIGN(cbdr->dma_base,  NTMP_BASE_ADDR_ALIGN);
 52	cbdr->addr_base_align = PTR_ALIGN(cbdr->addr_base,
 53					  NTMP_BASE_ADDR_ALIGN);
 54
 55	spin_lock_init(&cbdr->ring_lock);
 56
 57	cbdr->next_to_use = netc_read(cbdr->regs.pir);
 58	cbdr->next_to_clean = netc_read(cbdr->regs.cir);
 59
 60	/* Step 1: Configure the base address of the Control BD Ring */
 61	netc_write(cbdr->regs.bar0, lower_32_bits(cbdr->dma_base_align));
 62	netc_write(cbdr->regs.bar1, upper_32_bits(cbdr->dma_base_align));
 63
 64	/* Step 2: Configure the number of BDs of the Control BD Ring */
 65	netc_write(cbdr->regs.lenr, cbdr->bd_num);
 66
 67	/* Step 3: Enable the Control BD Ring */
 68	netc_write(cbdr->regs.mr, NETC_CBDR_MR_EN);
 69
 70	return 0;
 71}
 72EXPORT_SYMBOL_GPL(ntmp_init_cbdr);
 73
 74void ntmp_free_cbdr(struct netc_cbdr *cbdr)
 75{
 76	/* Disable the Control BD Ring */
 77	netc_write(cbdr->regs.mr, 0);
 78	dma_free_coherent(cbdr->dev, cbdr->dma_size, cbdr->addr_base,
 79			  cbdr->dma_base);
 80	memset(cbdr, 0, sizeof(*cbdr));
 81}
 82EXPORT_SYMBOL_GPL(ntmp_free_cbdr);
 83
 84static int ntmp_get_free_cbd_num(struct netc_cbdr *cbdr)
 85{
 86	return (cbdr->next_to_clean - cbdr->next_to_use - 1 +
 87		cbdr->bd_num) % cbdr->bd_num;
 88}
 89
 90static union netc_cbd *ntmp_get_cbd(struct netc_cbdr *cbdr, int index)
 91{
 92	return &((union netc_cbd *)(cbdr->addr_base_align))[index];
 93}
 94
 95static void ntmp_clean_cbdr(struct netc_cbdr *cbdr)
 96{
 97	union netc_cbd *cbd;
 98	int i;
 99
100	i = cbdr->next_to_clean;
101	while (netc_read(cbdr->regs.cir) != i) {
102		cbd = ntmp_get_cbd(cbdr, i);
103		memset(cbd, 0, sizeof(*cbd));
104		i = (i + 1) % cbdr->bd_num;
105	}
106
107	cbdr->next_to_clean = i;
108}
109
110static int netc_xmit_ntmp_cmd(struct ntmp_user *user, union netc_cbd *cbd)
111{
112	union netc_cbd *cur_cbd;
113	struct netc_cbdr *cbdr;
114	int i, err;
115	u16 status;
116	u32 val;
117
118	/* Currently only i.MX95 ENETC is supported, and it only has one
119	 * command BD ring
120	 */
121	cbdr = &user->ring[0];
122
123	spin_lock_bh(&cbdr->ring_lock);
124
125	if (unlikely(!ntmp_get_free_cbd_num(cbdr)))
126		ntmp_clean_cbdr(cbdr);
127
128	i = cbdr->next_to_use;
129	cur_cbd = ntmp_get_cbd(cbdr, i);
130	*cur_cbd = *cbd;
131	dma_wmb();
132
133	/* Update producer index of both software and hardware */
134	i = (i + 1) % cbdr->bd_num;
135	cbdr->next_to_use = i;
136	netc_write(cbdr->regs.pir, i);
137
138	err = read_poll_timeout_atomic(netc_read, val, val == i,
139				       NETC_CBDR_DELAY_US, NETC_CBDR_TIMEOUT,
140				       true, cbdr->regs.cir);
141	if (unlikely(err))
142		goto cbdr_unlock;
143
144	dma_rmb();
145	/* Get the writeback command BD, because the caller may need
146	 * to check some other fields of the response header.
147	 */
148	*cbd = *cur_cbd;
149
150	/* Check the writeback error status */
151	status = le16_to_cpu(cbd->resp_hdr.error_rr) & NTMP_RESP_ERROR;
152	if (unlikely(status)) {
153		err = -EIO;
154		dev_err(user->dev, "Command BD error: 0x%04x\n", status);
155	}
156
157	ntmp_clean_cbdr(cbdr);
158	dma_wmb();
159
160cbdr_unlock:
161	spin_unlock_bh(&cbdr->ring_lock);
162
163	return err;
164}
165
166static int ntmp_alloc_data_mem(struct ntmp_dma_buf *data, void **buf_align)
167{
168	void *buf;
169
170	buf = dma_alloc_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
171				 &data->dma, GFP_KERNEL);
172	if (!buf)
173		return -ENOMEM;
174
175	data->buf = buf;
176	*buf_align = PTR_ALIGN(buf, NTMP_DATA_ADDR_ALIGN);
177
178	return 0;
179}
180
181static void ntmp_free_data_mem(struct ntmp_dma_buf *data)
182{
183	dma_free_coherent(data->dev, data->size + NTMP_DATA_ADDR_ALIGN,
184			  data->buf, data->dma);
185}
186
187static void ntmp_fill_request_hdr(union netc_cbd *cbd, dma_addr_t dma,
188				  int len, int table_id, int cmd,
189				  int access_method)
190{
191	dma_addr_t dma_align;
192
193	memset(cbd, 0, sizeof(*cbd));
194	dma_align = ALIGN(dma, NTMP_DATA_ADDR_ALIGN);
195	cbd->req_hdr.addr = cpu_to_le64(dma_align);
196	cbd->req_hdr.len = cpu_to_le32(len);
197	cbd->req_hdr.cmd = cmd;
198	cbd->req_hdr.access_method = FIELD_PREP(NTMP_ACCESS_METHOD,
199						access_method);
200	cbd->req_hdr.table_id = table_id;
201	cbd->req_hdr.ver_cci_rr = FIELD_PREP(NTMP_HDR_VERSION,
202					     NTMP_HDR_VER2);
203	/* For NTMP version 2.0 or later version */
204	cbd->req_hdr.npf = cpu_to_le32(NTMP_NPF);
205}
206
207static void ntmp_fill_crd(struct ntmp_cmn_req_data *crd, u8 tblv,
208			  u8 qa, u16 ua)
209{
210	crd->update_act = cpu_to_le16(ua);
211	crd->tblv_qact = NTMP_TBLV_QACT(tblv, qa);
212}
213
214static void ntmp_fill_crd_eid(struct ntmp_req_by_eid *rbe, u8 tblv,
215			      u8 qa, u16 ua, u32 entry_id)
216{
217	ntmp_fill_crd(&rbe->crd, tblv, qa, ua);
218	rbe->entry_id = cpu_to_le32(entry_id);
219}
220
221static const char *ntmp_table_name(int tbl_id)
222{
223	switch (tbl_id) {
224	case NTMP_MAFT_ID:
225		return "MAC Address Filter Table";
226	case NTMP_RSST_ID:
227		return "RSS Table";
228	default:
229		return "Unknown Table";
230	};
231}
232
233static int ntmp_delete_entry_by_id(struct ntmp_user *user, int tbl_id,
234				   u8 tbl_ver, u32 entry_id, u32 req_len,
235				   u32 resp_len)
236{
237	struct ntmp_dma_buf data = {
238		.dev = user->dev,
239		.size = max(req_len, resp_len),
240	};
241	struct ntmp_req_by_eid *req;
242	union netc_cbd cbd;
243	int err;
244
245	err = ntmp_alloc_data_mem(&data, (void **)&req);
246	if (err)
247		return err;
248
249	ntmp_fill_crd_eid(req, tbl_ver, 0, 0, entry_id);
250	ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(req_len, resp_len),
251			      tbl_id, NTMP_CMD_DELETE, NTMP_AM_ENTRY_ID);
252
253	err = netc_xmit_ntmp_cmd(user, &cbd);
254	if (err)
255		dev_err(user->dev,
256			"Failed to delete entry 0x%x of %s, err: %pe",
257			entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
258
259	ntmp_free_data_mem(&data);
260
261	return err;
262}
263
264static int ntmp_query_entry_by_id(struct ntmp_user *user, int tbl_id,
265				  u32 len, struct ntmp_req_by_eid *req,
266				  dma_addr_t dma, bool compare_eid)
267{
268	struct ntmp_cmn_resp_query *resp;
269	int cmd = NTMP_CMD_QUERY;
270	union netc_cbd cbd;
271	u32 entry_id;
272	int err;
273
274	entry_id = le32_to_cpu(req->entry_id);
275	if (le16_to_cpu(req->crd.update_act))
276		cmd = NTMP_CMD_QU;
277
278	/* Request header */
279	ntmp_fill_request_hdr(&cbd, dma, len, tbl_id, cmd, NTMP_AM_ENTRY_ID);
280	err = netc_xmit_ntmp_cmd(user, &cbd);
281	if (err) {
282		dev_err(user->dev,
283			"Failed to query entry 0x%x of %s, err: %pe\n",
284			entry_id, ntmp_table_name(tbl_id), ERR_PTR(err));
285		return err;
286	}
287
288	/* For a few tables, the first field of their response data is not
289	 * entry_id, so directly return success.
290	 */
291	if (!compare_eid)
292		return 0;
293
294	resp = (struct ntmp_cmn_resp_query *)req;
295	if (unlikely(le32_to_cpu(resp->entry_id) != entry_id)) {
296		dev_err(user->dev,
297			"%s: query EID 0x%x doesn't match response EID 0x%x\n",
298			ntmp_table_name(tbl_id), entry_id, le32_to_cpu(resp->entry_id));
299		return -EIO;
300	}
301
302	return 0;
303}
304
305int ntmp_maft_add_entry(struct ntmp_user *user, u32 entry_id,
306			struct maft_entry_data *maft)
307{
308	struct ntmp_dma_buf data = {
309		.dev = user->dev,
310		.size = sizeof(struct maft_req_add),
311	};
312	struct maft_req_add *req;
313	union netc_cbd cbd;
314	int err;
315
316	err = ntmp_alloc_data_mem(&data, (void **)&req);
317	if (err)
318		return err;
319
320	/* Set mac address filter table request data buffer */
321	ntmp_fill_crd_eid(&req->rbe, user->tbl.maft_ver, 0, 0, entry_id);
322	req->keye = maft->keye;
323	req->cfge = maft->cfge;
324
325	ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
326			      NTMP_MAFT_ID, NTMP_CMD_ADD, NTMP_AM_ENTRY_ID);
327	err = netc_xmit_ntmp_cmd(user, &cbd);
328	if (err)
329		dev_err(user->dev, "Failed to add MAFT entry 0x%x, err: %pe\n",
330			entry_id, ERR_PTR(err));
331
332	ntmp_free_data_mem(&data);
333
334	return err;
335}
336EXPORT_SYMBOL_GPL(ntmp_maft_add_entry);
337
338int ntmp_maft_query_entry(struct ntmp_user *user, u32 entry_id,
339			  struct maft_entry_data *maft)
340{
341	struct ntmp_dma_buf data = {
342		.dev = user->dev,
343		.size = sizeof(struct maft_resp_query),
344	};
345	struct maft_resp_query *resp;
346	struct ntmp_req_by_eid *req;
347	int err;
348
349	err = ntmp_alloc_data_mem(&data, (void **)&req);
350	if (err)
351		return err;
352
353	ntmp_fill_crd_eid(req, user->tbl.maft_ver, 0, 0, entry_id);
354	err = ntmp_query_entry_by_id(user, NTMP_MAFT_ID,
355				     NTMP_LEN(sizeof(*req), data.size),
356				     req, data.dma, true);
357	if (err)
358		goto end;
359
360	resp = (struct maft_resp_query *)req;
361	maft->keye = resp->keye;
362	maft->cfge = resp->cfge;
363
364end:
365	ntmp_free_data_mem(&data);
366
367	return err;
368}
369EXPORT_SYMBOL_GPL(ntmp_maft_query_entry);
370
371int ntmp_maft_delete_entry(struct ntmp_user *user, u32 entry_id)
372{
373	return ntmp_delete_entry_by_id(user, NTMP_MAFT_ID, user->tbl.maft_ver,
374				       entry_id, NTMP_EID_REQ_LEN, 0);
375}
376EXPORT_SYMBOL_GPL(ntmp_maft_delete_entry);
377
378int ntmp_rsst_update_entry(struct ntmp_user *user, const u32 *table,
379			   int count)
380{
381	struct ntmp_dma_buf data = {.dev = user->dev};
382	struct rsst_req_update *req;
383	union netc_cbd cbd;
384	int err, i;
385
386	if (count != RSST_ENTRY_NUM)
387		/* HW only takes in a full 64 entry table */
388		return -EINVAL;
389
390	data.size = struct_size(req, groups, count);
391	err = ntmp_alloc_data_mem(&data, (void **)&req);
392	if (err)
393		return err;
394
395	/* Set the request data buffer */
396	ntmp_fill_crd_eid(&req->rbe, user->tbl.rsst_ver, 0,
397			  NTMP_GEN_UA_CFGEU | NTMP_GEN_UA_STSEU, 0);
398	for (i = 0; i < count; i++)
399		req->groups[i] = (u8)(table[i]);
400
401	ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(data.size, 0),
402			      NTMP_RSST_ID, NTMP_CMD_UPDATE, NTMP_AM_ENTRY_ID);
403
404	err = netc_xmit_ntmp_cmd(user, &cbd);
405	if (err)
406		dev_err(user->dev, "Failed to update RSST entry, err: %pe\n",
407			ERR_PTR(err));
408
409	ntmp_free_data_mem(&data);
410
411	return err;
412}
413EXPORT_SYMBOL_GPL(ntmp_rsst_update_entry);
414
415int ntmp_rsst_query_entry(struct ntmp_user *user, u32 *table, int count)
416{
417	struct ntmp_dma_buf data = {.dev = user->dev};
418	struct ntmp_req_by_eid *req;
419	union netc_cbd cbd;
420	int err, i;
421	u8 *group;
422
423	if (count != RSST_ENTRY_NUM)
424		/* HW only takes in a full 64 entry table */
425		return -EINVAL;
426
427	data.size = NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count) +
428		    RSST_CFGE_DATA_SIZE(count);
429	err = ntmp_alloc_data_mem(&data, (void **)&req);
430	if (err)
431		return err;
432
433	/* Set the request data buffer */
434	ntmp_fill_crd_eid(req, user->tbl.rsst_ver, 0, 0, 0);
435	ntmp_fill_request_hdr(&cbd, data.dma, NTMP_LEN(sizeof(*req), data.size),
436			      NTMP_RSST_ID, NTMP_CMD_QUERY, NTMP_AM_ENTRY_ID);
437	err = netc_xmit_ntmp_cmd(user, &cbd);
438	if (err) {
439		dev_err(user->dev, "Failed to query RSST entry, err: %pe\n",
440			ERR_PTR(err));
441		goto end;
442	}
443
444	group = (u8 *)req;
445	group += NTMP_ENTRY_ID_SIZE + RSST_STSE_DATA_SIZE(count);
446	for (i = 0; i < count; i++)
447		table[i] = group[i];
448
449end:
450	ntmp_free_data_mem(&data);
451
452	return err;
453}
454EXPORT_SYMBOL_GPL(ntmp_rsst_query_entry);
455
456MODULE_DESCRIPTION("NXP NETC Library");
457MODULE_LICENSE("Dual BSD/GPL");
~/ Read-only file preview.