diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-29 23:16:01 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-10-29 23:16:01 +0100 |
commit | b22b6beae6116e3a9c46ced312c626f6737a3fa6 (patch) | |
tree | c92228669e0444d91fd1445bc562351fd69b58cc /drivers/soc/qcom | |
parent | Merge tag 'armsoc-defconfig' of git://git.kernel.org/pub/scm/linux/kernel/git... (diff) | |
parent | Merge tag 'tegra-for-4.20-firmware-2' of git://git.kernel.org/pub/scm/linux/k... (diff) | |
download | linux-b22b6beae6116e3a9c46ced312c626f6737a3fa6.tar.xz linux-b22b6beae6116e3a9c46ced312c626f6737a3fa6.zip |
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann:
"The most noteworthy SoC driver changes this time include:
- The TEE subsystem gains an in-kernel interface to access the TEE
from device drivers.
- The reset controller subsystem gains a driver for the Qualcomm
Snapdragon 845 Power Domain Controller.
- The Xilinx Zynq platform now has a firmware interface for its
platform management unit. This contains a firmware "ioctl"
interface that was a little controversial at first, but the version
we merged solved that by not exposing arbitrary firmware calls to
user space.
- The Amlogic Meson platform gains a "canvas" driver that is used for
video processing and shared between different high-level drivers.
The rest is more of the usual, mostly related to SoC specific power
management support and core drivers in drivers/soc:
- Several Renesas SoCs (RZ/G1N, RZ/G2M, R-Car V3M, RZ/A2M) gain new
features related to power and reset control.
- The Mediatek mt8183 and mt6765 SoC platforms gain support for their
respective power management chips.
- A new driver for NXP i.MX8, which need a firmware interface for
power management.
- The SCPI firmware interface now contains support estimating power
usage of performance states
- The NVIDIA Tegra "pmc" driver gains a few new features, in
particular a pinctrl interface for configuring the pads.
- Lots of small changes for Qualcomm, in particular the "smem" device
driver.
- Some cleanups for the TI OMAP series related to their sysc
controller.
Additional cleanups and bugfixes in SoC specific drivers include the
Meson, Keystone, NXP, AT91, Sunxi, Actions, and Tegra platforms"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (129 commits)
firmware: tegra: bpmp: Implement suspend/resume support
drivers: clk: Add ZynqMP clock driver
dt-bindings: clock: Add bindings for ZynqMP clock driver
firmware: xilinx: Add zynqmp IOCTL API for device control
Documentation: xilinx: Add documentation for eemi APIs
MAINTAINERS: imx: include drivers/firmware/imx path
firmware: imx: add misc svc support
firmware: imx: add SCU firmware driver support
reset: Fix potential use-after-free in __of_reset_control_get()
dt-bindings: arm: fsl: add scu binding doc
soc: fsl: qbman: add interrupt coalesce changing APIs
soc: fsl: bman_portals: defer probe after bman's probe
soc: fsl: qbman: Use last response to determine valid bit
soc: fsl: qbman: Add 64 bit DMA addressing requirement to QBMan
soc: fsl: qbman: replace CPU 0 with any online CPU in hotplug handlers
soc: fsl: qbman: Check if CPU is offline when initializing portals
reset: qcom: PDC Global (Power Domain Controller) reset controller
dt-bindings: reset: Add PDC Global binding for SDM845 SoCs
reset: Grammar s/more then once/more than once/
bus: ti-sysc: Just use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS
...
Diffstat (limited to 'drivers/soc/qcom')
-rw-r--r-- | drivers/soc/qcom/Kconfig | 21 | ||||
-rw-r--r-- | drivers/soc/qcom/apr.c | 4 | ||||
-rw-r--r-- | drivers/soc/qcom/llcc-slice.c | 74 | ||||
-rw-r--r-- | drivers/soc/qcom/rmtfs_mem.c | 5 | ||||
-rw-r--r-- | drivers/soc/qcom/rpmh-rsc.c | 2 | ||||
-rw-r--r-- | drivers/soc/qcom/smem.c | 174 | ||||
-rw-r--r-- | drivers/soc/qcom/spm.c | 3 | ||||
-rw-r--r-- | drivers/soc/qcom/wcnss_ctrl.c | 2 |
8 files changed, 158 insertions, 127 deletions
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 41986d96f24b..684cb51694d1 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -33,7 +33,7 @@ config QCOM_GLINK_SSR config QCOM_GSBI tristate "QCOM General Serial Bus Interface" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST select MFD_SYSCON help Say y here to enable GSBI support. The GSBI provides control @@ -42,7 +42,7 @@ config QCOM_GSBI config QCOM_LLCC tristate "Qualcomm Technologies, Inc. LLCC driver" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST help Qualcomm Technologies, Inc. platform specific Last Level Cache Controller(LLCC) driver. This provides interfaces @@ -73,7 +73,8 @@ config QCOM_PM config QCOM_QMI_HELPERS tristate - depends on (ARCH_QCOM || COMPILE_TEST) && NET + depends on ARCH_QCOM || COMPILE_TEST + depends on NET help Helper library for handling QMI encoded messages. QMI encoded messages are used in communication between the majority of QRTR @@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM config QCOM_RPMH bool "Qualcomm RPM-Hardened (RPMH) Communication" - depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST + depends on ARCH_QCOM && ARM64 || COMPILE_TEST help Support for communication with the hardened-RPM blocks in Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an @@ -104,7 +105,7 @@ config QCOM_RPMH config QCOM_SMEM tristate "Qualcomm Shared Memory Manager (SMEM)" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST depends on HWSPINLOCK help Say y here to enable support for the Qualcomm Shared Memory Manager. @@ -113,8 +114,8 @@ config QCOM_SMEM config QCOM_SMD_RPM tristate "Qualcomm Resource Power Manager (RPM) over SMD" - depends on ARCH_QCOM - depends on RPMSG && OF + depends on ARCH_QCOM || COMPILE_TEST + depends on RPMSG help If you say yes to this option, support will be included for the Resource Power Manager system found in the Qualcomm 8974 based @@ -134,6 +135,7 @@ config QCOM_SMP2P depends on MAILBOX depends on QCOM_SMEM select QCOM_SMEM_STATE + select IRQ_DOMAIN help Say yes here to support the Qualcomm Shared Memory Point to Point protocol. @@ -142,13 +144,14 @@ config QCOM_SMSM tristate "Qualcomm Shared Memory State Machine" depends on QCOM_SMEM select QCOM_SMEM_STATE + select IRQ_DOMAIN help Say yes here to support the Qualcomm Shared Memory State Machine. The state machine is represented by bits in shared memory. config QCOM_WCNSS_CTRL tristate "Qualcomm WCNSS control driver" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG help Client driver for the WCNSS_CTRL SMD channel, used to download nv @@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL config QCOM_APR tristate "Qualcomm APR Bus (Asynchronous Packet Router)" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG help Enable APR IPC protocol support between diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 4bda793ba6ae..74f8b9607daa 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -87,7 +87,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf, } if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) { - dev_err(apr->dev, "APR: Wrong paket size\n"); + dev_err(apr->dev, "APR: Wrong packet size\n"); return -EINVAL; } @@ -221,7 +221,7 @@ static int apr_add_device(struct device *dev, struct device_node *np, if (np) snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np); else - strncpy(adev->name, id->name, APR_NAME_SIZE); + strscpy(adev->name, id->name, APR_NAME_SIZE); dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, id->domain_id, id->svc_id); diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 54063a31132f..192ca761b2cb 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c @@ -13,6 +13,7 @@ #include <linux/mutex.h> #include <linux/of_device.h> #include <linux/regmap.h> +#include <linux/sizes.h> #include <linux/slab.h> #include <linux/soc/qcom/llcc-qcom.h> @@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid, u32 slice_status; int ret; - act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid); - status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid); + act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid); + status_reg = LLCC_TRP_STATUSn(sid); /* Set the ACTIVE trigger */ act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; - ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); + ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg, + act_ctrl_reg_val); if (ret) return ret; /* Clear the ACTIVE trigger */ act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; - ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); + ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg, + act_ctrl_reg_val); if (ret) return ret; - ret = regmap_read_poll_timeout(drv_data->regmap, status_reg, + ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg, slice_status, !(slice_status & status), 0, LLCC_STATUS_READ_DELAY); return ret; @@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev) u32 attr0_val; u32 max_cap_cacheline; u32 sz; - int ret; + int ret = 0; const struct llcc_slice_config *llcc_table; struct llcc_slice_desc desc; - u32 bcast_off = drv_data->bcast_off; sz = drv_data->cfg_size; llcc_table = drv_data->cfg; for (i = 0; i < sz; i++) { - attr1_cfg = bcast_off + - LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); - attr0_cfg = bcast_off + - LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); + attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); + attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); attr1_val = llcc_table[i].cache_mode; attr1_val |= llcc_table[i].probe_target_ways << @@ -260,10 +260,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev) attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK; attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT; - ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val); + ret = regmap_write(drv_data->bcast_regmap, attr1_cfg, + attr1_val); if (ret) return ret; - ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val); + ret = regmap_write(drv_data->bcast_regmap, attr0_cfg, + attr0_val); if (ret) return ret; if (llcc_table[i].activate_on_init) { @@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev, { u32 num_banks; struct device *dev = &pdev->dev; - struct resource *res; - void __iomem *base; + struct resource *llcc_banks_res, *llcc_bcast_res; + void __iomem *llcc_banks_base, *llcc_bcast_base; int ret, i; + struct platform_device *llcc_edac; drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); if (!drv_data) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); + llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "llcc_base"); + llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res); + if (IS_ERR(llcc_banks_base)) + return PTR_ERR(llcc_banks_base); - drv_data->regmap = devm_regmap_init_mmio(dev, base, - &llcc_regmap_config); + drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base, + &llcc_regmap_config); if (IS_ERR(drv_data->regmap)) return PTR_ERR(drv_data->regmap); + llcc_bcast_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "llcc_broadcast_base"); + llcc_bcast_base = devm_ioremap_resource(&pdev->dev, llcc_bcast_res); + if (IS_ERR(llcc_bcast_base)) + return PTR_ERR(llcc_bcast_base); + + drv_data->bcast_regmap = devm_regmap_init_mmio(dev, llcc_bcast_base, + &llcc_regmap_config); + if (IS_ERR(drv_data->bcast_regmap)) + return PTR_ERR(drv_data->bcast_regmap); + ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, &num_banks); if (ret) @@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev, for (i = 0; i < num_banks; i++) drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; - drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE; - drv_data->bitmap = devm_kcalloc(dev, BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), GFP_KERNEL); @@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev, mutex_init(&drv_data->lock); platform_set_drvdata(pdev, drv_data); - return qcom_llcc_cfg_program(pdev); + ret = qcom_llcc_cfg_program(pdev); + if (ret) + return ret; + + drv_data->ecc_irq = platform_get_irq(pdev, 0); + if (drv_data->ecc_irq >= 0) { + llcc_edac = platform_device_register_data(&pdev->dev, + "qcom_llcc_edac", -1, drv_data, + sizeof(*drv_data)); + if (IS_ERR(llcc_edac)) + dev_err(dev, "Failed to register llcc edac driver\n"); + } + + return ret; } EXPORT_SYMBOL_GPL(qcom_llcc_probe); diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index 8a3678c2e83c..97bb5989aa21 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c @@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to parse qcom,vmid\n"); goto remove_cdev; } else if (!ret) { + if (!qcom_scm_is_available()) { + ret = -EPROBE_DEFER; + goto remove_cdev; + } + perms[0].vmid = QCOM_SCM_VMID_HLOS; perms[0].perm = QCOM_SCM_PERM_RW; perms[1].vmid = vmid; diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index ee75da66d64b..75bd9a83aef0 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type) return -EAGAIN; } write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0); + write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0); } bitmap_zero(tcs->slots, MAX_TCS_SLOTS); spin_unlock(&tcs->lock); @@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p) skip: /* Reclaim the TCS */ write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0); + write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0); write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i)); spin_lock(&drv->lock); clear_bit(i, drv->tcs_in_use); diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index bf4bd71ab53f..f80d040601fd 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -18,6 +18,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/sizes.h> #include <linux/slab.h> #include <linux/soc/qcom/smem.h> @@ -277,7 +278,7 @@ struct qcom_smem { u32 item_count; unsigned num_regions; - struct smem_region regions[0]; + struct smem_region regions[]; }; static void * @@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, size_t *size) { struct smem_header *header; - struct smem_region *area; + struct smem_region *region; struct smem_global_entry *entry; u32 aux_base; unsigned i; @@ -502,12 +503,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK; for (i = 0; i < smem->num_regions; i++) { - area = &smem->regions[i]; + region = &smem->regions[i]; - if (area->aux_base == aux_base || !aux_base) { + if (region->aux_base == aux_base || !aux_base) { if (size != NULL) *size = le32_to_cpu(entry->size); - return area->virt_base + le32_to_cpu(entry->offset); + return region->virt_base + le32_to_cpu(entry->offset); } } @@ -722,12 +723,59 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem) return le16_to_cpu(info->num_items); } +/* + * Validate the partition header for a partition whose partition + * table entry is supplied. Returns a pointer to its header if + * valid, or a null pointer otherwise. + */ +static struct smem_partition_header * +qcom_smem_partition_header(struct qcom_smem *smem, + struct smem_ptable_entry *entry, u16 host0, u16 host1) +{ + struct smem_partition_header *header; + u32 size; + + header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); + + if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) { + dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n", + header->magic[0], header->magic[1], + header->magic[2], header->magic[3]); + return NULL; + } + + if (host0 != le16_to_cpu(header->host0)) { + dev_err(smem->dev, "bad host0 (%hu != %hu)\n", + host0, le16_to_cpu(header->host0)); + return NULL; + } + if (host1 != le16_to_cpu(header->host1)) { + dev_err(smem->dev, "bad host1 (%hu != %hu)\n", + host1, le16_to_cpu(header->host1)); + return NULL; + } + + size = le32_to_cpu(header->size); + if (size != le32_to_cpu(entry->size)) { + dev_err(smem->dev, "bad partition size (%u != %u)\n", + size, le32_to_cpu(entry->size)); + return NULL; + } + + if (le32_to_cpu(header->offset_free_uncached) > size) { + dev_err(smem->dev, "bad partition free uncached (%u > %u)\n", + le32_to_cpu(header->offset_free_uncached), size); + return NULL; + } + + return header; +} + static int qcom_smem_set_global_partition(struct qcom_smem *smem) { struct smem_partition_header *header; struct smem_ptable_entry *entry; struct smem_ptable *ptable; - u32 host0, host1, size; bool found = false; int i; @@ -742,10 +790,15 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) 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 (!le32_to_cpu(entry->offset)) + continue; + if (!le32_to_cpu(entry->size)) + continue; + + if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST) + continue; - if (host0 == SMEM_GLOBAL_HOST && host0 == host1) { + if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) { found = true; break; } @@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) return -EINVAL; } - if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) { - dev_err(smem->dev, "Invalid entry for global partition\n"); + header = qcom_smem_partition_header(smem, entry, + SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST); + if (!header) 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); @@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) return 0; } -static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, - unsigned int local_host) +static int +qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host) { struct smem_partition_header *header; struct smem_ptable_entry *entry; struct smem_ptable *ptable; unsigned int remote_host; - u32 host0, host1; + u16 host0, host1; int i; ptable = qcom_smem_get_ptable(smem); @@ -809,71 +836,33 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, 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 != local_host && host1 != local_host) - continue; - if (!le32_to_cpu(entry->offset)) continue; - if (!le32_to_cpu(entry->size)) continue; + host0 = le16_to_cpu(entry->host0); + host1 = le16_to_cpu(entry->host1); if (host0 == local_host) remote_host = host1; - else + else if (host1 == local_host) remote_host = host0; + else + continue; if (remote_host >= SMEM_HOST_COUNT) { - dev_err(smem->dev, - "Invalid remote host %d\n", - remote_host); + dev_err(smem->dev, "bad host %hu\n", remote_host); return -EINVAL; } if (smem->partitions[remote_host]) { - dev_err(smem->dev, - "Already found a partition for host %d\n", - remote_host); - 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, - "Partition %d has invalid magic\n", i); + dev_err(smem->dev, "duplicate host %hu\n", remote_host); return -EINVAL; } - if (host0 != local_host && host1 != local_host) { - dev_err(smem->dev, - "Partition %d hosts are invalid\n", i); + header = qcom_smem_partition_header(smem, entry, host0, host1); + if (!header) return -EINVAL; - } - - if (host0 != remote_host && host1 != remote_host) { - dev_err(smem->dev, - "Partition %d hosts are invalid\n", i); - return -EINVAL; - } - - if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) { - dev_err(smem->dev, - "Partition %d has invalid size\n", i); - return -EINVAL; - } - - if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) { - dev_err(smem->dev, - "Partition %d has invalid free pointer\n", i); - return -EINVAL; - } smem->partitions[remote_host] = header; smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); @@ -887,6 +876,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, { struct device_node *np; struct resource r; + resource_size_t size; int ret; np = of_parse_phandle(dev->of_node, name, 0); @@ -899,12 +889,13 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, of_node_put(np); if (ret) return ret; + size = resource_size(&r); - smem->regions[i].aux_base = (u32)r.start; - smem->regions[i].size = resource_size(&r); - smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r)); + smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); if (!smem->regions[i].virt_base) return -ENOMEM; + smem->regions[i].aux_base = (u32)r.start; + smem->regions[i].size = size; return 0; } @@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev) return -EINVAL; } + BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT); ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); if (ret < 0 && ret != -ENOENT) return ret; diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index f9d7a85b2822..53807e839664 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu) cpumask_t mask; bool use_scm_power_down = false; + if (!qcom_scm_is_available()) + return -EPROBE_DEFER; + for (i = 0; ; i++) { state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); if (!state_node) diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index df3ccb30bc2d..373400dd816d 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp struct rpmsg_channel_info chinfo; struct wcnss_ctrl *_wcnss = wcnss; - strncpy(chinfo.name, name, sizeof(chinfo.name)); + strscpy(chinfo.name, name, sizeof(chinfo.name)); chinfo.src = RPMSG_ADDR_ANY; chinfo.dst = RPMSG_ADDR_ANY; |