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