1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2015, Sony Mobile Communications AB. 4 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 5 */ 6 7 #include <linux/hwspinlock.h> 8 #include <linux/io.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/of_address.h> 12 #include <linux/platform_device.h> 13 #include <linux/sizes.h> 14 #include <linux/slab.h> 15 #include <linux/soc/qcom/smem.h> 16 17 /* 18 * The Qualcomm shared memory system is a allocate only heap structure that 19 * consists of one of more memory areas that can be accessed by the processors 20 * in the SoC. 21 * 22 * All systems contains a global heap, accessible by all processors in the SoC, 23 * with a table of contents data structure (@smem_header) at the beginning of 24 * the main shared memory block. 25 * 26 * The global header contains meta data for allocations as well as a fixed list 27 * of 512 entries (@smem_global_entry) that can be initialized to reference 28 * parts of the shared memory space. 29 * 30 * 31 * In addition to this global heap a set of "private" heaps can be set up at 32 * boot time with access restrictions so that only certain processor pairs can 33 * access the data. 34 * 35 * These partitions are referenced from an optional partition table 36 * (@smem_ptable), that is found 4kB from the end of the main smem region. The 37 * partition table entries (@smem_ptable_entry) lists the involved processors 38 * (or hosts) and their location in the main shared memory region. 39 * 40 * Each partition starts with a header (@smem_partition_header) that identifies 41 * the partition and holds properties for the two internal memory regions. The 42 * two regions are cached and non-cached memory respectively. Each region 43 * contain a link list of allocation headers (@smem_private_entry) followed by 44 * their data. 45 * 46 * Items in the non-cached region are allocated from the start of the partition 47 * while items in the cached region are allocated from the end. The free area 48 * is hence the region between the cached and non-cached offsets. The header of 49 * cached items comes after the data. 50 * 51 * Version 12 (SMEM_GLOBAL_PART_VERSION) changes the item alloc/get procedure 52 * for the global heap. A new global partition is created from the global heap 53 * region with partition type (SMEM_GLOBAL_HOST) and the max smem item count is 54 * set by the bootloader. 55 * 56 * To synchronize allocations in the shared memory heaps a remote spinlock must 57 * be held - currently lock number 3 of the sfpb or tcsr is used for this on all 58 * platforms. 59 * 60 */ 61 62 /* 63 * The version member of the smem header contains an array of versions for the 64 * various software components in the SoC. We verify that the boot loader 65 * version is a valid version as a sanity check. 66 */ 67 #define SMEM_MASTER_SBL_VERSION_INDEX 7 68 #define SMEM_GLOBAL_HEAP_VERSION 11 69 #define SMEM_GLOBAL_PART_VERSION 12 70 71 /* 72 * The first 8 items are only to be allocated by the boot loader while 73 * initializing the heap. 74 */ 75 #define SMEM_ITEM_LAST_FIXED 8 76 77 /* Highest accepted item number, for both global and private heaps */ 78 #define SMEM_ITEM_COUNT 512 79 80 /* Processor/host identifier for the application processor */ 81 #define SMEM_HOST_APPS 0 82 83 /* Processor/host identifier for the global partition */ 84 #define SMEM_GLOBAL_HOST 0xfffe 85 86 /* Max number of processors/hosts in a system */ 87 #define SMEM_HOST_COUNT 10 88 89 /** 90 * struct smem_proc_comm - proc_comm communication struct (legacy) 91 * @command: current command to be executed 92 * @status: status of the currently requested command 93 * @params: parameters to the command 94 */ 95 struct smem_proc_comm { 96 __le32 command; 97 __le32 status; 98 __le32 params[2]; 99 }; 100 101 /** 102 * struct smem_global_entry - entry to reference smem items on the heap 103 * @allocated: boolean to indicate if this entry is used 104 * @offset: offset to the allocated space 105 * @size: size of the allocated space, 8 byte aligned 106 * @aux_base: base address for the memory region used by this unit, or 0 for 107 * the default region. bits 0,1 are reserved 108 */ 109 struct smem_global_entry { 110 __le32 allocated; 111 __le32 offset; 112 __le32 size; 113 __le32 aux_base; /* bits 1:0 reserved */ 114 }; 115 #define AUX_BASE_MASK 0xfffffffc 116 117 /** 118 * struct smem_header - header found in beginning of primary smem region 119 * @proc_comm: proc_comm communication interface (legacy) 120 * @version: array of versions for the various subsystems 121 * @initialized: boolean to indicate that smem is initialized 122 * @free_offset: index of the first unallocated byte in smem 123 * @available: number of bytes available for allocation 124 * @reserved: reserved field, must be 0 125 * toc: array of references to items 126 */ 127 struct smem_header { 128 struct smem_proc_comm proc_comm[4]; 129 __le32 version[32]; 130 __le32 initialized; 131 __le32 free_offset; 132 __le32 available; 133 __le32 reserved; 134 struct smem_global_entry toc[SMEM_ITEM_COUNT]; 135 }; 136 137 /** 138 * struct smem_ptable_entry - one entry in the @smem_ptable list 139 * @offset: offset, within the main shared memory region, of the partition 140 * @size: size of the partition 141 * @flags: flags for the partition (currently unused) 142 * @host0: first processor/host with access to this partition 143 * @host1: second processor/host with access to this partition 144 * @cacheline: alignment for "cached" entries 145 * @reserved: reserved entries for later use 146 */ 147 struct smem_ptable_entry { 148 __le32 offset; 149 __le32 size; 150 __le32 flags; 151 __le16 host0; 152 __le16 host1; 153 __le32 cacheline; 154 __le32 reserved[7]; 155 }; 156 157 /** 158 * struct smem_ptable - partition table for the private partitions 159 * @magic: magic number, must be SMEM_PTABLE_MAGIC 160 * @version: version of the partition table 161 * @num_entries: number of partitions in the table 162 * @reserved: for now reserved entries 163 * @entry: list of @smem_ptable_entry for the @num_entries partitions 164 */ 165 struct smem_ptable { 166 u8 magic[4]; 167 __le32 version; 168 __le32 num_entries; 169 __le32 reserved[5]; 170 struct smem_ptable_entry entry[]; 171 }; 172 173 static const u8 SMEM_PTABLE_MAGIC[] = { 0x24, 0x54, 0x4f, 0x43 }; /* "$TOC" */ 174 175 /** 176 * struct smem_partition_header - header of the partitions 177 * @magic: magic number, must be SMEM_PART_MAGIC 178 * @host0: first processor/host with access to this partition 179 * @host1: second processor/host with access to this partition 180 * @size: size of the partition 181 * @offset_free_uncached: offset to the first free byte of uncached memory in 182 * this partition 183 * @offset_free_cached: offset to the first free byte of cached memory in this 184 * partition 185 * @reserved: for now reserved entries 186 */ 187 struct smem_partition_header { 188 u8 magic[4]; 189 __le16 host0; 190 __le16 host1; 191 __le32 size; 192 __le32 offset_free_uncached; 193 __le32 offset_free_cached; 194 __le32 reserved[3]; 195 }; 196 197 static const u8 SMEM_PART_MAGIC[] = { 0x24, 0x50, 0x52, 0x54 }; 198 199 /** 200 * struct smem_private_entry - header of each item in the private partition 201 * @canary: magic number, must be SMEM_PRIVATE_CANARY 202 * @item: identifying number of the smem item 203 * @size: size of the data, including padding bytes 204 * @padding_data: number of bytes of padding of data 205 * @padding_hdr: number of bytes of padding between the header and the data 206 * @reserved: for now reserved entry 207 */ 208 struct smem_private_entry { 209 u16 canary; /* bytes are the same so no swapping needed */ 210 __le16 item; 211 __le32 size; /* includes padding bytes */ 212 __le16 padding_data; 213 __le16 padding_hdr; 214 __le32 reserved; 215 }; 216 #define SMEM_PRIVATE_CANARY 0xa5a5 217 218 /** 219 * struct smem_info - smem region info located after the table of contents 220 * @magic: magic number, must be SMEM_INFO_MAGIC 221 * @size: size of the smem region 222 * @base_addr: base address of the smem region 223 * @reserved: for now reserved entry 224 * @num_items: highest accepted item number 225 */ 226 struct smem_info { 227 u8 magic[4]; 228 __le32 size; 229 __le32 base_addr; 230 __le32 reserved; 231 __le16 num_items; 232 }; 233 234 static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */ 235 236 /** 237 * struct smem_region - representation of a chunk of memory used for smem 238 * @aux_base: identifier of aux_mem base 239 * @virt_base: virtual base address of memory with this aux_mem identifier 240 * @size: size of the memory region 241 */ 242 struct smem_region { 243 u32 aux_base; 244 void __iomem *virt_base; 245 size_t size; 246 }; 247 248 /** 249 * struct qcom_smem - device data for the smem device 250 * @dev: device pointer 251 * @hwlock: reference to a hwspinlock 252 * @global_partition: pointer to global partition when in use 253 * @global_cacheline: cacheline size for global partition 254 * @partitions: list of pointers to partitions affecting the current 255 * processor/host 256 * @cacheline: list of cacheline sizes for each host 257 * @item_count: max accepted item number 258 * @num_regions: number of @regions 259 * @regions: list of the memory regions defining the shared memory 260 */ 261 struct qcom_smem { 262 struct device *dev; 263 264 struct hwspinlock *hwlock; 265 266 struct smem_partition_header *global_partition; 267 size_t global_cacheline; 268 struct smem_partition_header *partitions[SMEM_HOST_COUNT]; 269 size_t cacheline[SMEM_HOST_COUNT]; 270 u32 item_count; 271 272 unsigned num_regions; 273 struct smem_region regions[]; 274 }; 275 276 static void * 277 phdr_to_last_uncached_entry(struct smem_partition_header *phdr) 278 { 279 void *p = phdr; 280 281 return p + le32_to_cpu(phdr->offset_free_uncached); 282 } 283 284 static struct smem_private_entry * 285 phdr_to_first_cached_entry(struct smem_partition_header *phdr, 286 size_t cacheline) 287 { 288 void *p = phdr; 289 struct smem_private_entry *e; 290 291 return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*e), cacheline); 292 } 293 294 static void * 295 phdr_to_last_cached_entry(struct smem_partition_header *phdr) 296 { 297 void *p = phdr; 298 299 return p + le32_to_cpu(phdr->offset_free_cached); 300 } 301 302 static struct smem_private_entry * 303 phdr_to_first_uncached_entry(struct smem_partition_header *phdr) 304 { 305 void *p = phdr; 306 307 return p + sizeof(*phdr); 308 } 309 310 static struct smem_private_entry * 311 uncached_entry_next(struct smem_private_entry *e) 312 { 313 void *p = e; 314 315 return p + sizeof(*e) + le16_to_cpu(e->padding_hdr) + 316 le32_to_cpu(e->size); 317 } 318 319 static struct smem_private_entry * 320 cached_entry_next(struct smem_private_entry *e, size_t cacheline) 321 { 322 void *p = e; 323 324 return p - le32_to_cpu(e->size) - ALIGN(sizeof(*e), cacheline); 325 } 326 327 static void *uncached_entry_to_item(struct smem_private_entry *e) 328 { 329 void *p = e; 330 331 return p + sizeof(*e) + le16_to_cpu(e->padding_hdr); 332 } 333 334 static void *cached_entry_to_item(struct smem_private_entry *e) 335 { 336 void *p = e; 337 338 return p - le32_to_cpu(e->size); 339 } 340 341 /* Pointer to the one and only smem handle */ 342 static struct qcom_smem *__smem; 343 344 /* Timeout (ms) for the trylock of remote spinlocks */ 345 #define HWSPINLOCK_TIMEOUT 1000 346 347 static int qcom_smem_alloc_private(struct qcom_smem *smem, 348 struct smem_partition_header *phdr, 349 unsigned item, 350 size_t size) 351 { 352 struct smem_private_entry *hdr, *end; 353 size_t alloc_size; 354 void *cached; 355 356 hdr = phdr_to_first_uncached_entry(phdr); 357 end = phdr_to_last_uncached_entry(phdr); 358 cached = phdr_to_last_cached_entry(phdr); 359 360 while (hdr < end) { 361 if (hdr->canary != SMEM_PRIVATE_CANARY) 362 goto bad_canary; 363 if (le16_to_cpu(hdr->item) == item) 364 return -EEXIST; 365 366 hdr = uncached_entry_next(hdr); 367 } 368 369 /* Check that we don't grow into the cached region */ 370 alloc_size = sizeof(*hdr) + ALIGN(size, 8); 371 if ((void *)hdr + alloc_size > cached) { 372 dev_err(smem->dev, "Out of memory\n"); 373 return -ENOSPC; 374 } 375 376 hdr->canary = SMEM_PRIVATE_CANARY; 377 hdr->item = cpu_to_le16(item); 378 hdr->size = cpu_to_le32(ALIGN(size, 8)); 379 hdr->padding_data = cpu_to_le16(le32_to_cpu(hdr->size) - size); 380 hdr->padding_hdr = 0; 381 382 /* 383 * Ensure the header is written before we advance the free offset, so 384 * that remote processors that does not take the remote spinlock still 385 * gets a consistent view of the linked list. 386 */ 387 wmb(); 388 le32_add_cpu(&phdr->offset_free_uncached, alloc_size); 389 390 return 0; 391 bad_canary: 392 dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n", 393 le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1)); 394 395 return -EINVAL; 396 } 397 398 static int qcom_smem_alloc_global(struct qcom_smem *smem, 399 unsigned item, 400 size_t size) 401 { 402 struct smem_global_entry *entry; 403 struct smem_header *header; 404 405 header = smem->regions[0].virt_base; 406 entry = &header->toc[item]; 407 if (entry->allocated) 408 return -EEXIST; 409 410 size = ALIGN(size, 8); 411 if (WARN_ON(size > le32_to_cpu(header->available))) 412 return -ENOMEM; 413 414 entry->offset = header->free_offset; 415 entry->size = cpu_to_le32(size); 416 417 /* 418 * Ensure the header is consistent before we mark the item allocated, 419 * so that remote processors will get a consistent view of the item 420 * even though they do not take the spinlock on read. 421 */ 422 wmb(); 423 entry->allocated = cpu_to_le32(1); 424 425 le32_add_cpu(&header->free_offset, size); 426 le32_add_cpu(&header->available, -size); 427 428 return 0; 429 } 430 431 /** 432 * qcom_smem_alloc() - allocate space for a smem item 433 * @host: remote processor id, or -1 434 * @item: smem item handle 435 * @size: number of bytes to be allocated 436 * 437 * Allocate space for a given smem item of size @size, given that the item is 438 * not yet allocated. 439 */ 440 int qcom_smem_alloc(unsigned host, unsigned item, size_t size) 441 { 442 struct smem_partition_header *phdr; 443 unsigned long flags; 444 int ret; 445 446 if (!__smem) 447 return -EPROBE_DEFER; 448 449 if (item < SMEM_ITEM_LAST_FIXED) { 450 dev_err(__smem->dev, 451 "Rejecting allocation of static entry %d\n", item); 452 return -EINVAL; 453 } 454 455 if (WARN_ON(item >= __smem->item_count)) 456 return -EINVAL; 457 458 ret = hwspin_lock_timeout_irqsave(__smem->hwlock, 459 HWSPINLOCK_TIMEOUT, 460 &flags); 461 if (ret) 462 return ret; 463 464 if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { 465 phdr = __smem->partitions[host]; 466 ret = qcom_smem_alloc_private(__smem, phdr, item, size); 467 } else if (__smem->global_partition) { 468 phdr = __smem->global_partition; 469 ret = qcom_smem_alloc_private(__smem, phdr, item, size); 470 } else { 471 ret = qcom_smem_alloc_global(__smem, item, size); 472 } 473 474 hwspin_unlock_irqrestore(__smem->hwlock, &flags); 475 476 return ret; 477 } 478 EXPORT_SYMBOL(qcom_smem_alloc); 479 480 static void *qcom_smem_get_global(struct qcom_smem *smem, 481 unsigned item, 482 size_t *size) 483 { 484 struct smem_header *header; 485 struct smem_region *region; 486 struct smem_global_entry *entry; 487 u32 aux_base; 488 unsigned i; 489 490 header = smem->regions[0].virt_base; 491 entry = &header->toc[item]; 492 if (!entry->allocated) 493 return ERR_PTR(-ENXIO); 494 495 aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK; 496 497 for (i = 0; i < smem->num_regions; i++) { 498 region = &smem->regions[i]; 499 500 if (region->aux_base == aux_base || !aux_base) { 501 if (size != NULL) 502 *size = le32_to_cpu(entry->size); 503 return region->virt_base + le32_to_cpu(entry->offset); 504 } 505 } 506 507 return ERR_PTR(-ENOENT); 508 } 509 510 static void *qcom_smem_get_private(struct qcom_smem *smem, 511 struct smem_partition_header *phdr, 512 size_t cacheline, 513 unsigned item, 514 size_t *size) 515 { 516 struct smem_private_entry *e, *end; 517 518 e = phdr_to_first_uncached_entry(phdr); 519 end = phdr_to_last_uncached_entry(phdr); 520 521 while (e < end) { 522 if (e->canary != SMEM_PRIVATE_CANARY) 523 goto invalid_canary; 524 525 if (le16_to_cpu(e->item) == item) { 526 if (size != NULL) 527 *size = le32_to_cpu(e->size) - 528 le16_to_cpu(e->padding_data); 529 530 return uncached_entry_to_item(e); 531 } 532 533 e = uncached_entry_next(e); 534 } 535 536 /* Item was not found in the uncached list, search the cached list */ 537 538 e = phdr_to_first_cached_entry(phdr, cacheline); 539 end = phdr_to_last_cached_entry(phdr); 540 541 while (e > end) { 542 if (e->canary != SMEM_PRIVATE_CANARY) 543 goto invalid_canary; 544 545 if (le16_to_cpu(e->item) == item) { 546 if (size != NULL) 547 *size = le32_to_cpu(e->size) - 548 le16_to_cpu(e->padding_data); 549 550 return cached_entry_to_item(e); 551 } 552 553 e = cached_entry_next(e, cacheline); 554 } 555 556 return ERR_PTR(-ENOENT); 557 558 invalid_canary: 559 dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n", 560 le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1)); 561 562 return ERR_PTR(-EINVAL); 563 } 564 565 /** 566 * qcom_smem_get() - resolve ptr of size of a smem item 567 * @host: the remote processor, or -1 568 * @item: smem item handle 569 * @size: pointer to be filled out with size of the item 570 * 571 * Looks up smem item and returns pointer to it. Size of smem 572 * item is returned in @size. 573 */ 574 void *qcom_smem_get(unsigned host, unsigned item, size_t *size) 575 { 576 struct smem_partition_header *phdr; 577 unsigned long flags; 578 size_t cacheln; 579 int ret; 580 void *ptr = ERR_PTR(-EPROBE_DEFER); 581 582 if (!__smem) 583 return ptr; 584 585 if (WARN_ON(item >= __smem->item_count)) 586 return ERR_PTR(-EINVAL); 587 588 ret = hwspin_lock_timeout_irqsave(__smem->hwlock, 589 HWSPINLOCK_TIMEOUT, 590 &flags); 591 if (ret) 592 return ERR_PTR(ret); 593 594 if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { 595 phdr = __smem->partitions[host]; 596 cacheln = __smem->cacheline[host]; 597 ptr = qcom_smem_get_private(__smem, phdr, cacheln, item, size); 598 } else if (__smem->global_partition) { 599 phdr = __smem->global_partition; 600 cacheln = __smem->global_cacheline; 601 ptr = qcom_smem_get_private(__smem, phdr, cacheln, item, size); 602 } else { 603 ptr = qcom_smem_get_global(__smem, item, size); 604 } 605 606 hwspin_unlock_irqrestore(__smem->hwlock, &flags); 607 608 return ptr; 609 610 } 611 EXPORT_SYMBOL(qcom_smem_get); 612 613 /** 614 * qcom_smem_get_free_space() - retrieve amount of free space in a partition 615 * @host: the remote processor identifying a partition, or -1 616 * 617 * To be used by smem clients as a quick way to determine if any new 618 * allocations has been made. 619 */ 620 int qcom_smem_get_free_space(unsigned host) 621 { 622 struct smem_partition_header *phdr; 623 struct smem_header *header; 624 unsigned ret; 625 626 if (!__smem) 627 return -EPROBE_DEFER; 628 629 if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { 630 phdr = __smem->partitions[host]; 631 ret = le32_to_cpu(phdr->offset_free_cached) - 632 le32_to_cpu(phdr->offset_free_uncached); 633 } else if (__smem->global_partition) { 634 phdr = __smem->global_partition; 635 ret = le32_to_cpu(phdr->offset_free_cached) - 636 le32_to_cpu(phdr->offset_free_uncached); 637 } else { 638 header = __smem->regions[0].virt_base; 639 ret = le32_to_cpu(header->available); 640 } 641 642 return ret; 643 } 644 EXPORT_SYMBOL(qcom_smem_get_free_space); 645 646 /** 647 * qcom_smem_virt_to_phys() - return the physical address associated 648 * with an smem item pointer (previously returned by qcom_smem_get() 649 * @p: the virtual address to convert 650 * 651 * Returns 0 if the pointer provided is not within any smem region. 652 */ 653 phys_addr_t qcom_smem_virt_to_phys(void *p) 654 { 655 unsigned i; 656 657 for (i = 0; i < __smem->num_regions; i++) { 658 struct smem_region *region = &__smem->regions[i]; 659 660 if (p < region->virt_base) 661 continue; 662 if (p < region->virt_base + region->size) { 663 u64 offset = p - region->virt_base; 664 665 return (phys_addr_t)region->aux_base + offset; 666 } 667 } 668 669 return 0; 670 } 671 EXPORT_SYMBOL(qcom_smem_virt_to_phys); 672 673 static int qcom_smem_get_sbl_version(struct qcom_smem *smem) 674 { 675 struct smem_header *header; 676 __le32 *versions; 677 678 header = smem->regions[0].virt_base; 679 versions = header->version; 680 681 return le32_to_cpu(versions[SMEM_MASTER_SBL_VERSION_INDEX]); 682 } 683 684 static struct smem_ptable *qcom_smem_get_ptable(struct qcom_smem *smem) 685 { 686 struct smem_ptable *ptable; 687 u32 version; 688 689 ptable = smem->regions[0].virt_base + smem->regions[0].size - SZ_4K; 690 if (memcmp(ptable->magic, SMEM_PTABLE_MAGIC, sizeof(ptable->magic))) 691 return ERR_PTR(-ENOENT); 692 693 version = le32_to_cpu(ptable->version); 694 if (version != 1) { 695 dev_err(smem->dev, 696 "Unsupported partition header version %d\n", version); 697 return ERR_PTR(-EINVAL); 698 } 699 return ptable; 700 } 701 702 static u32 qcom_smem_get_item_count(struct qcom_smem *smem) 703 { 704 struct smem_ptable *ptable; 705 struct smem_info *info; 706 707 ptable = qcom_smem_get_ptable(smem); 708 if (IS_ERR_OR_NULL(ptable)) 709 return SMEM_ITEM_COUNT; 710 711 info = (struct smem_info *)&ptable->entry[ptable->num_entries]; 712 if (memcmp(info->magic, SMEM_INFO_MAGIC, sizeof(info->magic))) 713 return SMEM_ITEM_COUNT; 714 715 return le16_to_cpu(info->num_items); 716 } 717 718 /* 719 * Validate the partition header for a partition whose partition 720 * table entry is supplied. Returns a pointer to its header if 721 * valid, or a null pointer otherwise. 722 */ 723 static struct smem_partition_header * 724 qcom_smem_partition_header(struct qcom_smem *smem, 725 struct smem_ptable_entry *entry, u16 host0, u16 host1) 726 { 727 struct smem_partition_header *header; 728 u32 size; 729 730 header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); 731 732 if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) { 733 dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n", 734 header->magic[0], header->magic[1], 735 header->magic[2], header->magic[3]); 736 return NULL; 737 } 738 739 if (host0 != le16_to_cpu(header->host0)) { 740 dev_err(smem->dev, "bad host0 (%hu != %hu)\n", 741 host0, le16_to_cpu(header->host0)); 742 return NULL; 743 } 744 if (host1 != le16_to_cpu(header->host1)) { 745 dev_err(smem->dev, "bad host1 (%hu != %hu)\n", 746 host1, le16_to_cpu(header->host1)); 747 return NULL; 748 } 749 750 size = le32_to_cpu(header->size); 751 if (size != le32_to_cpu(entry->size)) { 752 dev_err(smem->dev, "bad partition size (%u != %u)\n", 753 size, le32_to_cpu(entry->size)); 754 return NULL; 755 } 756 757 if (le32_to_cpu(header->offset_free_uncached) > size) { 758 dev_err(smem->dev, "bad partition free uncached (%u > %u)\n", 759 le32_to_cpu(header->offset_free_uncached), size); 760 return NULL; 761 } 762 763 return header; 764 } 765 766 static int qcom_smem_set_global_partition(struct qcom_smem *smem) 767 { 768 struct smem_partition_header *header; 769 struct smem_ptable_entry *entry; 770 struct smem_ptable *ptable; 771 bool found = false; 772 int i; 773 774 if (smem->global_partition) { 775 dev_err(smem->dev, "Already found the global partition\n"); 776 return -EINVAL; 777 } 778 779 ptable = qcom_smem_get_ptable(smem); 780 if (IS_ERR(ptable)) 781 return PTR_ERR(ptable); 782 783 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { 784 entry = &ptable->entry[i]; 785 if (!le32_to_cpu(entry->offset)) 786 continue; 787 if (!le32_to_cpu(entry->size)) 788 continue; 789 790 if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST) 791 continue; 792 793 if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) { 794 found = true; 795 break; 796 } 797 } 798 799 if (!found) { 800 dev_err(smem->dev, "Missing entry for global partition\n"); 801 return -EINVAL; 802 } 803 804 header = qcom_smem_partition_header(smem, entry, 805 SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST); 806 if (!header) 807 return -EINVAL; 808 809 smem->global_partition = header; 810 smem->global_cacheline = le32_to_cpu(entry->cacheline); 811 812 return 0; 813 } 814 815 static int 816 qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host) 817 { 818 struct smem_partition_header *header; 819 struct smem_ptable_entry *entry; 820 struct smem_ptable *ptable; 821 unsigned int remote_host; 822 u16 host0, host1; 823 int i; 824 825 ptable = qcom_smem_get_ptable(smem); 826 if (IS_ERR(ptable)) 827 return PTR_ERR(ptable); 828 829 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { 830 entry = &ptable->entry[i]; 831 if (!le32_to_cpu(entry->offset)) 832 continue; 833 if (!le32_to_cpu(entry->size)) 834 continue; 835 836 host0 = le16_to_cpu(entry->host0); 837 host1 = le16_to_cpu(entry->host1); 838 if (host0 == local_host) 839 remote_host = host1; 840 else if (host1 == local_host) 841 remote_host = host0; 842 else 843 continue; 844 845 if (remote_host >= SMEM_HOST_COUNT) { 846 dev_err(smem->dev, "bad host %hu\n", remote_host); 847 return -EINVAL; 848 } 849 850 if (smem->partitions[remote_host]) { 851 dev_err(smem->dev, "duplicate host %hu\n", remote_host); 852 return -EINVAL; 853 } 854 855 header = qcom_smem_partition_header(smem, entry, host0, host1); 856 if (!header) 857 return -EINVAL; 858 859 smem->partitions[remote_host] = header; 860 smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); 861 } 862 863 return 0; 864 } 865 866 static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, 867 const char *name, int i) 868 { 869 struct device_node *np; 870 struct resource r; 871 resource_size_t size; 872 int ret; 873 874 np = of_parse_phandle(dev->of_node, name, 0); 875 if (!np) { 876 dev_err(dev, "No %s specified\n", name); 877 return -EINVAL; 878 } 879 880 ret = of_address_to_resource(np, 0, &r); 881 of_node_put(np); 882 if (ret) 883 return ret; 884 size = resource_size(&r); 885 886 smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); 887 if (!smem->regions[i].virt_base) 888 return -ENOMEM; 889 smem->regions[i].aux_base = (u32)r.start; 890 smem->regions[i].size = size; 891 892 return 0; 893 } 894 895 static int qcom_smem_probe(struct platform_device *pdev) 896 { 897 struct smem_header *header; 898 struct qcom_smem *smem; 899 size_t array_size; 900 int num_regions; 901 int hwlock_id; 902 u32 version; 903 int ret; 904 905 num_regions = 1; 906 if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) 907 num_regions++; 908 909 array_size = num_regions * sizeof(struct smem_region); 910 smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL); 911 if (!smem) 912 return -ENOMEM; 913 914 smem->dev = &pdev->dev; 915 smem->num_regions = num_regions; 916 917 ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0); 918 if (ret) 919 return ret; 920 921 if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev, 922 "qcom,rpm-msg-ram", 1))) 923 return ret; 924 925 header = smem->regions[0].virt_base; 926 if (le32_to_cpu(header->initialized) != 1 || 927 le32_to_cpu(header->reserved)) { 928 dev_err(&pdev->dev, "SMEM is not initialized by SBL\n"); 929 return -EINVAL; 930 } 931 932 version = qcom_smem_get_sbl_version(smem); 933 switch (version >> 16) { 934 case SMEM_GLOBAL_PART_VERSION: 935 ret = qcom_smem_set_global_partition(smem); 936 if (ret < 0) 937 return ret; 938 smem->item_count = qcom_smem_get_item_count(smem); 939 break; 940 case SMEM_GLOBAL_HEAP_VERSION: 941 smem->item_count = SMEM_ITEM_COUNT; 942 break; 943 default: 944 dev_err(&pdev->dev, "Unsupported SMEM version 0x%x\n", version); 945 return -EINVAL; 946 } 947 948 BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT); 949 ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); 950 if (ret < 0 && ret != -ENOENT) 951 return ret; 952 953 hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); 954 if (hwlock_id < 0) { 955 if (hwlock_id != -EPROBE_DEFER) 956 dev_err(&pdev->dev, "failed to retrieve hwlock\n"); 957 return hwlock_id; 958 } 959 960 smem->hwlock = hwspin_lock_request_specific(hwlock_id); 961 if (!smem->hwlock) 962 return -ENXIO; 963 964 __smem = smem; 965 966 return 0; 967 } 968 969 static int qcom_smem_remove(struct platform_device *pdev) 970 { 971 hwspin_lock_free(__smem->hwlock); 972 __smem = NULL; 973 974 return 0; 975 } 976 977 static const struct of_device_id qcom_smem_of_match[] = { 978 { .compatible = "qcom,smem" }, 979 {} 980 }; 981 MODULE_DEVICE_TABLE(of, qcom_smem_of_match); 982 983 static struct platform_driver qcom_smem_driver = { 984 .probe = qcom_smem_probe, 985 .remove = qcom_smem_remove, 986 .driver = { 987 .name = "qcom-smem", 988 .of_match_table = qcom_smem_of_match, 989 .suppress_bind_attrs = true, 990 }, 991 }; 992 993 static int __init qcom_smem_init(void) 994 { 995 return platform_driver_register(&qcom_smem_driver); 996 } 997 arch_initcall(qcom_smem_init); 998 999 static void __exit qcom_smem_exit(void) 1000 { 1001 platform_driver_unregister(&qcom_smem_driver); 1002 } 1003 module_exit(qcom_smem_exit) 1004 1005 MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>"); 1006 MODULE_DESCRIPTION("Qualcomm Shared Memory Manager"); 1007 MODULE_LICENSE("GPL v2"); 1008