hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/soc/qcom/smem.c
....@@ -1,15 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (c) 2015, Sony Mobile Communications AB.
34 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License version 2 and
7
- * only version 2 as published by the Free Software Foundation.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
135 */
146
157 #include <linux/hwspinlock.h>
....@@ -18,6 +10,7 @@
1810 #include <linux/of.h>
1911 #include <linux/of_address.h>
2012 #include <linux/platform_device.h>
13
+#include <linux/sizes.h>
2114 #include <linux/slab.h>
2215 #include <linux/soc/qcom/smem.h>
2316
....@@ -91,7 +84,7 @@
9184 #define SMEM_GLOBAL_HOST 0xfffe
9285
9386 /* Max number of processors/hosts in a system */
94
-#define SMEM_HOST_COUNT 10
87
+#define SMEM_HOST_COUNT 11
9588
9689 /**
9790 * struct smem_proc_comm - proc_comm communication struct (legacy)
....@@ -275,9 +268,10 @@
275268 struct smem_partition_header *partitions[SMEM_HOST_COUNT];
276269 size_t cacheline[SMEM_HOST_COUNT];
277270 u32 item_count;
271
+ struct platform_device *socinfo;
278272
279273 unsigned num_regions;
280
- struct smem_region regions[0];
274
+ struct smem_region regions[];
281275 };
282276
283277 static void *
....@@ -489,7 +483,7 @@
489483 size_t *size)
490484 {
491485 struct smem_header *header;
492
- struct smem_region *area;
486
+ struct smem_region *region;
493487 struct smem_global_entry *entry;
494488 u32 aux_base;
495489 unsigned i;
....@@ -502,12 +496,12 @@
502496 aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
503497
504498 for (i = 0; i < smem->num_regions; i++) {
505
- area = &smem->regions[i];
499
+ region = &smem->regions[i];
506500
507
- if (area->aux_base == aux_base || !aux_base) {
501
+ if (region->aux_base == aux_base || !aux_base) {
508502 if (size != NULL)
509503 *size = le32_to_cpu(entry->size);
510
- return area->virt_base + le32_to_cpu(entry->offset);
504
+ return region->virt_base + le32_to_cpu(entry->offset);
511505 }
512506 }
513507
....@@ -722,12 +716,59 @@
722716 return le16_to_cpu(info->num_items);
723717 }
724718
719
+/*
720
+ * Validate the partition header for a partition whose partition
721
+ * table entry is supplied. Returns a pointer to its header if
722
+ * valid, or a null pointer otherwise.
723
+ */
724
+static struct smem_partition_header *
725
+qcom_smem_partition_header(struct qcom_smem *smem,
726
+ struct smem_ptable_entry *entry, u16 host0, u16 host1)
727
+{
728
+ struct smem_partition_header *header;
729
+ u32 size;
730
+
731
+ header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
732
+
733
+ if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
734
+ dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n",
735
+ header->magic[0], header->magic[1],
736
+ header->magic[2], header->magic[3]);
737
+ return NULL;
738
+ }
739
+
740
+ if (host0 != le16_to_cpu(header->host0)) {
741
+ dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
742
+ host0, le16_to_cpu(header->host0));
743
+ return NULL;
744
+ }
745
+ if (host1 != le16_to_cpu(header->host1)) {
746
+ dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
747
+ host1, le16_to_cpu(header->host1));
748
+ return NULL;
749
+ }
750
+
751
+ size = le32_to_cpu(header->size);
752
+ if (size != le32_to_cpu(entry->size)) {
753
+ dev_err(smem->dev, "bad partition size (%u != %u)\n",
754
+ size, le32_to_cpu(entry->size));
755
+ return NULL;
756
+ }
757
+
758
+ if (le32_to_cpu(header->offset_free_uncached) > size) {
759
+ dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
760
+ le32_to_cpu(header->offset_free_uncached), size);
761
+ return NULL;
762
+ }
763
+
764
+ return header;
765
+}
766
+
725767 static int qcom_smem_set_global_partition(struct qcom_smem *smem)
726768 {
727769 struct smem_partition_header *header;
728770 struct smem_ptable_entry *entry;
729771 struct smem_ptable *ptable;
730
- u32 host0, host1, size;
731772 bool found = false;
732773 int i;
733774
....@@ -742,10 +783,15 @@
742783
743784 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
744785 entry = &ptable->entry[i];
745
- host0 = le16_to_cpu(entry->host0);
746
- host1 = le16_to_cpu(entry->host1);
786
+ if (!le32_to_cpu(entry->offset))
787
+ continue;
788
+ if (!le32_to_cpu(entry->size))
789
+ continue;
747790
748
- if (host0 == SMEM_GLOBAL_HOST && host0 == host1) {
791
+ if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
792
+ continue;
793
+
794
+ if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
749795 found = true;
750796 break;
751797 }
....@@ -756,36 +802,10 @@
756802 return -EINVAL;
757803 }
758804
759
- if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) {
760
- dev_err(smem->dev, "Invalid entry for global partition\n");
805
+ header = qcom_smem_partition_header(smem, entry,
806
+ SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
807
+ if (!header)
761808 return -EINVAL;
762
- }
763
-
764
- header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
765
- host0 = le16_to_cpu(header->host0);
766
- host1 = le16_to_cpu(header->host1);
767
-
768
- if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
769
- dev_err(smem->dev, "Global partition has invalid magic\n");
770
- return -EINVAL;
771
- }
772
-
773
- if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) {
774
- dev_err(smem->dev, "Global partition hosts are invalid\n");
775
- return -EINVAL;
776
- }
777
-
778
- if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
779
- dev_err(smem->dev, "Global partition has invalid size\n");
780
- return -EINVAL;
781
- }
782
-
783
- size = le32_to_cpu(header->offset_free_uncached);
784
- if (size > le32_to_cpu(header->size)) {
785
- dev_err(smem->dev,
786
- "Global partition has invalid free pointer\n");
787
- return -EINVAL;
788
- }
789809
790810 smem->global_partition = header;
791811 smem->global_cacheline = le32_to_cpu(entry->cacheline);
....@@ -793,14 +813,14 @@
793813 return 0;
794814 }
795815
796
-static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
797
- unsigned int local_host)
816
+static int
817
+qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
798818 {
799819 struct smem_partition_header *header;
800820 struct smem_ptable_entry *entry;
801821 struct smem_ptable *ptable;
802822 unsigned int remote_host;
803
- u32 host0, host1;
823
+ u16 host0, host1;
804824 int i;
805825
806826 ptable = qcom_smem_get_ptable(smem);
....@@ -809,71 +829,33 @@
809829
810830 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
811831 entry = &ptable->entry[i];
812
- host0 = le16_to_cpu(entry->host0);
813
- host1 = le16_to_cpu(entry->host1);
814
-
815
- if (host0 != local_host && host1 != local_host)
816
- continue;
817
-
818832 if (!le32_to_cpu(entry->offset))
819833 continue;
820
-
821834 if (!le32_to_cpu(entry->size))
822835 continue;
823836
837
+ host0 = le16_to_cpu(entry->host0);
838
+ host1 = le16_to_cpu(entry->host1);
824839 if (host0 == local_host)
825840 remote_host = host1;
826
- else
841
+ else if (host1 == local_host)
827842 remote_host = host0;
843
+ else
844
+ continue;
828845
829846 if (remote_host >= SMEM_HOST_COUNT) {
830
- dev_err(smem->dev,
831
- "Invalid remote host %d\n",
832
- remote_host);
847
+ dev_err(smem->dev, "bad host %hu\n", remote_host);
833848 return -EINVAL;
834849 }
835850
836851 if (smem->partitions[remote_host]) {
837
- dev_err(smem->dev,
838
- "Already found a partition for host %d\n",
839
- remote_host);
852
+ dev_err(smem->dev, "duplicate host %hu\n", remote_host);
840853 return -EINVAL;
841854 }
842855
843
- header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
844
- host0 = le16_to_cpu(header->host0);
845
- host1 = le16_to_cpu(header->host1);
846
-
847
- if (memcmp(header->magic, SMEM_PART_MAGIC,
848
- sizeof(header->magic))) {
849
- dev_err(smem->dev,
850
- "Partition %d has invalid magic\n", i);
856
+ header = qcom_smem_partition_header(smem, entry, host0, host1);
857
+ if (!header)
851858 return -EINVAL;
852
- }
853
-
854
- if (host0 != local_host && host1 != local_host) {
855
- dev_err(smem->dev,
856
- "Partition %d hosts are invalid\n", i);
857
- return -EINVAL;
858
- }
859
-
860
- if (host0 != remote_host && host1 != remote_host) {
861
- dev_err(smem->dev,
862
- "Partition %d hosts are invalid\n", i);
863
- return -EINVAL;
864
- }
865
-
866
- if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
867
- dev_err(smem->dev,
868
- "Partition %d has invalid size\n", i);
869
- return -EINVAL;
870
- }
871
-
872
- if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) {
873
- dev_err(smem->dev,
874
- "Partition %d has invalid free pointer\n", i);
875
- return -EINVAL;
876
- }
877859
878860 smem->partitions[remote_host] = header;
879861 smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline);
....@@ -887,6 +869,7 @@
887869 {
888870 struct device_node *np;
889871 struct resource r;
872
+ resource_size_t size;
890873 int ret;
891874
892875 np = of_parse_phandle(dev->of_node, name, 0);
....@@ -899,12 +882,13 @@
899882 of_node_put(np);
900883 if (ret)
901884 return ret;
885
+ size = resource_size(&r);
902886
903
- smem->regions[i].aux_base = (u32)r.start;
904
- smem->regions[i].size = resource_size(&r);
905
- smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
887
+ smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
906888 if (!smem->regions[i].virt_base)
907889 return -ENOMEM;
890
+ smem->regions[i].aux_base = (u32)r.start;
891
+ smem->regions[i].size = size;
908892
909893 return 0;
910894 }
....@@ -962,6 +946,7 @@
962946 return -EINVAL;
963947 }
964948
949
+ BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
965950 ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
966951 if (ret < 0 && ret != -ENOENT)
967952 return ret;
....@@ -979,11 +964,19 @@
979964
980965 __smem = smem;
981966
967
+ smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
968
+ PLATFORM_DEVID_NONE, NULL,
969
+ 0);
970
+ if (IS_ERR(smem->socinfo))
971
+ dev_dbg(&pdev->dev, "failed to register socinfo device\n");
972
+
982973 return 0;
983974 }
984975
985976 static int qcom_smem_remove(struct platform_device *pdev)
986977 {
978
+ platform_device_unregister(__smem->socinfo);
979
+
987980 hwspin_lock_free(__smem->hwlock);
988981 __smem = NULL;
989982