1 /* 2 * Copyright (C) 2015-2017 Netronome Systems, Inc. 3 * 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. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 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. 23 * 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 31 * SOFTWARE. 32 */ 33 34 /* 35 * nfp_resource.c 36 * Author: Jakub Kicinski <jakub.kicinski@netronome.com> 37 * Jason McMullan <jason.mcmullan@netronome.com> 38 */ 39 #include <linux/delay.h> 40 #include <linux/kernel.h> 41 #include <linux/slab.h> 42 43 #include "crc32.h" 44 #include "nfp.h" 45 #include "nfp_cpp.h" 46 #include "nfp6000/nfp6000.h" 47 48 #define NFP_RESOURCE_TBL_TARGET NFP_CPP_TARGET_MU 49 #define NFP_RESOURCE_TBL_BASE 0x8100000000ULL 50 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 */ 54 55 #define NFP_RESOURCE_ENTRY_NAME_SZ 8 56 57 /** 58 * struct nfp_resource_entry - Resource table entry 59 * @owner: NFP CPP Lock, interface owner 60 * @key: NFP CPP Lock, posix_crc32(name, 8) 61 * @region: Memory region descriptor 62 * @name: ASCII, zero padded name 63 * @reserved 64 * @cpp_action: CPP Action 65 * @cpp_token: CPP Token 66 * @cpp_target: CPP Target ID 67 * @page_offset: 256-byte page offset into target's CPP address 68 * @page_size: size, in 256-byte pages 69 */ 70 struct nfp_resource_entry { 71 struct nfp_resource_entry_mutex { 72 u32 owner; 73 u32 key; 74 } mutex; 75 struct nfp_resource_entry_region { 76 u8 name[NFP_RESOURCE_ENTRY_NAME_SZ]; 77 u8 reserved[5]; 78 u8 cpp_action; 79 u8 cpp_token; 80 u8 cpp_target; 81 u32 page_offset; 82 u32 page_size; 83 } region; 84 }; 85 86 #define NFP_RESOURCE_TBL_SIZE 4096 87 #define NFP_RESOURCE_TBL_ENTRIES (NFP_RESOURCE_TBL_SIZE / \ 88 sizeof(struct nfp_resource_entry)) 89 90 struct nfp_resource { 91 char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1]; 92 u32 cpp_id; 93 u64 addr; 94 u64 size; 95 struct nfp_cpp_mutex *mutex; 96 }; 97 98 static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res) 99 { 100 char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ] = {}; 101 struct nfp_resource_entry entry; 102 u32 cpp_id, key; 103 int ret, i; 104 105 cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0); /* Atomic read */ 106 107 strncpy(name_pad, res->name, sizeof(name_pad)); 108 109 /* Search for a matching entry */ 110 if (!memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) { 111 nfp_err(cpp, "Grabbing device lock not supported\n"); 112 return -EOPNOTSUPP; 113 } 114 key = crc32_posix(name_pad, sizeof(name_pad)); 115 116 for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) { 117 u64 addr = NFP_RESOURCE_TBL_BASE + 118 sizeof(struct nfp_resource_entry) * i; 119 120 ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry)); 121 if (ret != sizeof(entry)) 122 return -EIO; 123 124 if (entry.mutex.key != key) 125 continue; 126 127 /* Found key! */ 128 res->mutex = 129 nfp_cpp_mutex_alloc(cpp, 130 NFP_RESOURCE_TBL_TARGET, addr, key); 131 res->cpp_id = NFP_CPP_ID(entry.region.cpp_target, 132 entry.region.cpp_action, 133 entry.region.cpp_token); 134 res->addr = (u64)entry.region.page_offset << 8; 135 res->size = (u64)entry.region.page_size << 8; 136 137 return 0; 138 } 139 140 return -ENOENT; 141 } 142 143 static int 144 nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res, 145 struct nfp_cpp_mutex *dev_mutex) 146 { 147 int err; 148 149 if (nfp_cpp_mutex_lock(dev_mutex)) 150 return -EINVAL; 151 152 err = nfp_cpp_resource_find(cpp, res); 153 if (err) 154 goto err_unlock_dev; 155 156 err = nfp_cpp_mutex_trylock(res->mutex); 157 if (err) 158 goto err_res_mutex_free; 159 160 nfp_cpp_mutex_unlock(dev_mutex); 161 162 return 0; 163 164 err_res_mutex_free: 165 nfp_cpp_mutex_free(res->mutex); 166 err_unlock_dev: 167 nfp_cpp_mutex_unlock(dev_mutex); 168 169 return err; 170 } 171 172 /** 173 * nfp_resource_acquire() - Acquire a resource handle 174 * @cpp: NFP CPP handle 175 * @name: Name of the resource 176 * 177 * NOTE: This function locks the acquired resource 178 * 179 * Return: NFP Resource handle, or ERR_PTR() 180 */ 181 struct nfp_resource * 182 nfp_resource_acquire(struct nfp_cpp *cpp, const char *name) 183 { 184 unsigned long warn_at = jiffies + NFP_MUTEX_WAIT_FIRST_WARN * HZ; 185 unsigned long err_at = jiffies + NFP_MUTEX_WAIT_ERROR * HZ; 186 struct nfp_cpp_mutex *dev_mutex; 187 struct nfp_resource *res; 188 int err; 189 190 res = kzalloc(sizeof(*res), GFP_KERNEL); 191 if (!res) 192 return ERR_PTR(-ENOMEM); 193 194 strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ); 195 196 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET, 197 NFP_RESOURCE_TBL_BASE, 198 NFP_RESOURCE_TBL_KEY); 199 if (!dev_mutex) { 200 kfree(res); 201 return ERR_PTR(-ENOMEM); 202 } 203 204 for (;;) { 205 err = nfp_resource_try_acquire(cpp, res, dev_mutex); 206 if (!err) 207 break; 208 if (err != -EBUSY) 209 goto err_free; 210 211 err = msleep_interruptible(1); 212 if (err != 0) { 213 err = -ERESTARTSYS; 214 goto err_free; 215 } 216 217 if (time_is_before_eq_jiffies(warn_at)) { 218 warn_at = jiffies + NFP_MUTEX_WAIT_NEXT_WARN * HZ; 219 nfp_warn(cpp, "Warning: waiting for NFP resource %s\n", 220 name); 221 } 222 if (time_is_before_eq_jiffies(err_at)) { 223 nfp_err(cpp, "Error: resource %s timed out\n", name); 224 err = -EBUSY; 225 goto err_free; 226 } 227 } 228 229 nfp_cpp_mutex_free(dev_mutex); 230 231 return res; 232 233 err_free: 234 nfp_cpp_mutex_free(dev_mutex); 235 kfree(res); 236 return ERR_PTR(err); 237 } 238 239 /** 240 * nfp_resource_release() - Release a NFP Resource handle 241 * @res: NFP Resource handle 242 * 243 * NOTE: This function implictly unlocks the resource handle 244 */ 245 void nfp_resource_release(struct nfp_resource *res) 246 { 247 nfp_cpp_mutex_unlock(res->mutex); 248 nfp_cpp_mutex_free(res->mutex); 249 kfree(res); 250 } 251 252 /** 253 * nfp_resource_cpp_id() - Return the cpp_id of a resource handle 254 * @res: NFP Resource handle 255 * 256 * Return: NFP CPP ID 257 */ 258 u32 nfp_resource_cpp_id(struct nfp_resource *res) 259 { 260 return res->cpp_id; 261 } 262 263 /** 264 * nfp_resource_name() - Return the name of a resource handle 265 * @res: NFP Resource handle 266 * 267 * Return: const char pointer to the name of the resource 268 */ 269 const char *nfp_resource_name(struct nfp_resource *res) 270 { 271 return res->name; 272 } 273 274 /** 275 * nfp_resource_address() - Return the address of a resource handle 276 * @res: NFP Resource handle 277 * 278 * Return: Address of the resource 279 */ 280 u64 nfp_resource_address(struct nfp_resource *res) 281 { 282 return res->addr; 283 } 284 285 /** 286 * nfp_resource_size() - Return the size in bytes of a resource handle 287 * @res: NFP Resource handle 288 * 289 * Return: Size of the resource in bytes 290 */ 291 u64 nfp_resource_size(struct nfp_resource *res) 292 { 293 return res->size; 294 } 295