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