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_rtsym.c 36 * Interface for accessing run-time symbol table 37 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com> 38 * Jason McMullan <jason.mcmullan@netronome.com> 39 * Espen Skoglund <espen.skoglund@netronome.com> 40 * Francois H. Theron <francois.theron@netronome.com> 41 */ 42 #include <linux/kernel.h> 43 #include <linux/module.h> 44 #include <linux/slab.h> 45 #include <linux/io-64-nonatomic-hi-lo.h> 46 47 #include "nfp.h" 48 #include "nfp_cpp.h" 49 #include "nfp_nffw.h" 50 #include "nfp6000/nfp6000.h" 51 52 /* These need to match the linker */ 53 #define SYM_TGT_LMEM 0 54 #define SYM_TGT_EMU_CACHE 0x17 55 56 struct nfp_rtsym_entry { 57 u8 type; 58 u8 target; 59 u8 island; 60 u8 addr_hi; 61 __le32 addr_lo; 62 __le16 name; 63 u8 menum; 64 u8 size_hi; 65 __le32 size_lo; 66 }; 67 68 struct nfp_rtsym_table { 69 struct nfp_cpp *cpp; 70 int num; 71 char *strtab; 72 struct nfp_rtsym symtab[]; 73 }; 74 75 static int nfp_meid(u8 island_id, u8 menum) 76 { 77 return (island_id & 0x3F) == island_id && menum < 12 ? 78 (island_id << 4) | (menum + 4) : -1; 79 } 80 81 static void 82 nfp_rtsym_sw_entry_init(struct nfp_rtsym_table *cache, u32 strtab_size, 83 struct nfp_rtsym *sw, struct nfp_rtsym_entry *fw) 84 { 85 sw->type = fw->type; 86 sw->name = cache->strtab + le16_to_cpu(fw->name) % strtab_size; 87 sw->addr = ((u64)fw->addr_hi << 32) | le32_to_cpu(fw->addr_lo); 88 sw->size = ((u64)fw->size_hi << 32) | le32_to_cpu(fw->size_lo); 89 90 switch (fw->target) { 91 case SYM_TGT_LMEM: 92 sw->target = NFP_RTSYM_TARGET_LMEM; 93 break; 94 case SYM_TGT_EMU_CACHE: 95 sw->target = NFP_RTSYM_TARGET_EMU_CACHE; 96 break; 97 default: 98 sw->target = fw->target; 99 break; 100 } 101 102 if (fw->menum != 0xff) 103 sw->domain = nfp_meid(fw->island, fw->menum); 104 else if (fw->island != 0xff) 105 sw->domain = fw->island; 106 else 107 sw->domain = -1; 108 } 109 110 struct nfp_rtsym_table *nfp_rtsym_table_read(struct nfp_cpp *cpp) 111 { 112 struct nfp_rtsym_table *rtbl; 113 const struct nfp_mip *mip; 114 115 mip = nfp_mip_open(cpp); 116 rtbl = __nfp_rtsym_table_read(cpp, mip); 117 nfp_mip_close(mip); 118 119 return rtbl; 120 } 121 122 struct nfp_rtsym_table * 123 __nfp_rtsym_table_read(struct nfp_cpp *cpp, const struct nfp_mip *mip) 124 { 125 const u32 dram = NFP_CPP_ID(NFP_CPP_TARGET_MU, NFP_CPP_ACTION_RW, 0) | 126 NFP_ISL_EMEM0; 127 u32 strtab_addr, symtab_addr, strtab_size, symtab_size; 128 struct nfp_rtsym_entry *rtsymtab; 129 struct nfp_rtsym_table *cache; 130 int err, n, size; 131 132 if (!mip) 133 return NULL; 134 135 nfp_mip_strtab(mip, &strtab_addr, &strtab_size); 136 nfp_mip_symtab(mip, &symtab_addr, &symtab_size); 137 138 if (!symtab_size || !strtab_size || symtab_size % sizeof(*rtsymtab)) 139 return NULL; 140 141 /* Align to 64 bits */ 142 symtab_size = round_up(symtab_size, 8); 143 strtab_size = round_up(strtab_size, 8); 144 145 rtsymtab = kmalloc(symtab_size, GFP_KERNEL); 146 if (!rtsymtab) 147 return NULL; 148 149 size = sizeof(*cache); 150 size += symtab_size / sizeof(*rtsymtab) * sizeof(struct nfp_rtsym); 151 size += strtab_size + 1; 152 cache = kmalloc(size, GFP_KERNEL); 153 if (!cache) 154 goto exit_free_rtsym_raw; 155 156 cache->cpp = cpp; 157 cache->num = symtab_size / sizeof(*rtsymtab); 158 cache->strtab = (void *)&cache->symtab[cache->num]; 159 160 err = nfp_cpp_read(cpp, dram, symtab_addr, rtsymtab, symtab_size); 161 if (err != symtab_size) 162 goto exit_free_cache; 163 164 err = nfp_cpp_read(cpp, dram, strtab_addr, cache->strtab, strtab_size); 165 if (err != strtab_size) 166 goto exit_free_cache; 167 cache->strtab[strtab_size] = '\0'; 168 169 for (n = 0; n < cache->num; n++) 170 nfp_rtsym_sw_entry_init(cache, strtab_size, 171 &cache->symtab[n], &rtsymtab[n]); 172 173 kfree(rtsymtab); 174 175 return cache; 176 177 exit_free_cache: 178 kfree(cache); 179 exit_free_rtsym_raw: 180 kfree(rtsymtab); 181 return NULL; 182 } 183 184 /** 185 * nfp_rtsym_count() - Get the number of RTSYM descriptors 186 * @rtbl: NFP RTsym table 187 * 188 * Return: Number of RTSYM descriptors 189 */ 190 int nfp_rtsym_count(struct nfp_rtsym_table *rtbl) 191 { 192 if (!rtbl) 193 return -EINVAL; 194 return rtbl->num; 195 } 196 197 /** 198 * nfp_rtsym_get() - Get the Nth RTSYM descriptor 199 * @rtbl: NFP RTsym table 200 * @idx: Index (0-based) of the RTSYM descriptor 201 * 202 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL 203 */ 204 const struct nfp_rtsym *nfp_rtsym_get(struct nfp_rtsym_table *rtbl, int idx) 205 { 206 if (!rtbl) 207 return NULL; 208 if (idx >= rtbl->num) 209 return NULL; 210 211 return &rtbl->symtab[idx]; 212 } 213 214 /** 215 * nfp_rtsym_lookup() - Return the RTSYM descriptor for a symbol name 216 * @rtbl: NFP RTsym table 217 * @name: Symbol name 218 * 219 * Return: const pointer to a struct nfp_rtsym descriptor, or NULL 220 */ 221 const struct nfp_rtsym * 222 nfp_rtsym_lookup(struct nfp_rtsym_table *rtbl, const char *name) 223 { 224 int n; 225 226 if (!rtbl) 227 return NULL; 228 229 for (n = 0; n < rtbl->num; n++) 230 if (strcmp(name, rtbl->symtab[n].name) == 0) 231 return &rtbl->symtab[n]; 232 233 return NULL; 234 } 235 236 static int 237 nfp_rtsym_to_dest(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, 238 u8 action, u8 token, u64 off, u32 *cpp_id, u64 *addr) 239 { 240 *addr = sym->addr + off; 241 242 if (sym->target == NFP_RTSYM_TARGET_EMU_CACHE) { 243 int locality_off = nfp_cpp_mu_locality_lsb(cpp); 244 245 *addr &= ~(NFP_MU_ADDR_ACCESS_TYPE_MASK << locality_off); 246 *addr |= NFP_MU_ADDR_ACCESS_TYPE_DIRECT << locality_off; 247 248 *cpp_id = NFP_CPP_ISLAND_ID(NFP_CPP_TARGET_MU, action, token, 249 sym->domain); 250 } else if (sym->target < 0) { 251 nfp_err(cpp, "Unhandled RTsym target encoding: %d\n", 252 sym->target); 253 return -EINVAL; 254 } else { 255 *cpp_id = NFP_CPP_ISLAND_ID(sym->target, action, token, 256 sym->domain); 257 } 258 259 return 0; 260 } 261 262 int __nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, 263 u8 action, u8 token, u64 off, void *buf, size_t len) 264 { 265 u32 cpp_id; 266 u64 addr; 267 int err; 268 269 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); 270 if (err) 271 return err; 272 273 return nfp_cpp_read(cpp, cpp_id, addr, buf, len); 274 } 275 276 int nfp_rtsym_read(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, 277 void *buf, size_t len) 278 { 279 return __nfp_rtsym_read(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len); 280 } 281 282 int __nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, 283 u8 action, u8 token, u64 off, u32 *value) 284 { 285 u32 cpp_id; 286 u64 addr; 287 int err; 288 289 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); 290 if (err) 291 return err; 292 293 return nfp_cpp_readl(cpp, cpp_id, addr, value); 294 } 295 296 int nfp_rtsym_readl(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, 297 u32 *value) 298 { 299 return __nfp_rtsym_readl(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); 300 } 301 302 int __nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, 303 u8 action, u8 token, u64 off, u64 *value) 304 { 305 u32 cpp_id; 306 u64 addr; 307 int err; 308 309 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); 310 if (err) 311 return err; 312 313 return nfp_cpp_readq(cpp, cpp_id, addr, value); 314 } 315 316 int nfp_rtsym_readq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, 317 u64 *value) 318 { 319 return __nfp_rtsym_readq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); 320 } 321 322 int __nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, 323 u8 action, u8 token, u64 off, void *buf, size_t len) 324 { 325 u32 cpp_id; 326 u64 addr; 327 int err; 328 329 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); 330 if (err) 331 return err; 332 333 return nfp_cpp_write(cpp, cpp_id, addr, buf, len); 334 } 335 336 int nfp_rtsym_write(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, 337 void *buf, size_t len) 338 { 339 return __nfp_rtsym_write(cpp, sym, NFP_CPP_ACTION_RW, 0, off, buf, len); 340 } 341 342 int __nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, 343 u8 action, u8 token, u64 off, u32 value) 344 { 345 u32 cpp_id; 346 u64 addr; 347 int err; 348 349 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); 350 if (err) 351 return err; 352 353 return nfp_cpp_writel(cpp, cpp_id, addr, value); 354 } 355 356 int nfp_rtsym_writel(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, 357 u32 value) 358 { 359 return __nfp_rtsym_writel(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); 360 } 361 362 int __nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, 363 u8 action, u8 token, u64 off, u64 value) 364 { 365 u32 cpp_id; 366 u64 addr; 367 int err; 368 369 err = nfp_rtsym_to_dest(cpp, sym, action, token, off, &cpp_id, &addr); 370 if (err) 371 return err; 372 373 return nfp_cpp_writeq(cpp, cpp_id, addr, value); 374 } 375 376 int nfp_rtsym_writeq(struct nfp_cpp *cpp, const struct nfp_rtsym *sym, u64 off, 377 u64 value) 378 { 379 return __nfp_rtsym_writeq(cpp, sym, NFP_CPP_ACTION_RW, 0, off, value); 380 } 381 382 /** 383 * nfp_rtsym_read_le() - Read a simple unsigned scalar value from symbol 384 * @rtbl: NFP RTsym table 385 * @name: Symbol name 386 * @error: Poniter to error code (optional) 387 * 388 * Lookup a symbol, map, read it and return it's value. Value of the symbol 389 * will be interpreted as a simple little-endian unsigned value. Symbol can 390 * be 4 or 8 bytes in size. 391 * 392 * Return: value read, on error sets the error and returns ~0ULL. 393 */ 394 u64 nfp_rtsym_read_le(struct nfp_rtsym_table *rtbl, const char *name, 395 int *error) 396 { 397 const struct nfp_rtsym *sym; 398 u32 val32, id; 399 u64 val; 400 int err; 401 402 sym = nfp_rtsym_lookup(rtbl, name); 403 if (!sym) { 404 err = -ENOENT; 405 goto exit; 406 } 407 408 id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain); 409 410 switch (sym->size) { 411 case 4: 412 err = nfp_cpp_readl(rtbl->cpp, id, sym->addr, &val32); 413 val = val32; 414 break; 415 case 8: 416 err = nfp_cpp_readq(rtbl->cpp, id, sym->addr, &val); 417 break; 418 default: 419 nfp_err(rtbl->cpp, 420 "rtsym '%s' unsupported or non-scalar size: %lld\n", 421 name, sym->size); 422 err = -EINVAL; 423 break; 424 } 425 426 exit: 427 if (error) 428 *error = err; 429 430 if (err) 431 return ~0ULL; 432 return val; 433 } 434 435 /** 436 * nfp_rtsym_write_le() - Write an unsigned scalar value to a symbol 437 * @rtbl: NFP RTsym table 438 * @name: Symbol name 439 * @value: Value to write 440 * 441 * Lookup a symbol and write a value to it. Symbol can be 4 or 8 bytes in size. 442 * If 4 bytes then the lower 32-bits of 'value' are used. Value will be 443 * written as simple little-endian unsigned value. 444 * 445 * Return: 0 on success or error code. 446 */ 447 int nfp_rtsym_write_le(struct nfp_rtsym_table *rtbl, const char *name, 448 u64 value) 449 { 450 const struct nfp_rtsym *sym; 451 int err; 452 u32 id; 453 454 sym = nfp_rtsym_lookup(rtbl, name); 455 if (!sym) 456 return -ENOENT; 457 458 id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, sym->domain); 459 460 switch (sym->size) { 461 case 4: 462 err = nfp_cpp_writel(rtbl->cpp, id, sym->addr, value); 463 break; 464 case 8: 465 err = nfp_cpp_writeq(rtbl->cpp, id, sym->addr, value); 466 break; 467 default: 468 nfp_err(rtbl->cpp, 469 "rtsym '%s' unsupported or non-scalar size: %lld\n", 470 name, sym->size); 471 err = -EINVAL; 472 break; 473 } 474 475 return err; 476 } 477 478 u8 __iomem * 479 nfp_rtsym_map(struct nfp_rtsym_table *rtbl, const char *name, const char *id, 480 unsigned int min_size, struct nfp_cpp_area **area) 481 { 482 const struct nfp_rtsym *sym; 483 u8 __iomem *mem; 484 u32 cpp_id; 485 486 sym = nfp_rtsym_lookup(rtbl, name); 487 if (!sym) 488 return (u8 __iomem *)ERR_PTR(-ENOENT); 489 490 cpp_id = NFP_CPP_ISLAND_ID(sym->target, NFP_CPP_ACTION_RW, 0, 491 sym->domain); 492 493 if (sym->size < min_size) { 494 nfp_err(rtbl->cpp, "Symbol %s too small\n", name); 495 return (u8 __iomem *)ERR_PTR(-EINVAL); 496 } 497 498 mem = nfp_cpp_map_area(rtbl->cpp, id, cpp_id, sym->addr, 499 sym->size, area); 500 if (IS_ERR(mem)) { 501 nfp_err(rtbl->cpp, "Failed to map symbol %s: %ld\n", 502 name, PTR_ERR(mem)); 503 return mem; 504 } 505 506 return mem; 507 } 508