1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018-2022 Marvell International Ltd. 4 * 5 */ 6 7#include <log.h> 8#include <time.h> 9#include <linux/delay.h> 10 11#include <mach/cvmx-regs.h> 12#include <mach/cvmx-csr.h> 13#include <mach/cvmx-bootmem.h> 14#include <mach/octeon-model.h> 15#include <mach/cvmx-fuse.h> 16#include <mach/octeon-feature.h> 17#include <mach/cvmx-qlm.h> 18#include <mach/octeon_qlm.h> 19#include <mach/cvmx-pcie.h> 20#include <mach/cvmx-coremask.h> 21#include <mach/cvmx-range.h> 22 23#include <mach/cvmx-global-resources.h> 24#include <mach/cvmx-bootmem.h> 25 26#include <mach/cvmx-pki.h> 27#include <mach/cvmx-helper.h> 28#include <mach/cvmx-helper-board.h> 29#include <mach/cvmx-helper-cfg.h> 30 31#define CVMX_MAX_GLOBAL_RESOURCES 128 32#define CVMX_RESOURCES_ENTRIES_SIZE \ 33 (sizeof(struct cvmx_global_resource_entry) * CVMX_MAX_GLOBAL_RESOURCES) 34 35/** 36 * This macro returns a member of the data 37 * structure. The argument "field" is the member name of the 38 * structure to read. The return type is a u64. 39 */ 40#define CVMX_GLOBAL_RESOURCES_GET_FIELD(field) \ 41 __cvmx_struct_get_unsigned_field( \ 42 __cvmx_global_resources_addr, \ 43 offsetof(struct cvmx_global_resources, field), \ 44 SIZEOF_FIELD(struct cvmx_global_resources, field)) 45 46/** 47 * This macro writes a member of the struct cvmx_global_resourcest 48 * structure. The argument "field" is the member name of the 49 * struct cvmx_global_resources to write. 50 */ 51#define CVMX_GLOBAL_RESOURCES_SET_FIELD(field, value) \ 52 __cvmx_struct_set_unsigned_field( \ 53 __cvmx_global_resources_addr, \ 54 offsetof(struct cvmx_global_resources, field), \ 55 SIZEOF_FIELD(struct cvmx_global_resources, field), value) 56 57/** 58 * This macro returns a member of the struct cvmx_global_resource_entry. 59 * The argument "field" is the member name of this structure. 60 * the return type is a u64. The "addr" parameter is the physical 61 * address of the structure. 62 */ 63#define CVMX_RESOURCE_ENTRY_GET_FIELD(addr, field) \ 64 __cvmx_struct_get_unsigned_field( \ 65 addr, offsetof(struct cvmx_global_resource_entry, field), \ 66 SIZEOF_FIELD(struct cvmx_global_resource_entry, field)) 67 68/** 69 * This macro writes a member of the struct cvmx_global_resource_entry 70 * structure. The argument "field" is the member name of the 71 * struct cvmx_global_resource_entry to write. The "addr" parameter 72 * is the physical address of the structure. 73 */ 74#define CVMX_RESOURCE_ENTRY_SET_FIELD(addr, field, value) \ 75 __cvmx_struct_set_unsigned_field( \ 76 addr, offsetof(struct cvmx_global_resource_entry, field), \ 77 SIZEOF_FIELD(struct cvmx_global_resource_entry, field), value) 78 79#define CVMX_GET_RESOURCE_ENTRY(count) \ 80 (__cvmx_global_resources_addr + \ 81 offsetof(struct cvmx_global_resources, resource_entry) + \ 82 (count * sizeof(struct cvmx_global_resource_entry))) 83 84#define CVMX_RESOURCE_TAG_SET_FIELD(addr, field, value) \ 85 __cvmx_struct_set_unsigned_field( \ 86 addr, offsetof(struct global_resource_tag, field), \ 87 SIZEOF_FIELD(struct global_resource_tag, field), value) 88 89#define CVMX_RESOURCE_TAG_GET_FIELD(addr, field) \ 90 __cvmx_struct_get_unsigned_field( \ 91 addr, offsetof(struct global_resource_tag, field), \ 92 SIZEOF_FIELD(struct global_resource_tag, field)) 93 94#define MAX_RESOURCE_TAG_LEN 16 95#define CVMX_GLOBAL_RESOURCE_NO_LOCKING (1) 96 97struct cvmx_global_resource_entry { 98 struct global_resource_tag tag; 99 u64 phys_addr; 100 u64 size; 101}; 102 103struct cvmx_global_resources { 104 u32 pad; 105 u32 rlock; 106 u64 entry_cnt; 107 struct cvmx_global_resource_entry resource_entry[]; 108}; 109 110/* Not the right place, putting it here for now */ 111u64 cvmx_app_id; 112 113/* 114 * Global named memory can be accessed anywhere even in 32-bit mode 115 */ 116static u64 __cvmx_global_resources_addr; 117 118/** 119 * This macro returns the size of a member of a structure. 120 */ 121#define SIZEOF_FIELD(s, field) sizeof(((s *)NULL)->field) 122 123/** 124 * This function is the implementation of the get macros defined 125 * for individual structure members. The argument are generated 126 * by the macros inorder to read only the needed memory. 127 * 128 * @param base 64bit physical address of the complete structure 129 * @param offset from the beginning of the structure to the member being 130 * accessed. 131 * @param size Size of the structure member. 132 * 133 * @return Value of the structure member promoted into a u64. 134 */ 135static inline u64 __cvmx_struct_get_unsigned_field(u64 base, int offset, 136 int size) 137{ 138 base = (1ull << 63) | (base + offset); 139 switch (size) { 140 case 4: 141 return cvmx_read64_uint32(base); 142 case 8: 143 return cvmx_read64_uint64(base); 144 default: 145 return 0; 146 } 147} 148 149/** 150 * This function is the implementation of the set macros defined 151 * for individual structure members. The argument are generated 152 * by the macros in order to write only the needed memory. 153 * 154 * @param base 64bit physical address of the complete structure 155 * @param offset from the beginning of the structure to the member being 156 * accessed. 157 * @param size Size of the structure member. 158 * @param value Value to write into the structure 159 */ 160static inline void __cvmx_struct_set_unsigned_field(u64 base, int offset, 161 int size, u64 value) 162{ 163 base = (1ull << 63) | (base + offset); 164 switch (size) { 165 case 4: 166 cvmx_write64_uint32(base, value); 167 break; 168 case 8: 169 cvmx_write64_uint64(base, value); 170 break; 171 default: 172 break; 173 } 174} 175 176/* Get the global resource lock. */ 177static inline void __cvmx_global_resource_lock(void) 178{ 179 u64 lock_addr = 180 (1ull << 63) | (__cvmx_global_resources_addr + 181 offsetof(struct cvmx_global_resources, rlock)); 182 unsigned int tmp; 183 184 __asm__ __volatile__(".set noreorder\n" 185 "1: ll %[tmp], 0(%[addr])\n" 186 " bnez %[tmp], 1b\n" 187 " li %[tmp], 1\n" 188 " sc %[tmp], 0(%[addr])\n" 189 " beqz %[tmp], 1b\n" 190 " nop\n" 191 ".set reorder\n" 192 : [tmp] "=&r"(tmp) 193 : [addr] "r"(lock_addr) 194 : "memory"); 195} 196 197/* Release the global resource lock. */ 198static inline void __cvmx_global_resource_unlock(void) 199{ 200 u64 lock_addr = 201 (1ull << 63) | (__cvmx_global_resources_addr + 202 offsetof(struct cvmx_global_resources, rlock)); 203 CVMX_SYNCW; 204 __asm__ __volatile__("sw $0, 0(%[addr])\n" 205 : 206 : [addr] "r"(lock_addr) 207 : "memory"); 208 CVMX_SYNCW; 209} 210 211static u64 __cvmx_alloc_bootmem_for_global_resources(int sz) 212{ 213 void *tmp; 214 215 tmp = cvmx_bootmem_alloc_range(sz, CVMX_CACHE_LINE_SIZE, 0, 0); 216 return cvmx_ptr_to_phys(tmp); 217} 218 219static inline void __cvmx_get_tagname(struct global_resource_tag *rtag, 220 char *tagname) 221{ 222 int i, j, k; 223 224 j = 0; 225 k = 8; 226 for (i = 7; i >= 0; i--, j++, k++) { 227 tagname[j] = (rtag->lo >> (i * 8)) & 0xff; 228 tagname[k] = (rtag->hi >> (i * 8)) & 0xff; 229 } 230} 231 232static u64 __cvmx_global_resources_init(void) 233{ 234 struct cvmx_bootmem_named_block_desc *block_desc; 235 int sz = sizeof(struct cvmx_global_resources) + 236 CVMX_RESOURCES_ENTRIES_SIZE; 237 s64 tmp_phys; 238 int count = 0; 239 u64 base = 0; 240 241 cvmx_bootmem_lock(); 242 243 block_desc = (struct cvmx_bootmem_named_block_desc *) 244 __cvmx_bootmem_find_named_block_flags( 245 CVMX_GLOBAL_RESOURCES_DATA_NAME, 246 CVMX_BOOTMEM_FLAG_NO_LOCKING); 247 if (!block_desc) { 248 debug("%s: allocating global resources\n", __func__); 249 250 tmp_phys = cvmx_bootmem_phy_named_block_alloc( 251 sz, 0, 0, CVMX_CACHE_LINE_SIZE, 252 CVMX_GLOBAL_RESOURCES_DATA_NAME, 253 CVMX_BOOTMEM_FLAG_NO_LOCKING); 254 if (tmp_phys < 0) { 255 cvmx_printf( 256 "ERROR: %s: failed to allocate global resource name block. sz=%d\n", 257 __func__, sz); 258 goto end; 259 } 260 __cvmx_global_resources_addr = (u64)tmp_phys; 261 262 debug("%s: memset global resources %llu\n", __func__, 263 CAST_ULL(__cvmx_global_resources_addr)); 264 265 base = (1ull << 63) | __cvmx_global_resources_addr; 266 for (count = 0; count < (sz / 8); count++) { 267 cvmx_write64_uint64(base, 0); 268 base += 8; 269 } 270 } else { 271 debug("%s:found global resource\n", __func__); 272 __cvmx_global_resources_addr = block_desc->base_addr; 273 } 274end: 275 cvmx_bootmem_unlock(); 276 debug("__cvmx_global_resources_addr=%llu sz=%d\n", 277 CAST_ULL(__cvmx_global_resources_addr), sz); 278 return __cvmx_global_resources_addr; 279} 280 281u64 cvmx_get_global_resource(struct global_resource_tag tag, int no_lock) 282{ 283 u64 entry_cnt = 0; 284 u64 resource_entry_addr = 0; 285 int count = 0; 286 u64 rphys_addr = 0; 287 u64 tag_lo = 0, tag_hi = 0; 288 289 if (__cvmx_global_resources_addr == 0) 290 __cvmx_global_resources_init(); 291 if (!no_lock) 292 __cvmx_global_resource_lock(); 293 294 entry_cnt = CVMX_GLOBAL_RESOURCES_GET_FIELD(entry_cnt); 295 while (entry_cnt > 0) { 296 resource_entry_addr = CVMX_GET_RESOURCE_ENTRY(count); 297 tag_lo = CVMX_RESOURCE_TAG_GET_FIELD(resource_entry_addr, lo); 298 tag_hi = CVMX_RESOURCE_TAG_GET_FIELD(resource_entry_addr, hi); 299 300 if (tag_lo == tag.lo && tag_hi == tag.hi) { 301 debug("%s: Found global resource entry\n", __func__); 302 break; 303 } 304 entry_cnt--; 305 count++; 306 } 307 308 if (entry_cnt == 0) { 309 debug("%s: no matching global resource entry found\n", 310 __func__); 311 if (!no_lock) 312 __cvmx_global_resource_unlock(); 313 return 0; 314 } 315 rphys_addr = 316 CVMX_RESOURCE_ENTRY_GET_FIELD(resource_entry_addr, phys_addr); 317 if (!no_lock) 318 __cvmx_global_resource_unlock(); 319 320 return rphys_addr; 321} 322 323u64 cvmx_create_global_resource(struct global_resource_tag tag, u64 size, 324 int no_lock, int *_new_) 325{ 326 u64 entry_count = 0; 327 u64 resource_entry_addr = 0; 328 u64 phys_addr; 329 330 if (__cvmx_global_resources_addr == 0) 331 __cvmx_global_resources_init(); 332 333 if (!no_lock) 334 __cvmx_global_resource_lock(); 335 336 phys_addr = 337 cvmx_get_global_resource(tag, CVMX_GLOBAL_RESOURCE_NO_LOCKING); 338 if (phys_addr != 0) { 339 /* we already have the resource, return it */ 340 *_new_ = 0; 341 goto end; 342 } 343 344 *_new_ = 1; 345 entry_count = CVMX_GLOBAL_RESOURCES_GET_FIELD(entry_cnt); 346 if (entry_count >= CVMX_MAX_GLOBAL_RESOURCES) { 347 char tagname[MAX_RESOURCE_TAG_LEN + 1]; 348 349 __cvmx_get_tagname(&tag, tagname); 350 cvmx_printf( 351 "ERROR: %s: reached global resources limit for %s\n", 352 __func__, tagname); 353 phys_addr = 0; 354 goto end; 355 } 356 357 /* Allocate bootmem for the resource*/ 358 phys_addr = __cvmx_alloc_bootmem_for_global_resources(size); 359 if (!phys_addr) { 360 char tagname[MAX_RESOURCE_TAG_LEN + 1]; 361 362 __cvmx_get_tagname(&tag, tagname); 363 debug("ERROR: %s: out of memory %s, size=%d\n", __func__, 364 tagname, (int)size); 365 goto end; 366 } 367 368 resource_entry_addr = CVMX_GET_RESOURCE_ENTRY(entry_count); 369 CVMX_RESOURCE_ENTRY_SET_FIELD(resource_entry_addr, phys_addr, 370 phys_addr); 371 CVMX_RESOURCE_ENTRY_SET_FIELD(resource_entry_addr, size, size); 372 CVMX_RESOURCE_TAG_SET_FIELD(resource_entry_addr, lo, tag.lo); 373 CVMX_RESOURCE_TAG_SET_FIELD(resource_entry_addr, hi, tag.hi); 374 /* update entry_cnt */ 375 entry_count += 1; 376 CVMX_GLOBAL_RESOURCES_SET_FIELD(entry_cnt, entry_count); 377 378end: 379 if (!no_lock) 380 __cvmx_global_resource_unlock(); 381 382 return phys_addr; 383} 384 385int cvmx_create_global_resource_range(struct global_resource_tag tag, 386 int nelements) 387{ 388 int sz = cvmx_range_memory_size(nelements); 389 int _new_; 390 u64 addr; 391 int rv = 0; 392 393 if (__cvmx_global_resources_addr == 0) 394 __cvmx_global_resources_init(); 395 396 __cvmx_global_resource_lock(); 397 addr = cvmx_create_global_resource(tag, sz, 1, &_new_); 398 if (!addr) { 399 __cvmx_global_resource_unlock(); 400 return -1; 401 } 402 if (_new_) 403 rv = cvmx_range_init(addr, nelements); 404 __cvmx_global_resource_unlock(); 405 return rv; 406} 407 408int cvmx_allocate_global_resource_range(struct global_resource_tag tag, 409 u64 owner, int nelements, int alignment) 410{ 411 u64 addr = cvmx_get_global_resource(tag, 1); 412 int base; 413 414 if (addr == 0) { 415 char tagname[256]; 416 417 __cvmx_get_tagname(&tag, tagname); 418 cvmx_printf("ERROR: %s: cannot find resource %s\n", __func__, 419 tagname); 420 return -1; 421 } 422 __cvmx_global_resource_lock(); 423 base = cvmx_range_alloc(addr, owner, nelements, alignment); 424 __cvmx_global_resource_unlock(); 425 return base; 426} 427 428int cvmx_resource_alloc_reverse(struct global_resource_tag tag, u64 owner) 429{ 430 u64 addr = cvmx_get_global_resource(tag, 1); 431 int rv; 432 433 if (addr == 0) { 434 char tagname[256]; 435 436 __cvmx_get_tagname(&tag, tagname); 437 debug("ERROR: cannot find resource %s\n", tagname); 438 return -1; 439 } 440 __cvmx_global_resource_lock(); 441 rv = cvmx_range_alloc_ordered(addr, owner, 1, 1, 1); 442 __cvmx_global_resource_unlock(); 443 return rv; 444} 445 446int cvmx_reserve_global_resource_range(struct global_resource_tag tag, 447 u64 owner, int base, int nelements) 448{ 449 u64 addr = cvmx_get_global_resource(tag, 1); 450 int start; 451 452 __cvmx_global_resource_lock(); 453 start = cvmx_range_reserve(addr, owner, base, nelements); 454 __cvmx_global_resource_unlock(); 455 return start; 456} 457 458int cvmx_free_global_resource_range_with_base(struct global_resource_tag tag, 459 int base, int nelements) 460{ 461 u64 addr = cvmx_get_global_resource(tag, 1); 462 int rv; 463 464 /* Resource was not created, nothing to release */ 465 if (addr == 0) 466 return 0; 467 468 __cvmx_global_resource_lock(); 469 rv = cvmx_range_free_with_base(addr, base, nelements); 470 __cvmx_global_resource_unlock(); 471 return rv; 472} 473 474int cvmx_free_global_resource_range_multiple(struct global_resource_tag tag, 475 int bases[], int nelements) 476{ 477 u64 addr = cvmx_get_global_resource(tag, 1); 478 int rv; 479 480 /* Resource was not created, nothing to release */ 481 if (addr == 0) 482 return 0; 483 484 __cvmx_global_resource_lock(); 485 rv = cvmx_range_free_mutiple(addr, bases, nelements); 486 __cvmx_global_resource_unlock(); 487 return rv; 488} 489 490void cvmx_app_id_init(void *bootmem) 491{ 492 u64 *p = (u64 *)bootmem; 493 494 *p = 0; 495} 496 497u64 cvmx_allocate_app_id(void) 498{ 499 u64 *vptr; 500 501 vptr = (u64 *)cvmx_bootmem_alloc_named_range_once(sizeof(cvmx_app_id), 502 0, 1 << 31, 128, 503 "cvmx_app_id", 504 cvmx_app_id_init); 505 506 cvmx_app_id = __atomic_add_fetch(vptr, 1, __ATOMIC_SEQ_CST); 507 508 debug("CVMX_APP_ID = %lx\n", (unsigned long)cvmx_app_id); 509 return cvmx_app_id; 510} 511 512u64 cvmx_get_app_id(void) 513{ 514 if (cvmx_app_id == 0) 515 cvmx_allocate_app_id(); 516 return cvmx_app_id; 517} 518