File Index
Files and directories
Sign in
FILE

nfp_cpplib.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_cpplib.c C
  1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
  2/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
  3
  4/*
  5 * nfp_cpplib.c
  6 * Library of functions to access the NFP's CPP bus
  7 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
  8 *          Jason McMullan <jason.mcmullan@netronome.com>
  9 *          Rolf Neugebauer <rolf.neugebauer@netronome.com>
 10 */
 11
 12#include <linux/unaligned.h>
 13#include <linux/bitfield.h>
 14#include <linux/delay.h>
 15#include <linux/kernel.h>
 16#include <linux/module.h>
 17#include <linux/slab.h>
 18#include <linux/sched.h>
 19
 20#include "nfp_cpp.h"
 21#include "nfp6000/nfp6000.h"
 22#include "nfp6000/nfp_xpb.h"
 23
 24/* NFP6000 PL */
 25#define NFP_PL_DEVICE_PART_NFP6000		0x6200
 26#define NFP_PL_DEVICE_ID			0x00000004
 27#define   NFP_PL_DEVICE_ID_MASK			GENMASK(7, 0)
 28#define   NFP_PL_DEVICE_PART_MASK		GENMASK(31, 16)
 29#define NFP_PL_DEVICE_MODEL_MASK		(NFP_PL_DEVICE_PART_MASK | \
 30						 NFP_PL_DEVICE_ID_MASK)
 31
 32/**
 33 * nfp_cpp_readl() - Read a u32 word from a CPP location
 34 * @cpp:	CPP device handle
 35 * @cpp_id:	CPP ID for operation
 36 * @address:	Address for operation
 37 * @value:	Pointer to read buffer
 38 *
 39 * Return: 0 on success, or -ERRNO
 40 */
 41int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
 42		  unsigned long long address, u32 *value)
 43{
 44	u8 tmp[4];
 45	int n;
 46
 47	n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
 48	if (n != sizeof(tmp))
 49		return n < 0 ? n : -EIO;
 50
 51	*value = get_unaligned_le32(tmp);
 52	return 0;
 53}
 54
 55/**
 56 * nfp_cpp_writel() - Write a u32 word to a CPP location
 57 * @cpp:	CPP device handle
 58 * @cpp_id:	CPP ID for operation
 59 * @address:	Address for operation
 60 * @value:	Value to write
 61 *
 62 * Return: 0 on success, or -ERRNO
 63 */
 64int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
 65		   unsigned long long address, u32 value)
 66{
 67	u8 tmp[4];
 68	int n;
 69
 70	put_unaligned_le32(value, tmp);
 71	n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
 72
 73	return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
 74}
 75
 76/**
 77 * nfp_cpp_readq() - Read a u64 word from a CPP location
 78 * @cpp:	CPP device handle
 79 * @cpp_id:	CPP ID for operation
 80 * @address:	Address for operation
 81 * @value:	Pointer to read buffer
 82 *
 83 * Return: 0 on success, or -ERRNO
 84 */
 85int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
 86		  unsigned long long address, u64 *value)
 87{
 88	u8 tmp[8];
 89	int n;
 90
 91	n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
 92	if (n != sizeof(tmp))
 93		return n < 0 ? n : -EIO;
 94
 95	*value = get_unaligned_le64(tmp);
 96	return 0;
 97}
 98
 99/**
100 * nfp_cpp_writeq() - Write a u64 word to a CPP location
101 * @cpp:	CPP device handle
102 * @cpp_id:	CPP ID for operation
103 * @address:	Address for operation
104 * @value:	Value to write
105 *
106 * Return: 0 on success, or -ERRNO
107 */
108int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
109		   unsigned long long address, u64 value)
110{
111	u8 tmp[8];
112	int n;
113
114	put_unaligned_le64(value, tmp);
115	n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
116
117	return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
118}
119
120/* NOTE: This code should not use nfp_xpb_* functions,
121 * as those are model-specific
122 */
123int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
124{
125	u32 reg;
126	int err;
127
128	err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
129			    &reg);
130	if (err < 0)
131		return err;
132
133	*model = reg & NFP_PL_DEVICE_MODEL_MASK;
134	/* Disambiguate the NFP4000/NFP5000/NFP6000 chips */
135	if (FIELD_GET(NFP_PL_DEVICE_PART_MASK, reg) ==
136	    NFP_PL_DEVICE_PART_NFP6000) {
137		if (*model & NFP_PL_DEVICE_ID_MASK)
138			*model -= 0x10;
139	}
140
141	return 0;
142}
143
144static u8 nfp_bytemask(int width, u64 addr)
145{
146	if (width == 8)
147		return 0xff;
148	else if (width == 4)
149		return 0x0f << (addr & 4);
150	else if (width == 2)
151		return 0x03 << (addr & 6);
152	else if (width == 1)
153		return 0x01 << (addr & 7);
154	else
155		return 0;
156}
157
158int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
159			  u64 addr, void *buff, size_t len, int width_read)
160{
161	struct nfp_cpp_explicit *expl;
162	char *tmp = buff;
163	int err, i, incr;
164	u8 byte_mask;
165
166	if (len & (width_read - 1))
167		return -EINVAL;
168
169	expl = nfp_cpp_explicit_acquire(cpp);
170	if (!expl)
171		return -EBUSY;
172
173	incr = min_t(int, 16 * width_read, 128);
174	incr = min_t(int, incr, len);
175
176	/* Translate a NFP_CPP_ACTION_RW to action 0 */
177	if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
178		cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
179				    NFP_CPP_ID_TOKEN_of(cpp_id));
180
181	byte_mask = nfp_bytemask(width_read, addr);
182
183	nfp_cpp_explicit_set_target(expl, cpp_id,
184				    incr / width_read - 1, byte_mask);
185	nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
186				    0, NFP_SIGNAL_NONE);
187
188	for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
189		if (i + incr > len) {
190			incr = len - i;
191			nfp_cpp_explicit_set_target(expl, cpp_id,
192						    incr / width_read - 1,
193						    0xff);
194		}
195
196		err = nfp_cpp_explicit_do(expl, addr);
197		if (err < 0)
198			goto exit_release;
199
200		err = nfp_cpp_explicit_get(expl, tmp, incr);
201		if (err < 0)
202			goto exit_release;
203	}
204	err = len;
205exit_release:
206	nfp_cpp_explicit_release(expl);
207
208	return err;
209}
210
211int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
212			   const void *buff, size_t len, int width_write)
213{
214	struct nfp_cpp_explicit *expl;
215	const char *tmp = buff;
216	int err, i, incr;
217	u8 byte_mask;
218
219	if (len & (width_write - 1))
220		return -EINVAL;
221
222	expl = nfp_cpp_explicit_acquire(cpp);
223	if (!expl)
224		return -EBUSY;
225
226	incr = min_t(int, 16 * width_write, 128);
227	incr = min_t(int, incr, len);
228
229	/* Translate a NFP_CPP_ACTION_RW to action 1 */
230	if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
231		cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
232				    NFP_CPP_ID_TOKEN_of(cpp_id));
233
234	byte_mask = nfp_bytemask(width_write, addr);
235
236	nfp_cpp_explicit_set_target(expl, cpp_id,
237				    incr / width_write - 1, byte_mask);
238	nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
239				    0, NFP_SIGNAL_NONE);
240
241	for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
242		if (i + incr > len) {
243			incr = len - i;
244			nfp_cpp_explicit_set_target(expl, cpp_id,
245						    incr / width_write - 1,
246						    0xff);
247		}
248
249		err = nfp_cpp_explicit_put(expl, tmp, incr);
250		if (err < 0)
251			goto exit_release;
252
253		err = nfp_cpp_explicit_do(expl, addr);
254		if (err < 0)
255			goto exit_release;
256	}
257	err = len;
258exit_release:
259	nfp_cpp_explicit_release(expl);
260
261	return err;
262}
263
264/**
265 * nfp_cpp_map_area() - Helper function to map an area
266 * @cpp:    NFP CPP handler
267 * @name:   Name for the area
268 * @cpp_id: CPP ID for operation
269 * @addr:   CPP address
270 * @size:   Size of the area
271 * @area:   Area handle (output)
272 *
273 * Map an area of IOMEM access.  To undo the effect of this function call
274 * @nfp_cpp_area_release_free(*area).
275 *
276 * Return: Pointer to memory mapped area or ERR_PTR
277 */
278u8 __iomem *
279nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
280		 unsigned long size, struct nfp_cpp_area **area)
281{
282	u8 __iomem *res;
283
284	*area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
285	if (!*area)
286		goto err_eio;
287
288	res = nfp_cpp_area_iomem(*area);
289	if (!res)
290		goto err_release_free;
291
292	return res;
293
294err_release_free:
295	nfp_cpp_area_release_free(*area);
296err_eio:
297	return (u8 __iomem *)ERR_PTR(-EIO);
298}
~/ Read-only file preview.