5555 * is hence the region between the cached and non-cached offsets. The header of
5656 * cached items comes after the data.
5757 *
58+ * Version 12 (SMEM_GLOBAL_PART_VERSION) changes the item alloc/get procedure
59+ * for the global heap. A new global partition is created from the global heap
60+ * region with partition type (SMEM_GLOBAL_HOST) and the max smem item count is
61+ * set by the bootloader.
5862 *
5963 * To synchronize allocations in the shared memory heaps a remote spinlock must
6064 * be held - currently lock number 3 of the sfpb or tcsr is used for this on all
6872 * version is a valid version as a sanity check.
6973 */
7074#define SMEM_MASTER_SBL_VERSION_INDEX 7
71- #define SMEM_EXPECTED_VERSION 11
75+ #define SMEM_GLOBAL_HEAP_VERSION 11
76+ #define SMEM_GLOBAL_PART_VERSION 12
7277
7378/*
7479 * The first 8 items are only to be allocated by the boot loader while
8287/* Processor/host identifier for the application processor */
8388#define SMEM_HOST_APPS 0
8489
90+ /* Processor/host identifier for the global partition */
91+ #define SMEM_GLOBAL_HOST 0xfffe
92+
8593/* Max number of processors/hosts in a system */
8694#define SMEM_HOST_COUNT 9
8795
@@ -230,6 +238,8 @@ struct smem_region {
230238 * struct qcom_smem - device data for the smem device
231239 * @dev: device pointer
232240 * @hwlock: reference to a hwspinlock
241+ * @global_partition: pointer to global partition when in use
242+ * @global_cacheline: cacheline size for global partition
233243 * @partitions: list of pointers to partitions affecting the current
234244 * processor/host
235245 * @cacheline: list of cacheline sizes for each host
@@ -241,6 +251,8 @@ struct qcom_smem {
241251
242252 struct hwspinlock * hwlock ;
243253
254+ struct smem_partition_header * global_partition ;
255+ size_t global_cacheline ;
244256 struct smem_partition_header * partitions [SMEM_HOST_COUNT ];
245257 size_t cacheline [SMEM_HOST_COUNT ];
246258
@@ -317,25 +329,23 @@ static struct qcom_smem *__smem;
317329#define HWSPINLOCK_TIMEOUT 1000
318330
319331static int qcom_smem_alloc_private (struct qcom_smem * smem ,
320- unsigned host ,
332+ struct smem_partition_header * phdr ,
321333 unsigned item ,
322334 size_t size )
323335{
324- struct smem_partition_header * phdr ;
325336 struct smem_private_entry * hdr , * end ;
326337 size_t alloc_size ;
327338 void * cached ;
328339
329- phdr = smem -> partitions [host ];
330340 hdr = phdr_to_first_uncached_entry (phdr );
331341 end = phdr_to_last_uncached_entry (phdr );
332342 cached = phdr_to_last_cached_entry (phdr );
333343
334344 while (hdr < end ) {
335345 if (hdr -> canary != SMEM_PRIVATE_CANARY ) {
336346 dev_err (smem -> dev ,
337- "Found invalid canary in host %d partition\n" ,
338- host );
347+ "Found invalid canary in hosts %d: %d partition\n" ,
348+ phdr -> host0 , phdr -> host1 );
339349 return - EINVAL ;
340350 }
341351
@@ -373,8 +383,8 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem,
373383 unsigned item ,
374384 size_t size )
375385{
376- struct smem_header * header ;
377386 struct smem_global_entry * entry ;
387+ struct smem_header * header ;
378388
379389 if (WARN_ON (item >= SMEM_ITEM_COUNT ))
380390 return - EINVAL ;
@@ -416,6 +426,7 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem,
416426 */
417427int qcom_smem_alloc (unsigned host , unsigned item , size_t size )
418428{
429+ struct smem_partition_header * phdr ;
419430 unsigned long flags ;
420431 int ret ;
421432
@@ -434,10 +445,15 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
434445 if (ret )
435446 return ret ;
436447
437- if (host < SMEM_HOST_COUNT && __smem -> partitions [host ])
438- ret = qcom_smem_alloc_private (__smem , host , item , size );
439- else
448+ if (host < SMEM_HOST_COUNT && __smem -> partitions [host ]) {
449+ phdr = __smem -> partitions [host ];
450+ ret = qcom_smem_alloc_private (__smem , phdr , item , size );
451+ } else if (__smem -> global_partition ) {
452+ phdr = __smem -> global_partition ;
453+ ret = qcom_smem_alloc_private (__smem , phdr , item , size );
454+ } else {
440455 ret = qcom_smem_alloc_global (__smem , item , size );
456+ }
441457
442458 hwspin_unlock_irqrestore (__smem -> hwlock , & flags );
443459
@@ -479,16 +495,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
479495}
480496
481497static void * qcom_smem_get_private (struct qcom_smem * smem ,
482- unsigned host ,
498+ struct smem_partition_header * phdr ,
499+ size_t cacheline ,
483500 unsigned item ,
484501 size_t * size )
485502{
486- struct smem_partition_header * phdr ;
487503 struct smem_private_entry * e , * end ;
488- size_t cacheline ;
489-
490- phdr = smem -> partitions [host ];
491- cacheline = smem -> cacheline [host ];
492504
493505 e = phdr_to_first_uncached_entry (phdr );
494506 end = phdr_to_last_uncached_entry (phdr );
@@ -531,7 +543,8 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
531543 return ERR_PTR (- ENOENT );
532544
533545invalid_canary :
534- dev_err (smem -> dev , "Found invalid canary in host %d partition\n" , host );
546+ dev_err (smem -> dev , "Found invalid canary in hosts %d:%d partition\n" ,
547+ phdr -> host0 , phdr -> host1 );
535548
536549 return ERR_PTR (- EINVAL );
537550}
@@ -547,7 +560,9 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
547560 */
548561void * qcom_smem_get (unsigned host , unsigned item , size_t * size )
549562{
563+ struct smem_partition_header * phdr ;
550564 unsigned long flags ;
565+ size_t cacheln ;
551566 int ret ;
552567 void * ptr = ERR_PTR (- EPROBE_DEFER );
553568
@@ -560,10 +575,17 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
560575 if (ret )
561576 return ERR_PTR (ret );
562577
563- if (host < SMEM_HOST_COUNT && __smem -> partitions [host ])
564- ptr = qcom_smem_get_private (__smem , host , item , size );
565- else
578+ if (host < SMEM_HOST_COUNT && __smem -> partitions [host ]) {
579+ phdr = __smem -> partitions [host ];
580+ cacheln = __smem -> cacheline [host ];
581+ ptr = qcom_smem_get_private (__smem , phdr , cacheln , item , size );
582+ } else if (__smem -> global_partition ) {
583+ phdr = __smem -> global_partition ;
584+ cacheln = __smem -> global_cacheline ;
585+ ptr = qcom_smem_get_private (__smem , phdr , cacheln , item , size );
586+ } else {
566587 ptr = qcom_smem_get_global (__smem , item , size );
588+ }
567589
568590 hwspin_unlock_irqrestore (__smem -> hwlock , & flags );
569591
@@ -592,6 +614,10 @@ int qcom_smem_get_free_space(unsigned host)
592614 phdr = __smem -> partitions [host ];
593615 ret = le32_to_cpu (phdr -> offset_free_cached ) -
594616 le32_to_cpu (phdr -> offset_free_uncached );
617+ } else if (__smem -> global_partition ) {
618+ phdr = __smem -> global_partition ;
619+ ret = le32_to_cpu (phdr -> offset_free_cached ) -
620+ le32_to_cpu (phdr -> offset_free_uncached );
595621 } else {
596622 header = __smem -> regions [0 ].virt_base ;
597623 ret = le32_to_cpu (header -> available );
@@ -612,27 +638,106 @@ static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
612638 return le32_to_cpu (versions [SMEM_MASTER_SBL_VERSION_INDEX ]);
613639}
614640
615- static int qcom_smem_enumerate_partitions (struct qcom_smem * smem ,
616- unsigned local_host )
641+ static struct smem_ptable * qcom_smem_get_ptable (struct qcom_smem * smem )
617642{
618- struct smem_partition_header * header ;
619- struct smem_ptable_entry * entry ;
620643 struct smem_ptable * ptable ;
621- unsigned remote_host ;
622- u32 version , host0 , host1 ;
623- int i ;
644+ u32 version ;
624645
625646 ptable = smem -> regions [0 ].virt_base + smem -> regions [0 ].size - SZ_4K ;
626647 if (memcmp (ptable -> magic , SMEM_PTABLE_MAGIC , sizeof (ptable -> magic )))
627- return 0 ;
648+ return ERR_PTR ( - ENOENT ) ;
628649
629650 version = le32_to_cpu (ptable -> version );
630651 if (version != 1 ) {
631652 dev_err (smem -> dev ,
632653 "Unsupported partition header version %d\n" , version );
654+ return ERR_PTR (- EINVAL );
655+ }
656+ return ptable ;
657+ }
658+
659+ static int qcom_smem_set_global_partition (struct qcom_smem * smem )
660+ {
661+ struct smem_partition_header * header ;
662+ struct smem_ptable_entry * entry = NULL ;
663+ struct smem_ptable * ptable ;
664+ u32 host0 , host1 , size ;
665+ int i ;
666+
667+ ptable = qcom_smem_get_ptable (smem );
668+ if (IS_ERR (ptable ))
669+ return PTR_ERR (ptable );
670+
671+ for (i = 0 ; i < le32_to_cpu (ptable -> num_entries ); i ++ ) {
672+ entry = & ptable -> entry [i ];
673+ host0 = le16_to_cpu (entry -> host0 );
674+ host1 = le16_to_cpu (entry -> host1 );
675+
676+ if (host0 == SMEM_GLOBAL_HOST && host0 == host1 )
677+ break ;
678+ }
679+
680+ if (!entry ) {
681+ dev_err (smem -> dev , "Missing entry for global partition\n" );
682+ return - EINVAL ;
683+ }
684+
685+ if (!le32_to_cpu (entry -> offset ) || !le32_to_cpu (entry -> size )) {
686+ dev_err (smem -> dev , "Invalid entry for global partition\n" );
687+ return - EINVAL ;
688+ }
689+
690+ if (smem -> global_partition ) {
691+ dev_err (smem -> dev , "Already found the global partition\n" );
692+ return - EINVAL ;
693+ }
694+
695+ header = smem -> regions [0 ].virt_base + le32_to_cpu (entry -> offset );
696+ host0 = le16_to_cpu (header -> host0 );
697+ host1 = le16_to_cpu (header -> host1 );
698+
699+ if (memcmp (header -> magic , SMEM_PART_MAGIC , sizeof (header -> magic ))) {
700+ dev_err (smem -> dev , "Global partition has invalid magic\n" );
701+ return - EINVAL ;
702+ }
703+
704+ if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST ) {
705+ dev_err (smem -> dev , "Global partition hosts are invalid\n" );
706+ return - EINVAL ;
707+ }
708+
709+ if (le32_to_cpu (header -> size ) != le32_to_cpu (entry -> size )) {
710+ dev_err (smem -> dev , "Global partition has invalid size\n" );
633711 return - EINVAL ;
634712 }
635713
714+ size = le32_to_cpu (header -> offset_free_uncached );
715+ if (size > le32_to_cpu (header -> size )) {
716+ dev_err (smem -> dev ,
717+ "Global partition has invalid free pointer\n" );
718+ return - EINVAL ;
719+ }
720+
721+ smem -> global_partition = header ;
722+ smem -> global_cacheline = le32_to_cpu (entry -> cacheline );
723+
724+ return 0 ;
725+ }
726+
727+ static int qcom_smem_enumerate_partitions (struct qcom_smem * smem ,
728+ unsigned int local_host )
729+ {
730+ struct smem_partition_header * header ;
731+ struct smem_ptable_entry * entry ;
732+ struct smem_ptable * ptable ;
733+ unsigned int remote_host ;
734+ u32 host0 , host1 ;
735+ int i ;
736+
737+ ptable = qcom_smem_get_ptable (smem );
738+ if (IS_ERR (ptable ))
739+ return PTR_ERR (ptable );
740+
636741 for (i = 0 ; i < le32_to_cpu (ptable -> num_entries ); i ++ ) {
637742 entry = & ptable -> entry [i ];
638743 host0 = le16_to_cpu (entry -> host0 );
@@ -773,13 +878,20 @@ static int qcom_smem_probe(struct platform_device *pdev)
773878 }
774879
775880 version = qcom_smem_get_sbl_version (smem );
776- if (version >> 16 != SMEM_EXPECTED_VERSION ) {
881+ switch (version >> 16 ) {
882+ case SMEM_GLOBAL_PART_VERSION :
883+ ret = qcom_smem_set_global_partition (smem );
884+ if (ret < 0 )
885+ return ret ;
886+ case SMEM_GLOBAL_HEAP_VERSION :
887+ break ;
888+ default :
777889 dev_err (& pdev -> dev , "Unsupported SMEM version 0x%x\n" , version );
778890 return - EINVAL ;
779891 }
780892
781893 ret = qcom_smem_enumerate_partitions (smem , SMEM_HOST_APPS );
782- if (ret < 0 )
894+ if (ret < 0 && ret != - ENOENT )
783895 return ret ;
784896
785897 hwlock_id = of_hwspin_lock_get_id (pdev -> dev .of_node , 0 );
0 commit comments