diff options
Diffstat (limited to 'drivers/soc/qcom/smem.c')
-rw-r--r-- | drivers/soc/qcom/smem.c | 77 |
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); |