2 * Copyright (C) 2015-2017 Netronome Systems, Inc.
4 * This software is dual licensed under the GNU General License Version 2,
5 * June 1991 as shown in the file COPYING in the top-level directory of this
6 * source tree or the BSD 2-Clause License provided below. You have the
7 * option to license this software under the complete terms of either license.
9 * The BSD 2-Clause License:
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
15 * 1. Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
19 * 2. Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 * Author: Jakub Kicinski <jakub.kicinski@netronome.com>
37 * Jason McMullan <jason.mcmullan@netronome.com>
39 #include <linux/delay.h>
40 #include <linux/kernel.h>
41 #include <linux/slab.h>
46 #include "nfp6000/nfp6000.h"
48 #define NFP_RESOURCE_TBL_TARGET NFP_CPP_TARGET_MU
49 #define NFP_RESOURCE_TBL_BASE 0x8100000000ULL
51 /* NFP Resource Table self-identifier */
52 #define NFP_RESOURCE_TBL_NAME "nfp.res"
53 #define NFP_RESOURCE_TBL_KEY 0x00000000 /* Special key for entry 0 */
55 #define NFP_RESOURCE_ENTRY_NAME_SZ 8
58 * struct nfp_resource_entry - Resource table entry
59 * @mutex: NFP CPP Lock
60 * @mutex.owner: NFP CPP Lock, interface owner
61 * @mutex.key: NFP CPP Lock, posix_crc32(name, 8)
62 * @region: Memory region descriptor
63 * @region.name: ASCII, zero padded name
64 * @region.reserved: padding
65 * @region.cpp_action: CPP Action
66 * @region.cpp_token: CPP Token
67 * @region.cpp_target: CPP Target ID
68 * @region.page_offset: 256-byte page offset into target's CPP address
69 * @region.page_size: size, in 256-byte pages
71 struct nfp_resource_entry {
72 struct nfp_resource_entry_mutex {
76 struct nfp_resource_entry_region {
77 u8 name[NFP_RESOURCE_ENTRY_NAME_SZ];
87 #define NFP_RESOURCE_TBL_SIZE 4096
88 #define NFP_RESOURCE_TBL_ENTRIES (NFP_RESOURCE_TBL_SIZE / \
89 sizeof(struct nfp_resource_entry))
92 char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1];
96 struct nfp_cpp_mutex *mutex;
99 static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
101 struct nfp_resource_entry entry;
105 cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0); /* Atomic read */
107 /* Search for a matching entry */
108 if (!strcmp(res->name, NFP_RESOURCE_TBL_NAME)) {
109 nfp_err(cpp, "Grabbing device lock not supported\n");
112 key = crc32_posix(res->name, NFP_RESOURCE_ENTRY_NAME_SZ);
114 for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
115 u64 addr = NFP_RESOURCE_TBL_BASE +
116 sizeof(struct nfp_resource_entry) * i;
118 ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry));
119 if (ret != sizeof(entry))
122 if (entry.mutex.key != key)
127 nfp_cpp_mutex_alloc(cpp,
128 NFP_RESOURCE_TBL_TARGET, addr, key);
129 res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
130 entry.region.cpp_action,
131 entry.region.cpp_token);
132 res->addr = (u64)entry.region.page_offset << 8;
133 res->size = (u64)entry.region.page_size << 8;
142 nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res,
143 struct nfp_cpp_mutex *dev_mutex)
147 if (nfp_cpp_mutex_lock(dev_mutex))
150 err = nfp_cpp_resource_find(cpp, res);
154 err = nfp_cpp_mutex_trylock(res->mutex);
156 goto err_res_mutex_free;
158 nfp_cpp_mutex_unlock(dev_mutex);
163 nfp_cpp_mutex_free(res->mutex);
165 nfp_cpp_mutex_unlock(dev_mutex);
171 * nfp_resource_acquire() - Acquire a resource handle
172 * @cpp: NFP CPP handle
173 * @name: Name of the resource
175 * NOTE: This function locks the acquired resource
177 * Return: NFP Resource handle, or ERR_PTR()
179 struct nfp_resource *
180 nfp_resource_acquire(struct nfp_cpp *cpp, const char *name)
182 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
183 unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ;
184 struct nfp_cpp_mutex *dev_mutex;
185 struct nfp_resource *res;
188 res = kzalloc(sizeof(*res), GFP_KERNEL);
190 return ERR_PTR(-ENOMEM);
192 strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ);
194 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
195 NFP_RESOURCE_TBL_BASE,
196 NFP_RESOURCE_TBL_KEY);
199 return ERR_PTR(-ENOMEM);
203 err = nfp_resource_try_acquire(cpp, res, dev_mutex);
209 err = msleep_interruptible(1);
215 if (time_is_before_eq_jiffies(warn_at)) {
216 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
217 nfp_warn(cpp, "Warning: waiting for NFP resource %s\n",
220 if (time_is_before_eq_jiffies(err_at)) {
221 nfp_err(cpp, "Error: resource %s timed out\n", name);
227 nfp_cpp_mutex_free(dev_mutex);
232 nfp_cpp_mutex_free(dev_mutex);
238 * nfp_resource_release() - Release a NFP Resource handle
239 * @res: NFP Resource handle
241 * NOTE: This function implictly unlocks the resource handle
243 void nfp_resource_release(struct nfp_resource *res)
245 nfp_cpp_mutex_unlock(res->mutex);
246 nfp_cpp_mutex_free(res->mutex);
251 * nfp_resource_wait() - Wait for resource to appear
252 * @cpp: NFP CPP handle
253 * @name: Name of the resource
254 * @secs: Number of seconds to wait
256 * Wait for resource to appear in the resource table, grab and release
257 * its lock. The wait is jiffies-based, don't expect fine granularity.
259 * Return: 0 on success, errno otherwise.
261 int nfp_resource_wait(struct nfp_cpp *cpp, const char *name, unsigned int secs)
263 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ;
264 unsigned long err_at = jiffies + secs * HZ;
265 struct nfp_resource *res;
268 res = nfp_resource_acquire(cpp, name);
270 nfp_resource_release(res);
274 if (PTR_ERR(res) != -ENOENT) {
275 nfp_err(cpp, "error waiting for resource %s: %ld\n",
279 if (time_is_before_eq_jiffies(err_at)) {
280 nfp_err(cpp, "timeout waiting for resource %s\n", name);
283 if (time_is_before_eq_jiffies(warn_at)) {
284 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ;
285 nfp_info(cpp, "waiting for NFP resource %s\n", name);
287 if (msleep_interruptible(10)) {
288 nfp_err(cpp, "wait for resource %s interrupted\n",
296 * nfp_resource_cpp_id() - Return the cpp_id of a resource handle
297 * @res: NFP Resource handle
301 u32 nfp_resource_cpp_id(struct nfp_resource *res)
307 * nfp_resource_name() - Return the name of a resource handle
308 * @res: NFP Resource handle
310 * Return: const char pointer to the name of the resource
312 const char *nfp_resource_name(struct nfp_resource *res)
318 * nfp_resource_address() - Return the address of a resource handle
319 * @res: NFP Resource handle
321 * Return: Address of the resource
323 u64 nfp_resource_address(struct nfp_resource *res)
329 * nfp_resource_size() - Return the size in bytes of a resource handle
330 * @res: NFP Resource handle
332 * Return: Size of the resource in bytes
334 u64 nfp_resource_size(struct nfp_resource *res)
340 * nfp_resource_table_init() - Run initial checks on the resource table
341 * @cpp: NFP CPP handle
343 * Start-of-day init procedure for resource table. Must be called before
344 * any local resource table users may exist.
346 * Return: 0 on success, -errno on failure
348 int nfp_resource_table_init(struct nfp_cpp *cpp)
350 struct nfp_cpp_mutex *dev_mutex;
353 err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET,
354 NFP_RESOURCE_TBL_BASE);
356 nfp_err(cpp, "Error: failed to reclaim resource table mutex\n");
360 nfp_warn(cpp, "Warning: busted main resource table mutex\n");
362 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET,
363 NFP_RESOURCE_TBL_BASE,
364 NFP_RESOURCE_TBL_KEY);
368 if (nfp_cpp_mutex_lock(dev_mutex)) {
369 nfp_err(cpp, "Error: failed to claim resource table mutex\n");
370 nfp_cpp_mutex_free(dev_mutex);
374 /* Resource 0 is the dev_mutex, start from 1 */
375 for (i = 1; i < NFP_RESOURCE_TBL_ENTRIES; i++) {
376 u64 addr = NFP_RESOURCE_TBL_BASE +
377 sizeof(struct nfp_resource_entry) * i;
379 err = nfp_cpp_mutex_reclaim(cpp, NFP_RESOURCE_TBL_TARGET, addr);
382 "Error: failed to reclaim resource %d mutex\n",
387 nfp_warn(cpp, "Warning: busted resource %d mutex\n", i);
392 nfp_cpp_mutex_unlock(dev_mutex);
393 nfp_cpp_mutex_free(dev_mutex);