1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 Netronome Systems, Inc. 3 * All rights reserved. 4 */ 5 6 #include <stdio.h> 7 #include <time.h> 8 #include <endian.h> 9 10 #include <rte_string_fns.h> 11 12 #include "nfp_cpp.h" 13 #include "nfp6000/nfp6000.h" 14 #include "nfp_resource.h" 15 #include "nfp_crc.h" 16 17 #define NFP_RESOURCE_TBL_TARGET NFP_CPP_TARGET_MU 18 #define NFP_RESOURCE_TBL_BASE 0x8100000000ULL 19 20 /* NFP Resource Table self-identifier */ 21 #define NFP_RESOURCE_TBL_NAME "nfp.res" 22 #define NFP_RESOURCE_TBL_KEY 0x00000000 /* Special key for entry 0 */ 23 24 #define NFP_RESOURCE_ENTRY_NAME_SZ 8 25 26 /* 27 * struct nfp_resource_entry - Resource table entry 28 * @owner: NFP CPP Lock, interface owner 29 * @key: NFP CPP Lock, posix_crc32(name, 8) 30 * @region: Memory region descriptor 31 * @name: ASCII, zero padded name 32 * @reserved 33 * @cpp_action: CPP Action 34 * @cpp_token: CPP Token 35 * @cpp_target: CPP Target ID 36 * @page_offset: 256-byte page offset into target's CPP address 37 * @page_size: size, in 256-byte pages 38 */ 39 struct nfp_resource_entry { 40 struct nfp_resource_entry_mutex { 41 uint32_t owner; 42 uint32_t key; 43 } mutex; 44 struct nfp_resource_entry_region { 45 uint8_t name[NFP_RESOURCE_ENTRY_NAME_SZ]; 46 uint8_t reserved[5]; 47 uint8_t cpp_action; 48 uint8_t cpp_token; 49 uint8_t cpp_target; 50 uint32_t page_offset; 51 uint32_t page_size; 52 } region; 53 }; 54 55 #define NFP_RESOURCE_TBL_SIZE 4096 56 #define NFP_RESOURCE_TBL_ENTRIES (int)(NFP_RESOURCE_TBL_SIZE / \ 57 sizeof(struct nfp_resource_entry)) 58 59 struct nfp_resource { 60 char name[NFP_RESOURCE_ENTRY_NAME_SZ + 1]; 61 uint32_t cpp_id; 62 uint64_t addr; 63 uint64_t size; 64 struct nfp_cpp_mutex *mutex; 65 }; 66 67 static int 68 nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res) 69 { 70 char name_pad[NFP_RESOURCE_ENTRY_NAME_SZ + 2]; 71 struct nfp_resource_entry entry; 72 uint32_t cpp_id, key; 73 int ret, i; 74 75 cpp_id = NFP_CPP_ID(NFP_RESOURCE_TBL_TARGET, 3, 0); /* Atomic read */ 76 77 memset(name_pad, 0, sizeof(name_pad)); 78 strlcpy(name_pad, res->name, sizeof(name_pad)); 79 80 /* Search for a matching entry */ 81 if (!memcmp(name_pad, NFP_RESOURCE_TBL_NAME "\0\0\0\0\0\0\0\0", 8)) { 82 printf("Grabbing device lock not supported\n"); 83 return -EOPNOTSUPP; 84 } 85 key = nfp_crc32_posix(name_pad, NFP_RESOURCE_ENTRY_NAME_SZ); 86 87 for (i = 0; i < NFP_RESOURCE_TBL_ENTRIES; i++) { 88 uint64_t addr = NFP_RESOURCE_TBL_BASE + 89 sizeof(struct nfp_resource_entry) * i; 90 91 ret = nfp_cpp_read(cpp, cpp_id, addr, &entry, sizeof(entry)); 92 if (ret != sizeof(entry)) 93 return -EIO; 94 95 if (entry.mutex.key != key) 96 continue; 97 98 /* Found key! */ 99 res->mutex = 100 nfp_cpp_mutex_alloc(cpp, 101 NFP_RESOURCE_TBL_TARGET, addr, key); 102 res->cpp_id = NFP_CPP_ID(entry.region.cpp_target, 103 entry.region.cpp_action, 104 entry.region.cpp_token); 105 res->addr = ((uint64_t)entry.region.page_offset) << 8; 106 res->size = (uint64_t)entry.region.page_size << 8; 107 return 0; 108 } 109 110 return -ENOENT; 111 } 112 113 static int 114 nfp_resource_try_acquire(struct nfp_cpp *cpp, struct nfp_resource *res, 115 struct nfp_cpp_mutex *dev_mutex) 116 { 117 int err; 118 119 if (nfp_cpp_mutex_lock(dev_mutex)) 120 return -EINVAL; 121 122 err = nfp_cpp_resource_find(cpp, res); 123 if (err) 124 goto err_unlock_dev; 125 126 err = nfp_cpp_mutex_trylock(res->mutex); 127 if (err) 128 goto err_res_mutex_free; 129 130 nfp_cpp_mutex_unlock(dev_mutex); 131 132 return 0; 133 134 err_res_mutex_free: 135 nfp_cpp_mutex_free(res->mutex); 136 err_unlock_dev: 137 nfp_cpp_mutex_unlock(dev_mutex); 138 139 return err; 140 } 141 142 /* 143 * nfp_resource_acquire() - Acquire a resource handle 144 * @cpp: NFP CPP handle 145 * @name: Name of the resource 146 * 147 * NOTE: This function locks the acquired resource 148 * 149 * Return: NFP Resource handle, or ERR_PTR() 150 */ 151 struct nfp_resource * 152 nfp_resource_acquire(struct nfp_cpp *cpp, const char *name) 153 { 154 struct nfp_cpp_mutex *dev_mutex; 155 struct nfp_resource *res; 156 int err; 157 struct timespec wait; 158 int count; 159 160 res = malloc(sizeof(*res)); 161 if (!res) 162 return NULL; 163 164 memset(res, 0, sizeof(*res)); 165 166 strncpy(res->name, name, NFP_RESOURCE_ENTRY_NAME_SZ); 167 168 dev_mutex = nfp_cpp_mutex_alloc(cpp, NFP_RESOURCE_TBL_TARGET, 169 NFP_RESOURCE_TBL_BASE, 170 NFP_RESOURCE_TBL_KEY); 171 if (!dev_mutex) { 172 free(res); 173 return NULL; 174 } 175 176 wait.tv_sec = 0; 177 wait.tv_nsec = 1000000; 178 count = 0; 179 180 for (;;) { 181 err = nfp_resource_try_acquire(cpp, res, dev_mutex); 182 if (!err) 183 break; 184 if (err != -EBUSY) 185 goto err_free; 186 187 if (count++ > 1000) { 188 printf("Error: resource %s timed out\n", name); 189 err = -EBUSY; 190 goto err_free; 191 } 192 193 nanosleep(&wait, NULL); 194 } 195 196 nfp_cpp_mutex_free(dev_mutex); 197 198 return res; 199 200 err_free: 201 nfp_cpp_mutex_free(dev_mutex); 202 free(res); 203 return NULL; 204 } 205 206 /* 207 * nfp_resource_release() - Release a NFP Resource handle 208 * @res: NFP Resource handle 209 * 210 * NOTE: This function implicitly unlocks the resource handle 211 */ 212 void 213 nfp_resource_release(struct nfp_resource *res) 214 { 215 nfp_cpp_mutex_unlock(res->mutex); 216 nfp_cpp_mutex_free(res->mutex); 217 free(res); 218 } 219 220 /* 221 * nfp_resource_cpp_id() - Return the cpp_id of a resource handle 222 * @res: NFP Resource handle 223 * 224 * Return: NFP CPP ID 225 */ 226 uint32_t 227 nfp_resource_cpp_id(const struct nfp_resource *res) 228 { 229 return res->cpp_id; 230 } 231 232 /* 233 * nfp_resource_name() - Return the name of a resource handle 234 * @res: NFP Resource handle 235 * 236 * Return: const char pointer to the name of the resource 237 */ 238 const char 239 *nfp_resource_name(const struct nfp_resource *res) 240 { 241 return res->name; 242 } 243 244 /* 245 * nfp_resource_address() - Return the address of a resource handle 246 * @res: NFP Resource handle 247 * 248 * Return: Address of the resource 249 */ 250 uint64_t 251 nfp_resource_address(const struct nfp_resource *res) 252 { 253 return res->addr; 254 } 255 256 /* 257 * nfp_resource_size() - Return the size in bytes of a resource handle 258 * @res: NFP Resource handle 259 * 260 * Return: Size of the resource in bytes 261 */ 262 uint64_t 263 nfp_resource_size(const struct nfp_resource *res) 264 { 265 return res->size; 266 } 267