From 01f141544413aa5de45d3979b8aafa9aaf6f9b9f Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 4 Oct 2017 20:11:27 -0700 Subject: soc: qcom: smem: Rename "uncached" accessors In preparation for adding accessors for "cached" entries rename the "uncached" accessors. Also rename "first" cached entry to "last", as the cached list grows backwards. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 18ec52f2078a..b451dbc4aa39 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -245,14 +245,14 @@ struct qcom_smem { }; static struct smem_private_entry * -phdr_to_last_private_entry(struct smem_partition_header *phdr) +phdr_to_last_uncached_entry(struct smem_partition_header *phdr) { void *p = phdr; return p + le32_to_cpu(phdr->offset_free_uncached); } -static void *phdr_to_first_cached_entry(struct smem_partition_header *phdr) +static void *phdr_to_last_cached_entry(struct smem_partition_header *phdr) { void *p = phdr; @@ -260,7 +260,7 @@ static void *phdr_to_first_cached_entry(struct smem_partition_header *phdr) } static struct smem_private_entry * -phdr_to_first_private_entry(struct smem_partition_header *phdr) +phdr_to_first_uncached_entry(struct smem_partition_header *phdr) { void *p = phdr; @@ -268,7 +268,7 @@ phdr_to_first_private_entry(struct smem_partition_header *phdr) } static struct smem_private_entry * -private_entry_next(struct smem_private_entry *e) +uncached_entry_next(struct smem_private_entry *e) { void *p = e; @@ -276,7 +276,7 @@ private_entry_next(struct smem_private_entry *e) le32_to_cpu(e->size); } -static void *entry_to_item(struct smem_private_entry *e) +static void *uncached_entry_to_item(struct smem_private_entry *e) { void *p = e; @@ -300,9 +300,9 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, void *cached; phdr = smem->partitions[host]; - hdr = phdr_to_first_private_entry(phdr); - end = phdr_to_last_private_entry(phdr); - cached = phdr_to_first_cached_entry(phdr); + hdr = phdr_to_first_uncached_entry(phdr); + end = phdr_to_last_uncached_entry(phdr); + cached = phdr_to_last_cached_entry(phdr); while (hdr < end) { if (hdr->canary != SMEM_PRIVATE_CANARY) { @@ -315,7 +315,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, if (le16_to_cpu(hdr->item) == item) return -EEXIST; - hdr = private_entry_next(hdr); + hdr = uncached_entry_next(hdr); } /* Check that we don't grow into the cached region */ @@ -460,8 +460,8 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, struct smem_private_entry *e, *end; phdr = smem->partitions[host]; - e = phdr_to_first_private_entry(phdr); - end = phdr_to_last_private_entry(phdr); + e = phdr_to_first_uncached_entry(phdr); + end = phdr_to_last_uncached_entry(phdr); while (e < end) { if (e->canary != SMEM_PRIVATE_CANARY) { @@ -476,10 +476,10 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, *size = le32_to_cpu(e->size) - le16_to_cpu(e->padding_data); - return entry_to_item(e); + return uncached_entry_to_item(e); } - e = private_entry_next(e); + e = uncached_entry_next(e); } return ERR_PTR(-ENOENT); -- cgit From c7c1dc35871378ede5f117dc9c2a7ce1cecd4449 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 4 Oct 2017 20:11:28 -0700 Subject: soc: qcom: smem: Support getting cached entries On msm8996 cached SMEM items are used for storing the GLINK FIFOs, so for items not found in the uncached list we need to also search the cased list for these items. Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 69 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 8 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index b451dbc4aa39..c28275be0038 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -52,7 +52,8 @@ * * Items in the non-cached region are allocated from the start of the partition * while items in the cached region are allocated from the end. The free area - * is hence the region between the cached and non-cached offsets. + * is hence the region between the cached and non-cached offsets. The header of + * cached items comes after the data. * * * To synchronize allocations in the shared memory heaps a remote spinlock must @@ -140,6 +141,7 @@ struct smem_header { * @flags: flags for the partition (currently unused) * @host0: first processor/host with access to this partition * @host1: second processor/host with access to this partition + * @cacheline: alignment for "cached" entries * @reserved: reserved entries for later use */ struct smem_ptable_entry { @@ -148,7 +150,8 @@ struct smem_ptable_entry { __le32 flags; __le16 host0; __le16 host1; - __le32 reserved[8]; + __le32 cacheline; + __le32 reserved[7]; }; /** @@ -230,6 +233,7 @@ struct smem_region { * @hwlock: reference to a hwspinlock * @partitions: list of pointers to partitions affecting the current * processor/host + * @cacheline: list of cacheline sizes for each host * @num_regions: number of @regions * @regions: list of the memory regions defining the shared memory */ @@ -239,6 +243,7 @@ struct qcom_smem { struct hwspinlock *hwlock; struct smem_partition_header *partitions[SMEM_HOST_COUNT]; + size_t cacheline[SMEM_HOST_COUNT]; unsigned num_regions; struct smem_region regions[0]; @@ -252,6 +257,14 @@ 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, + size_t cacheline) +{ + void *p = phdr; + + return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*phdr), cacheline); +} + static void *phdr_to_last_cached_entry(struct smem_partition_header *phdr) { void *p = phdr; @@ -276,6 +289,14 @@ uncached_entry_next(struct smem_private_entry *e) le32_to_cpu(e->size); } +static struct smem_private_entry * +cached_entry_next(struct smem_private_entry *e, size_t cacheline) +{ + void *p = e; + + return p - le32_to_cpu(e->size) - ALIGN(sizeof(*e), cacheline); +} + static void *uncached_entry_to_item(struct smem_private_entry *e) { void *p = e; @@ -283,6 +304,13 @@ static void *uncached_entry_to_item(struct smem_private_entry *e) return p + sizeof(*e) + le16_to_cpu(e->padding_hdr); } +static void *cached_entry_to_item(struct smem_private_entry *e) +{ + void *p = e; + + return p - le32_to_cpu(e->size); +} + /* Pointer to the one and only smem handle */ static struct qcom_smem *__smem; @@ -458,18 +486,17 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, { struct smem_partition_header *phdr; struct smem_private_entry *e, *end; + size_t cacheline; phdr = smem->partitions[host]; + cacheline = smem->cacheline[host]; + e = phdr_to_first_uncached_entry(phdr); end = phdr_to_last_uncached_entry(phdr); while (e < end) { - if (e->canary != SMEM_PRIVATE_CANARY) { - dev_err(smem->dev, - "Found invalid canary in host %d partition\n", - host); - return ERR_PTR(-EINVAL); - } + if (e->canary != SMEM_PRIVATE_CANARY) + goto invalid_canary; if (le16_to_cpu(e->item) == item) { if (size != NULL) @@ -482,7 +509,32 @@ static void *qcom_smem_get_private(struct qcom_smem *smem, e = uncached_entry_next(e); } + /* Item was not found in the uncached list, search the cached list */ + + e = phdr_to_first_cached_entry(phdr, cacheline); + end = phdr_to_last_cached_entry(phdr); + + while (e > end) { + if (e->canary != SMEM_PRIVATE_CANARY) + goto invalid_canary; + + if (le16_to_cpu(e->item) == item) { + if (size != NULL) + *size = le32_to_cpu(e->size) - + le16_to_cpu(e->padding_data); + + return cached_entry_to_item(e); + } + + e = cached_entry_next(e, cacheline); + } + return ERR_PTR(-ENOENT); + +invalid_canary: + dev_err(smem->dev, "Found invalid canary in host %d partition\n", host); + + return ERR_PTR(-EINVAL); } /** @@ -659,6 +711,7 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, } smem->partitions[remote_host] = header; + smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); } return 0; -- cgit From a216000f0140f415cec96129f777b5234c9d142f Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Oct 2017 14:29:06 -0700 Subject: soc: qcom: smem: Use le32_to_cpu for comparison Endianness can vary in the system, add le32_to_cpu when comparing partition sizes from smem. Signed-off-by: Chris Lew Acked-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index c28275be0038..db04c45d4132 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -698,7 +698,7 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, return -EINVAL; } - if (header->size != entry->size) { + if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) { dev_err(smem->dev, "Partition %d has invalid size\n", i); return -EINVAL; -- cgit From dcc0967dd776cefe04856726a39195c1c5edbd2c Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Oct 2017 14:29:07 -0700 Subject: soc: qcom: smem: Read version from the smem header The SMEM header structure includes the version information. Read the version directly from the header instead of getting an item from the global heap. Signed-off-by: Chris Lew Acked-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index db04c45d4132..540322ae409e 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -63,13 +63,12 @@ */ /* - * Item 3 of the global heap contains an array of versions for the various - * software components in the SoC. We verify that the boot loader version is - * what the expected version (SMEM_EXPECTED_VERSION) as a sanity check. + * The version member of the smem header contains an array of versions for the + * various software components in the SoC. We verify that the boot loader + * version is a valid version as a sanity check. */ -#define SMEM_ITEM_VERSION 3 -#define SMEM_MASTER_SBL_VERSION_INDEX 7 -#define SMEM_EXPECTED_VERSION 11 +#define SMEM_MASTER_SBL_VERSION_INDEX 7 +#define SMEM_EXPECTED_VERSION 11 /* * The first 8 items are only to be allocated by the boot loader while @@ -604,19 +603,11 @@ EXPORT_SYMBOL(qcom_smem_get_free_space); static int qcom_smem_get_sbl_version(struct qcom_smem *smem) { + struct smem_header *header; __le32 *versions; - size_t size; - - versions = qcom_smem_get_global(smem, SMEM_ITEM_VERSION, &size); - if (IS_ERR(versions)) { - dev_err(smem->dev, "Unable to read the version item\n"); - return -ENOENT; - } - if (size < sizeof(unsigned) * SMEM_MASTER_SBL_VERSION_INDEX) { - dev_err(smem->dev, "Version item is too small\n"); - return -EINVAL; - } + header = smem->regions[0].virt_base; + versions = header->version; return le32_to_cpu(versions[SMEM_MASTER_SBL_VERSION_INDEX]); } -- cgit From d52e404874369f10d20519f4095478d9cb4d6aad Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Oct 2017 14:29:08 -0700 Subject: soc: qcom: smem: Support global partition SMEM V12 creates a global partition to allocate global smem items from instead of a global heap. The global partition has the same structure as a private partition. Signed-off-by: Chris Lew Acked-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 172 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 142 insertions(+), 30 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 540322ae409e..6a3134e9c591 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -55,6 +55,10 @@ * is hence the region between the cached and non-cached offsets. The header of * cached items comes after the data. * + * Version 12 (SMEM_GLOBAL_PART_VERSION) changes the item alloc/get procedure + * for the global heap. A new global partition is created from the global heap + * region with partition type (SMEM_GLOBAL_HOST) and the max smem item count is + * set by the bootloader. * * To synchronize allocations in the shared memory heaps a remote spinlock must * be held - currently lock number 3 of the sfpb or tcsr is used for this on all @@ -68,7 +72,8 @@ * version is a valid version as a sanity check. */ #define SMEM_MASTER_SBL_VERSION_INDEX 7 -#define SMEM_EXPECTED_VERSION 11 +#define SMEM_GLOBAL_HEAP_VERSION 11 +#define SMEM_GLOBAL_PART_VERSION 12 /* * The first 8 items are only to be allocated by the boot loader while @@ -82,6 +87,9 @@ /* Processor/host identifier for the application processor */ #define SMEM_HOST_APPS 0 +/* Processor/host identifier for the global partition */ +#define SMEM_GLOBAL_HOST 0xfffe + /* Max number of processors/hosts in a system */ #define SMEM_HOST_COUNT 9 @@ -230,6 +238,8 @@ struct smem_region { * struct qcom_smem - device data for the smem device * @dev: device pointer * @hwlock: reference to a hwspinlock + * @global_partition: pointer to global partition when in use + * @global_cacheline: cacheline size for global partition * @partitions: list of pointers to partitions affecting the current * processor/host * @cacheline: list of cacheline sizes for each host @@ -241,6 +251,8 @@ struct qcom_smem { struct hwspinlock *hwlock; + struct smem_partition_header *global_partition; + size_t global_cacheline; struct smem_partition_header *partitions[SMEM_HOST_COUNT]; size_t cacheline[SMEM_HOST_COUNT]; @@ -317,16 +329,14 @@ static struct qcom_smem *__smem; #define HWSPINLOCK_TIMEOUT 1000 static int qcom_smem_alloc_private(struct qcom_smem *smem, - unsigned host, + struct smem_partition_header *phdr, unsigned item, size_t size) { - struct smem_partition_header *phdr; struct smem_private_entry *hdr, *end; size_t alloc_size; void *cached; - phdr = smem->partitions[host]; hdr = phdr_to_first_uncached_entry(phdr); end = phdr_to_last_uncached_entry(phdr); cached = phdr_to_last_cached_entry(phdr); @@ -334,8 +344,8 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, while (hdr < end) { if (hdr->canary != SMEM_PRIVATE_CANARY) { dev_err(smem->dev, - "Found invalid canary in host %d partition\n", - host); + "Found invalid canary in hosts %d:%d partition\n", + phdr->host0, phdr->host1); return -EINVAL; } @@ -373,8 +383,8 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem, unsigned item, size_t size) { - struct smem_header *header; struct smem_global_entry *entry; + struct smem_header *header; if (WARN_ON(item >= SMEM_ITEM_COUNT)) return -EINVAL; @@ -416,6 +426,7 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem, */ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) { + struct smem_partition_header *phdr; unsigned long flags; int ret; @@ -434,10 +445,15 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) if (ret) return ret; - if (host < SMEM_HOST_COUNT && __smem->partitions[host]) - ret = qcom_smem_alloc_private(__smem, host, item, size); - else + if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { + phdr = __smem->partitions[host]; + ret = qcom_smem_alloc_private(__smem, phdr, item, size); + } else if (__smem->global_partition) { + phdr = __smem->global_partition; + ret = qcom_smem_alloc_private(__smem, phdr, item, size); + } else { ret = qcom_smem_alloc_global(__smem, item, size); + } hwspin_unlock_irqrestore(__smem->hwlock, &flags); @@ -479,16 +495,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, } static void *qcom_smem_get_private(struct qcom_smem *smem, - unsigned host, + struct smem_partition_header *phdr, + size_t cacheline, unsigned item, size_t *size) { - struct smem_partition_header *phdr; struct smem_private_entry *e, *end; - size_t cacheline; - - phdr = smem->partitions[host]; - cacheline = smem->cacheline[host]; e = phdr_to_first_uncached_entry(phdr); end = phdr_to_last_uncached_entry(phdr); @@ -531,7 +543,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 host %d partition\n", host); + dev_err(smem->dev, "Found invalid canary in hosts %d:%d partition\n", + phdr->host0, phdr->host1); return ERR_PTR(-EINVAL); } @@ -547,7 +560,9 @@ invalid_canary: */ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) { + struct smem_partition_header *phdr; unsigned long flags; + size_t cacheln; int ret; void *ptr = ERR_PTR(-EPROBE_DEFER); @@ -560,10 +575,17 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) if (ret) return ERR_PTR(ret); - if (host < SMEM_HOST_COUNT && __smem->partitions[host]) - ptr = qcom_smem_get_private(__smem, host, item, size); - else + if (host < SMEM_HOST_COUNT && __smem->partitions[host]) { + phdr = __smem->partitions[host]; + cacheln = __smem->cacheline[host]; + ptr = qcom_smem_get_private(__smem, phdr, cacheln, item, size); + } else if (__smem->global_partition) { + phdr = __smem->global_partition; + cacheln = __smem->global_cacheline; + ptr = qcom_smem_get_private(__smem, phdr, cacheln, item, size); + } else { ptr = qcom_smem_get_global(__smem, item, size); + } hwspin_unlock_irqrestore(__smem->hwlock, &flags); @@ -592,6 +614,10 @@ int qcom_smem_get_free_space(unsigned host) phdr = __smem->partitions[host]; ret = le32_to_cpu(phdr->offset_free_cached) - le32_to_cpu(phdr->offset_free_uncached); + } else if (__smem->global_partition) { + phdr = __smem->global_partition; + ret = le32_to_cpu(phdr->offset_free_cached) - + le32_to_cpu(phdr->offset_free_uncached); } else { header = __smem->regions[0].virt_base; ret = le32_to_cpu(header->available); @@ -612,27 +638,106 @@ static int qcom_smem_get_sbl_version(struct qcom_smem *smem) return le32_to_cpu(versions[SMEM_MASTER_SBL_VERSION_INDEX]); } -static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, - unsigned local_host) +static struct smem_ptable *qcom_smem_get_ptable(struct qcom_smem *smem) { - struct smem_partition_header *header; - struct smem_ptable_entry *entry; struct smem_ptable *ptable; - unsigned remote_host; - u32 version, host0, host1; - int i; + u32 version; ptable = smem->regions[0].virt_base + smem->regions[0].size - SZ_4K; if (memcmp(ptable->magic, SMEM_PTABLE_MAGIC, sizeof(ptable->magic))) - return 0; + return ERR_PTR(-ENOENT); version = le32_to_cpu(ptable->version); if (version != 1) { dev_err(smem->dev, "Unsupported partition header version %d\n", version); + return ERR_PTR(-EINVAL); + } + return ptable; +} + +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 *ptable; + u32 host0, host1, size; + int i; + + ptable = qcom_smem_get_ptable(smem); + if (IS_ERR(ptable)) + return PTR_ERR(ptable); + + for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { + entry = &ptable->entry[i]; + host0 = le16_to_cpu(entry->host0); + host1 = le16_to_cpu(entry->host1); + + if (host0 == SMEM_GLOBAL_HOST && host0 == host1) + break; + } + + if (!entry) { + dev_err(smem->dev, "Missing entry for global partition\n"); + return -EINVAL; + } + + if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) { + dev_err(smem->dev, "Invalid entry for global partition\n"); + 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); + + if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) { + dev_err(smem->dev, "Global partition has invalid magic\n"); + return -EINVAL; + } + + if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) { + dev_err(smem->dev, "Global partition hosts are invalid\n"); + return -EINVAL; + } + + if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) { + dev_err(smem->dev, "Global partition has invalid size\n"); return -EINVAL; } + size = le32_to_cpu(header->offset_free_uncached); + if (size > le32_to_cpu(header->size)) { + dev_err(smem->dev, + "Global partition has invalid free pointer\n"); + return -EINVAL; + } + + smem->global_partition = header; + smem->global_cacheline = le32_to_cpu(entry->cacheline); + + return 0; +} + +static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, + unsigned int local_host) +{ + struct smem_partition_header *header; + struct smem_ptable_entry *entry; + struct smem_ptable *ptable; + unsigned int remote_host; + u32 host0, host1; + int i; + + ptable = qcom_smem_get_ptable(smem); + if (IS_ERR(ptable)) + return PTR_ERR(ptable); + for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { entry = &ptable->entry[i]; host0 = le16_to_cpu(entry->host0); @@ -773,13 +878,20 @@ static int qcom_smem_probe(struct platform_device *pdev) } version = qcom_smem_get_sbl_version(smem); - if (version >> 16 != SMEM_EXPECTED_VERSION) { + switch (version >> 16) { + case SMEM_GLOBAL_PART_VERSION: + ret = qcom_smem_set_global_partition(smem); + if (ret < 0) + return ret; + case SMEM_GLOBAL_HEAP_VERSION: + break; + default: dev_err(&pdev->dev, "Unsupported SMEM version 0x%x\n", version); return -EINVAL; } ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); - if (ret < 0) + if (ret < 0 && ret != -ENOENT) return ret; hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); -- cgit From 5b3940676107dd65165b5eaea58fa60442d29a1f Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Oct 2017 14:29:09 -0700 Subject: soc: qcom: smem: Support dynamic item limit In V12 SMEM, SBL writes SMEM parameter information after the TOC. Use the SBL provided item count as the max item number. Signed-off-by: Chris Lew Acked-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 51 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 6a3134e9c591..19704baa65f4 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -222,6 +222,24 @@ struct smem_private_entry { }; #define SMEM_PRIVATE_CANARY 0xa5a5 +/** + * struct smem_info - smem region info located after the table of contents + * @magic: magic number, must be SMEM_INFO_MAGIC + * @size: size of the smem region + * @base_addr: base address of the smem region + * @reserved: for now reserved entry + * @num_items: highest accepted item number + */ +struct smem_info { + u8 magic[4]; + __le32 size; + __le32 base_addr; + __le32 reserved; + __le16 num_items; +}; + +static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */ + /** * struct smem_region - representation of a chunk of memory used for smem * @aux_base: identifier of aux_mem base @@ -243,6 +261,7 @@ struct smem_region { * @partitions: list of pointers to partitions affecting the current * processor/host * @cacheline: list of cacheline sizes for each host + * @item_count: max accepted item number * @num_regions: number of @regions * @regions: list of the memory regions defining the shared memory */ @@ -255,6 +274,7 @@ struct qcom_smem { size_t global_cacheline; struct smem_partition_header *partitions[SMEM_HOST_COUNT]; size_t cacheline[SMEM_HOST_COUNT]; + u32 item_count; unsigned num_regions; struct smem_region regions[0]; @@ -386,9 +406,6 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem, struct smem_global_entry *entry; struct smem_header *header; - if (WARN_ON(item >= SMEM_ITEM_COUNT)) - return -EINVAL; - header = smem->regions[0].virt_base; entry = &header->toc[item]; if (entry->allocated) @@ -439,6 +456,9 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) return -EINVAL; } + if (WARN_ON(item >= __smem->item_count)) + return -EINVAL; + ret = hwspin_lock_timeout_irqsave(__smem->hwlock, HWSPINLOCK_TIMEOUT, &flags); @@ -471,9 +491,6 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, u32 aux_base; unsigned i; - if (WARN_ON(item >= SMEM_ITEM_COUNT)) - return ERR_PTR(-EINVAL); - header = smem->regions[0].virt_base; entry = &header->toc[item]; if (!entry->allocated) @@ -569,6 +586,9 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) if (!__smem) return ptr; + if (WARN_ON(item >= __smem->item_count)) + return ERR_PTR(-EINVAL); + ret = hwspin_lock_timeout_irqsave(__smem->hwlock, HWSPINLOCK_TIMEOUT, &flags); @@ -656,6 +676,22 @@ static struct smem_ptable *qcom_smem_get_ptable(struct qcom_smem *smem) return ptable; } +static u32 qcom_smem_get_item_count(struct qcom_smem *smem) +{ + struct smem_ptable *ptable; + struct smem_info *info; + + ptable = qcom_smem_get_ptable(smem); + if (IS_ERR_OR_NULL(ptable)) + return SMEM_ITEM_COUNT; + + info = (struct smem_info *)&ptable->entry[ptable->num_entries]; + if (memcmp(info->magic, SMEM_INFO_MAGIC, sizeof(info->magic))) + return SMEM_ITEM_COUNT; + + return le16_to_cpu(info->num_items); +} + static int qcom_smem_set_global_partition(struct qcom_smem *smem) { struct smem_partition_header *header; @@ -883,7 +919,10 @@ static int qcom_smem_probe(struct platform_device *pdev) ret = qcom_smem_set_global_partition(smem); if (ret < 0) return ret; + smem->item_count = qcom_smem_get_item_count(smem); + break; case SMEM_GLOBAL_HEAP_VERSION: + smem->item_count = SMEM_ITEM_COUNT; break; default: dev_err(&pdev->dev, "Unsupported SMEM version 0x%x\n", version); -- cgit From e691b48dcc7553b423bcbc7ddcd9f51698d093b1 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Wed, 11 Oct 2017 14:29:10 -0700 Subject: soc: qcom: smem: Increase the number of hosts Increase the maximum number of hosts in a system to 10. Signed-off-by: Chris Lew Acked-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 19704baa65f4..0b94d62fad2b 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -91,7 +91,7 @@ #define SMEM_GLOBAL_HOST 0xfffe /* Max number of processors/hosts in a system */ -#define SMEM_HOST_COUNT 9 +#define SMEM_HOST_COUNT 10 /** * struct smem_proc_comm - proc_comm communication struct (legacy) -- cgit