summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/smem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/qcom/smem.c')
-rw-r--r--drivers/soc/qcom/smem.c77
1 files changed, 55 insertions, 22 deletions
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 0b94d62fad2b..70b2ee80d6bd 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -280,7 +280,7 @@ struct qcom_smem {
struct smem_region regions[0];
};
-static struct smem_private_entry *
+static void *
phdr_to_last_uncached_entry(struct smem_partition_header *phdr)
{
void *p = phdr;
@@ -288,15 +288,18 @@ phdr_to_last_uncached_entry(struct smem_partition_header *phdr)
return p + le32_to_cpu(phdr->offset_free_uncached);
}
-static void *phdr_to_first_cached_entry(struct smem_partition_header *phdr,
+static struct smem_private_entry *
+phdr_to_first_cached_entry(struct smem_partition_header *phdr,
size_t cacheline)
{
void *p = phdr;
+ struct smem_private_entry *e;
- return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*phdr), cacheline);
+ return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*e), cacheline);
}
-static void *phdr_to_last_cached_entry(struct smem_partition_header *phdr)
+static void *
+phdr_to_last_cached_entry(struct smem_partition_header *phdr)
{
void *p = phdr;
@@ -361,14 +364,14 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
end = phdr_to_last_uncached_entry(phdr);
cached = phdr_to_last_cached_entry(phdr);
- while (hdr < end) {
- if (hdr->canary != SMEM_PRIVATE_CANARY) {
- dev_err(smem->dev,
- "Found invalid canary in hosts %d:%d partition\n",
- phdr->host0, phdr->host1);
- return -EINVAL;
- }
+ if (smem->global_partition) {
+ dev_err(smem->dev, "Already found the global partition\n");
+ return -EINVAL;
+ }
+ while (hdr < end) {
+ if (hdr->canary != SMEM_PRIVATE_CANARY)
+ goto bad_canary;
if (le16_to_cpu(hdr->item) == item)
return -EEXIST;
@@ -377,7 +380,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
/* Check that we don't grow into the cached region */
alloc_size = sizeof(*hdr) + ALIGN(size, 8);
- if ((void *)hdr + alloc_size >= cached) {
+ if ((void *)hdr + alloc_size > cached) {
dev_err(smem->dev, "Out of memory\n");
return -ENOSPC;
}
@@ -397,6 +400,11 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
le32_add_cpu(&phdr->offset_free_uncached, alloc_size);
return 0;
+bad_canary:
+ dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
+ le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
+
+ return -EINVAL;
}
static int qcom_smem_alloc_global(struct qcom_smem *smem,
@@ -560,8 +568,8 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
return ERR_PTR(-ENOENT);
invalid_canary:
- dev_err(smem->dev, "Found invalid canary in hosts %d:%d partition\n",
- phdr->host0, phdr->host1);
+ dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
+ le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
return ERR_PTR(-EINVAL);
}
@@ -647,6 +655,33 @@ int qcom_smem_get_free_space(unsigned host)
}
EXPORT_SYMBOL(qcom_smem_get_free_space);
+/**
+ * qcom_smem_virt_to_phys() - return the physical address associated
+ * with an smem item pointer (previously returned by qcom_smem_get()
+ * @p: the virtual address to convert
+ *
+ * Returns 0 if the pointer provided is not within any smem region.
+ */
+phys_addr_t qcom_smem_virt_to_phys(void *p)
+{
+ unsigned i;
+
+ for (i = 0; i < __smem->num_regions; i++) {
+ struct smem_region *region = &__smem->regions[i];
+
+ if (p < region->virt_base)
+ continue;
+ if (p < region->virt_base + region->size) {
+ u64 offset = p - region->virt_base;
+
+ return (phys_addr_t)region->aux_base + offset;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(qcom_smem_virt_to_phys);
+
static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
{
struct smem_header *header;
@@ -695,9 +730,10 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
static int qcom_smem_set_global_partition(struct qcom_smem *smem)
{
struct smem_partition_header *header;
- struct smem_ptable_entry *entry = NULL;
+ struct smem_ptable_entry *entry;
struct smem_ptable *ptable;
u32 host0, host1, size;
+ bool found = false;
int i;
ptable = qcom_smem_get_ptable(smem);
@@ -709,11 +745,13 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
host0 = le16_to_cpu(entry->host0);
host1 = le16_to_cpu(entry->host1);
- if (host0 == SMEM_GLOBAL_HOST && host0 == host1)
+ if (host0 == SMEM_GLOBAL_HOST && host0 == host1) {
+ found = true;
break;
+ }
}
- if (!entry) {
+ if (!found) {
dev_err(smem->dev, "Missing entry for global partition\n");
return -EINVAL;
}
@@ -723,11 +761,6 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
return -EINVAL;
}
- if (smem->global_partition) {
- dev_err(smem->dev, "Already found the global partition\n");
- return -EINVAL;
- }
-
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
host0 = le16_to_cpu(header->host0);
host1 = le16_to_cpu(header->host1);