1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
6 * Author: Jakub Kicinski <jakub.kicinski@netronome.com>
7 * Jason McMullan <jason.mcmullan@netronome.com>
9 #include <linux/delay.h>
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
16 #include "nfp6000/nfp6000.h"
18 #define NFP_RESOURCE_TBL_TARGET NFP_CPP_TARGET_MU
19 #define NFP_RESOURCE_TBL_BASE 0x8100000000ULL
21 /* NFP Resource Table self-identifier */
22 #define NFP_RESOURCE_TBL_NAME "nfp.res"
23 #define NFP_RESOURCE_TBL_KEY 0x00000000 /* Special key for entry 0 */
25 #define NFP_RESOURCE_ENTRY_NAME_SZ 8
28 * struct nfp_resource_entry - Resource table entry
29 * @mutex: NFP CPP Lock
30 * @mutex.owner: NFP CPP Lock, interface owner
31 * @mutex.key: NFP CPP Lock, posix_crc32(name, 8)
32 * @region: Memory region descriptor
33 * @region.name: ASCII, zero padded name
34 * @region.reserved: padding
35 * @region.cpp_action: CPP Action
36 * @region.cpp_token: CPP Token
37 * @region.cpp_target: CPP Target ID
38 * @region.page_offset: 256-byte page offset into target's CPP address
39 * @region.page_size: size, in 256-byte pages
41 struct nfp_resource_entry {
42 struct nfp_resource_entry_mutex {
46 struct nfp_resource_entry_region {
47 u8 name[NFP_RESOURCE_ENTRY_NAME_SZ];
57 #define NFP_RESOURCE_TBL_SIZE 4096
58 #define NFP_RESOURCE_TBL_ENTRIES (NFP_RESOURCE_TBL_SIZE / \
59 sizeof(struct nfp_resource_entry))
62 char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
66 struct nfp_cpp_mutex *mutex;
69 static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
71 struct nfp_resource_entry entry;
75 cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0); /* Atomic read */
77 /* Search for a matching entry */
78 if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) {
79 nfp_err(cpp, "Grabbing device lock not supported\n");
82 key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ);
84 for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
85 u64 addr = NFP_RESOURCE_TBL_BASE +
86 sizeof(struct nfp_resource_entry) * i;
88 ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
89 if (ret != sizeof(entry))
92 if (entry.mutex.key != key)
97 nfp_cpp_mutex_alloc(cpp,
98 NFP_RESOURCE_TBL_TARGET, addr, key);
99 res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
100 entry.region.cpp_action,
101 entry.region.cpp_token);
102 res->addr = (u64)entry.region.page_offset << 8;
103 res->size = (u64)entry.region.page_size << 8;
112 nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
113 struct nfp_cpp_mutex *dev_mutex)
117 if (nfp_cpp_mutex_lock(dev_mutex))
120 err = nfp_cpp_resource_find(cpp, res);
124 err = nfp_cpp_mutex_trylock(res->mutex);
126 goto err_res_mutex_free;
128 nfp_cpp_mutex_unlock(dev_mutex);
133 nfp_cpp_mutex_free(res->mutex);
135 nfp_cpp_mutex_unlock(dev_mutex);
141 * nfp_resource_acquire() - Acquire a resource handle
142 * @cpp: NFP CPP handle
143 * @name: Name of the resource
145 * NOTE: This function locks the acquired resource
147 * Return: NFP Resource handle, or ERR_PTR()
149 struct nfp_resource *
150 nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
152 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
153 unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ;
154 struct nfp_cpp_mutex *dev_mutex;
155 struct nfp_resource *res;
158 res = kzalloc(sizeof(*res), GFP_KERNEL);
160 return ERR_PTR(-ENOMEM);
162 strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
164 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
165 NFP_RESOURCE_TBL_BASE,
166 NFP_RESOURCE_TBL_KEY);
169 return ERR_PTR(-ENOMEM);
173 err = nfp_resource_try_acquire(cpp, res, dev_mutex);
179 err = msleep_interruptible(1);
185 if (time_is_before_eq_jiffies(warn_at)) {
186 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
187 nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
190 if (time_is_before_eq_jiffies(err_at)) {
191 nfp_err(cpp, "Error: resource %s timed out\n", name);
197 nfp_cpp_mutex_free(dev_mutex);
202 nfp_cpp_mutex_free(dev_mutex);
208 * nfp_resource_release() - Release a NFP Resource handle
209 * @res: NFP Resource handle
211 * NOTE: This function implictly unlocks the resource handle
213 void nfp_resource_release(struct nfp_resource *res)
215 nfp_cpp_mutex_unlock(res->mutex);
216 nfp_cpp_mutex_free(res->mutex);
221 * nfp_resource_wait() - Wait for resource to appear
222 * @cpp: NFP CPP handle
223 * @name: Name of the resource
224 * @secs: Number of seconds to wait
226 * Wait for resource to appear in the resource table, grab and release
227 * its lock. The wait is jiffies-based, don't expect fine granularity.
229 * Return: 0 on success, errno otherwise.
231 int nfp_resource_wait(struct nfp_cpp *cpp, const char *name, unsigned int secs)
233 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
234 unsigned long err_at = jiffies + secs * HZ;
235 struct nfp_resource *res;
238 res = nfp_resource_acquire(cpp, name);
240 nfp_resource_release(res);
244 if (PTR_ERR(res) != -ENOENT) {
245 nfp_err(cpp, "error waiting for resource %s: %ld\n",
249 if (time_is_before_eq_jiffies(err_at)) {
250 nfp_err(cpp, "timeout waiting for resource %s\n", name);
253 if (time_is_before_eq_jiffies(warn_at)) {
254 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
255 nfp_info(cpp, "waiting for NFP resource %s\n", name);
257 if (msleep_interruptible(10)) {
258 nfp_err(cpp, "wait for resource %s interrupted\n",
266 * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
267 * @res: NFP Resource handle
271 u32 nfp_resource_cpp_id(struct nfp_resource *res)
277 * nfp_resource_name() - Return the name of a resource handle
278 * @res: NFP Resource handle
280 * Return: const char pointer to the name of the resource
282 const char *nfp_resource_name(struct nfp_resource *res)
288 * nfp_resource_address() - Return the address of a resource handle
289 * @res: NFP Resource handle
291 * Return: Address of the resource
293 u64 nfp_resource_address(struct nfp_resource *res)
299 * nfp_resource_size() - Return the size in bytes of a resource handle
300 * @res: NFP Resource handle
302 * Return: Size of the resource in bytes
304 u64 nfp_resource_size(struct nfp_resource *res)
310 * nfp_resource_table_init() - Run initial checks on the resource table
311 * @cpp: NFP CPP handle
313 * Start-of-day init procedure for resource table. Must be called before
314 * any local resource table users may exist.
316 * Return: 0 on success, -errno on failure
318 int nfp_resource_table_init(struct nfp_cpp *cpp)
320 struct nfp_cpp_mutex *dev_mutex;
323 err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET,
324 NFP_RESOURCE_TBL_BASE);
326 nfp_err(cpp, "Error: failed to reclaim resource table mutex\n");
330 nfp_warn(cpp, "Warning: busted main resource table mutex\n");
332 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
333 NFP_RESOURCE_TBL_BASE,
334 NFP_RESOURCE_TBL_KEY);
338 if (nfp_cpp_mutex_lock(dev_mutex)) {
339 nfp_err(cpp, "Error: failed to claim resource table mutex\n");
340 nfp_cpp_mutex_free(dev_mutex);
344 /* Resource 0 is the dev_mutex, start from 1 */
345 for (i = 1; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
346 u64 addr = NFP_RESOURCE_TBL_BASE +
347 sizeof(struct nfp_resource_entry) * i;
349 err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET, addr);
352 "Error: failed to reclaim resource %d mutex\n",
357 nfp_warn(cpp, "Warning: busted resource %d mutex\n", i);
362 nfp_cpp_mutex_unlock(dev_mutex);
363 nfp_cpp_mutex_free(dev_mutex);