From 7f9c136216c745099f36a4e0c3b2e63eedeb442f Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Wed, 12 Sep 2018 11:06:32 -0700 Subject: soc: qcom: Add broadcast base for Last Level Cache Controller (LLCC) Currently, broadcast base is set to end of the LLCC banks, which may not be correct always. As the number of banks may vary for each chipset and the broadcast base could be at a different address as well. This info depends on the chipset, so get the broadcast base info from the device tree (DT). Add broadcast base in LLCC driver and use this for broadcast writes. Signed-off-by: Venkata Narendra Kumar Gutta Reviewed-by: Evan Green Signed-off-by: Andy Gross --- drivers/soc/qcom/llcc-slice.c | 55 ++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 54063a31132f..08e3d388e153 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c @@ -106,22 +106,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; @@ -226,16 +228,13 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev) int ret; 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 +259,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 +280,36 @@ 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; 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 +331,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); -- cgit v1.2.3 From c081f3060fab316fcf103967a24e502d58488849 Mon Sep 17 00:00:00 2001 From: Venkata Narendra Kumar Gutta Date: Wed, 12 Sep 2018 11:06:33 -0700 Subject: soc: qcom: Add support to register LLCC EDAC driver Cache error reporting controller detects and reports single and double bit errors on Last Level Cache Controller (LLCC) cache. Add required support to register LLCC EDAC driver as platform driver, from LLCC driver. Signed-off-by: Venkata Narendra Kumar Gutta Reviewed-by: Evan Green Signed-off-by: Andy Gross --- drivers/soc/qcom/llcc-slice.c | 18 ++++++++++++++++-- include/linux/soc/qcom/llcc-qcom.h | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 08e3d388e153..d78926742510 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c @@ -225,7 +225,7 @@ 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; @@ -283,6 +283,7 @@ int qcom_llcc_probe(struct platform_device *pdev, 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) @@ -342,7 +343,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/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index c681e795b587..2e4b34d2617e 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -78,6 +78,7 @@ struct llcc_slice_config { * @num_banks: Number of llcc banks * @bitmap: Bit map to track the active slice ids * @offsets: Pointer to the bank offsets array + * @ecc_irq: interrupt for llcc cache error detection and reporting */ struct llcc_drv_data { struct regmap *regmap; @@ -89,6 +90,7 @@ struct llcc_drv_data { u32 num_banks; unsigned long *bitmap; u32 *offsets; + int ecc_irq; }; #if IS_ENABLED(CONFIG_QCOM_LLCC) -- cgit v1.2.3 From e11bbcedecae85ce60a5d99ea03528c2d6f867e0 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 6 Sep 2018 15:49:05 -0700 Subject: soc: qcom: geni: Don't ignore clk_round_rate() errors in geni_se_clk_tbl_get() The function clk_round_rate() is defined to return a "long", not an "unsigned long". That's because it might return a negative error code. Change the call in geni_se_clk_tbl_get() to check for errors. While we're at it, get rid of a useless init of "freq". NOTE: overall the idea that we should iterate over clk_round_rate() to try to reconstruct a table already present in the clock driver is questionable. Specifically: - This method relies on "clk_round_rate()" rounding up. - This method only works if the table is sorted and has no duplicates. ...this patch doesn't try to fix those problems, it just makes the error handling more correct. Fixes: eddac5af0654 ("soc: qcom: Add GENI based QUP Wrapper driver") Signed-off-by: Douglas Anderson Reviewed-by: Matthias Kaehlcke Signed-off-by: Andy Gross --- drivers/soc/qcom/qcom-geni-se.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index feed3db21c10..1b19b8428c4a 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on); */ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) { - unsigned long freq = 0; + long freq = 0; int i; if (se->clk_perf_tbl) { @@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) { freq = clk_round_rate(se->clk, freq + 1); - if (!freq || freq == se->clk_perf_tbl[i - 1]) + if (freq <= 0 || freq == se->clk_perf_tbl[i - 1]) break; se->clk_perf_tbl[i] = freq; } -- cgit v1.2.3 From 867d4aa7013fdee8b962cde1711f96c8dd86d926 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 6 Sep 2018 15:49:06 -0700 Subject: soc: qcom: geni: geni_se_clk_freq_match() should always accept multiples The geni_se_clk_freq_match() has some strange semantics. Specifically it is defined with two modes: 1. It can find a clock that's an exact multiple of the requested rate 2. It can find a non-exact match but it can't handle multiples then ...but callers should always be able to handle a clock that is a multiple of the requested clock so mode #2 doesn't really make sense. Let's change the semantics so that the non-exact match can also accept multiples and then change the code to handle that. The only caller of this code is the unlanded SPI driver [1] which currently passes "exact = True", thus it should be safe to change the semantics in this way. ...and, in fact, the SPI driver should likely be modified to pass "exact = False" (with the new semantics) since that will allow it to work with SPI devices that request a clock rate that doesn't exactly match a rate we can make. [1] https://lkml.kernel.org/r/1535107336-2214-1-git-send-email-dkota@codeaurora.org Fixes: eddac5af0654 ("soc: qcom: Add GENI based QUP Wrapper driver") Signed-off-by: Douglas Anderson Reviewed-by: Matthias Kaehlcke Signed-off-by: Andy Gross --- drivers/soc/qcom/qcom-geni-se.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 1b19b8428c4a..ee89ffb6dde8 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get); * @se: Pointer to the concerned serial engine. * @req_freq: Requested clock frequency. * @index: Index of the resultant frequency in the table. - * @res_freq: Resultant frequency which matches or is closer to the - * requested frequency. + * @res_freq: Resultant frequency of the source clock. * @exact: Flag to indicate exact multiple requirement of the requested * frequency. * - * This function is called by the protocol drivers to determine the matching - * or exact multiple of the requested frequency, as provided by the serial - * engine clock in order to meet the performance requirements. If there is - * no matching or exact multiple of the requested frequency found, then it - * selects the closest floor frequency, if exact flag is not set. + * This function is called by the protocol drivers to determine the best match + * of the requested frequency as provided by the serial engine clock in order + * to meet the performance requirements. + * + * If we return success: + * - if @exact is true then @res_freq / == @req_freq + * - if @exact is false then @res_freq / <= @req_freq * * Return: 0 on success, standard Linux error codes on failure. */ @@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, unsigned long *tbl; int num_clk_levels; int i; + unsigned long best_delta; + unsigned long new_delta; + unsigned int divider; num_clk_levels = geni_se_clk_tbl_get(se, &tbl); if (num_clk_levels < 0) @@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, if (num_clk_levels == 0) return -EINVAL; - *res_freq = 0; + best_delta = ULONG_MAX; for (i = 0; i < num_clk_levels; i++) { - if (!(tbl[i] % req_freq)) { + divider = DIV_ROUND_UP(tbl[i], req_freq); + new_delta = req_freq - tbl[i] / divider; + if (new_delta < best_delta) { + /* We have a new best! */ *index = i; *res_freq = tbl[i]; - return 0; - } - if (!(*res_freq) || ((tbl[i] > *res_freq) && - (tbl[i] < req_freq))) { - *index = i; - *res_freq = tbl[i]; + /* If the new best is exact then we're done */ + if (new_delta == 0) + return 0; + + /* Record how close we got */ + best_delta = new_delta; } } -- cgit v1.2.3 From 35aac0ba88d55da6ef879572e931f57098aa4d23 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 11 Jun 2018 09:38:38 +0100 Subject: soc: qcom: apr: fix spelling mistake: "paket" -> "packet" Trivial fix to spelling mistake in dev_err message text Signed-off-by: Colin Ian King Signed-off-by: Andy Gross --- drivers/soc/qcom/apr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 57af8a537332..7f8c4c096ad2 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; } -- cgit v1.2.3 From 9487e2ab1010c92789471d944230ecd38c720333 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:15 +0200 Subject: soc: qcom: smem: Add missing include of sizes.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing include of sizes.h. drivers/soc/qcom/smem.c: In function ‘qcom_smem_get_ptable’: drivers/soc/qcom/smem.c:666:64: error: ‘SZ_4K’ undeclared ptable = smem->regions[0].virt_base + smem->regions[0].size - SZ_4K; ^~~~~ Signed-off-by: Niklas Cassel Reviewed-by: Vivek Gautam Reviewed-by: Vinod Koul Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index bf4bd71ab53f..b77573eed596 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From da8eaf9a6cee12a0a77c82ffb0c93818e050f0d7 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:16 +0200 Subject: soc: qcom: llcc-slice: Add missing include of sizes.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing include of sizes.h. drivers/soc/qcom/llcc-slice.c: In function ‘llcc_update_act_ctrl’: drivers/soc/qcom/llcc-slice.c:41:44: error: ‘SZ_4K’ undeclared #define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K) ^~~~~ Signed-off-by: Niklas Cassel Reviewed-by: Vivek Gautam Reviewed-by: Vinod Koul Signed-off-by: Andy Gross --- drivers/soc/qcom/llcc-slice.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index d78926742510..192ca761b2cb 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 810f11a9cbfda027252d23a4a52d4af814296129 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:17 +0200 Subject: soc: qcom: smp2p: Add select IRQ_DOMAIN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we are using irq_domain_add_linear(), add a select on IRQ_DOMAIN. This is needed in order to be able to remove the depends on ARCH_QCOM. drivers/soc/qcom/smp2p.c: In function ‘qcom_smp2p_inbound_entry’: drivers/soc/qcom/smp2p.c:317:18: error: implicit declaration of function ‘irq_domain_add_linear’ entry->domain = irq_domain_add_linear(node, 32, &smp2p_irq_ops, entry); ^~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Niklas Cassel Reviewed-by: Vivek Gautam Reviewed-by: Vinod Koul Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index ba79b609aca2..6e063202ad0b 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -134,6 +134,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. -- cgit v1.2.3 From 0a5cdb4138f534bf58065acfb33d10336d6508df Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:18 +0200 Subject: soc: qcom: smsm: Add select IRQ_DOMAIN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we are using irq_domain_add_linear(), add a select on IRQ_DOMAIN. This is needed in order to be able to remove the depends on ARCH_QCOM. drivers/soc/qcom/smsm.c: In function ‘smsm_inbound_entry’: drivers/soc/qcom/smsm.c:411:18: error: implicit declaration of function ‘irq_domain_add_linear’ entry->domain = irq_domain_add_linear(node, 32, &smsm_irq_ops, entry); ^~~~~~~~~~~~~~~~~~~~~ Signed-off-by: Niklas Cassel Reviewed-by: Vivek Gautam Reviewed-by: Vinod Koul Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 6e063202ad0b..7da6e67c7ea1 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -143,6 +143,7 @@ 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. -- cgit v1.2.3 From a09b440af8de5f7cec20384a094ee1f88cbe2c17 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:19 +0200 Subject: soc: qcom: Remove bogus depends on OF from QCOM_SMD_RPM QCOM_SMD_RPM builds perfectly fine without CONFIG_OF set. Remove the bogus depends on OF. Signed-off-by: Niklas Cassel Reviewed-by: Vivek Gautam Reviewed-by: Vinod Koul Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 7da6e67c7ea1..ac657164a136 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -114,7 +114,7 @@ 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 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 -- cgit v1.2.3 From c62615b16c70db8f5e55e326f6d690909afc510f Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:20 +0200 Subject: soc: qcom: Remove depends on OF from QCOM_RPMH QCOM_RPHM already selects ARM64, which always selects OF. Additionally, the rpmh driver only uses linux/of.h, which has dummy definitions for all functions, in order for code to to be able to build without CONFIG_OF set. Remove the superfluous depends on OF. Signed-off-by: Niklas Cassel Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index ac657164a136..cf4ece232897 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -94,7 +94,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 -- cgit v1.2.3 From 4c96ed170d658d8826d94edec8ac93ee777981a2 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:21 +0200 Subject: soc: qcom: wcnss_ctrl: Avoid string overflow 'chinfo.name' is used as a NUL-terminated string, but using strncpy() with the length equal to the buffer size may result in lack of the termination: drivers//soc/qcom/wcnss_ctrl.c: In function 'qcom_wcnss_open_channel': drivers//soc/qcom/wcnss_ctrl.c:284:2: warning: 'strncpy' specified bound 32 equals destination size [-Wstringop-truncation] strncpy(chinfo.name, name, sizeof(chinfo.name)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This changes it to use the safer strscpy() instead. Signed-off-by: Niklas Cassel Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/wcnss_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc/qcom') 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; -- cgit v1.2.3 From 4fadb26574cb74e5de079dd384f25f44f4fb3ec3 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:22 +0200 Subject: soc: qcom: apr: Avoid string overflow 'adev->name' is used as a NUL-terminated string, but using strncpy() with the length equal to the buffer size may result in lack of the termination: In function 'apr_add_device', inlined from 'of_register_apr_devices' at drivers//soc/qcom/apr.c:264:7, inlined from 'apr_probe' at drivers//soc/qcom/apr.c:290:2: drivers//soc/qcom/apr.c:222:3: warning: 'strncpy' specified bound 32 equals destination size [-Wstringop-truncation] strncpy(adev->name, np->name, APR_NAME_SIZE); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This changes it to use the safer strscpy() instead. Signed-off-by: Niklas Cassel Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/apr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 7f8c4c096ad2..716762d59c1f 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -219,9 +219,9 @@ static int apr_add_device(struct device *dev, struct device_node *np, adev->domain_id = id->domain_id; adev->version = id->svc_version; if (np) - strncpy(adev->name, np->name, APR_NAME_SIZE); + strscpy(adev->name, np->name, APR_NAME_SIZE); 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); -- cgit v1.2.3 From ccfb464cd106890cfa51070f75921a273e2852e5 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Wed, 29 Aug 2018 09:57:23 +0200 Subject: soc: qcom: Allow COMPILE_TEST of qcom SoC Kconfigs Since commit cab673583d96 ("soc: Unconditionally include qcom Makefile"), we unconditionally include the soc/qcom/Makefile. This opens up the possibility to compile test the code even when building for other architectures. Allow COMPILE_TEST for all qcom SoC Kconfigs, except for two Kconfigs that depend on QCOM_SCM, since that triggers lots of build errors in qcom_scm. Signed-off-by: Niklas Cassel Reviewed-by: Vivek Gautam Reviewed-by: Vinod Koul Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index cf4ece232897..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 && 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 @@ -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,7 +114,7 @@ config QCOM_SMEM config QCOM_SMD_RPM tristate "Qualcomm Resource Power Manager (RPM) over SMD" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG help If you say yes to this option, support will be included for the @@ -150,7 +151,7 @@ config QCOM_SMSM 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 @@ -158,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 -- cgit v1.2.3 From 61a3bd10082b0e861b4e1bc451a92e20181a52f5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 23 Jul 2018 16:17:35 +0200 Subject: soc: qcom: spm: add SCM probe dependency Check for SCM availability before attempting to use SPM. SPM probe will fail otherwise. Signed-off-by: Felix Fietkau Signed-off-by: John Crispin Signed-off-by: Andy Gross --- drivers/soc/qcom/spm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/soc/qcom') 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) -- cgit v1.2.3 From 137dc5843faeacabf48fc22a8dc58c4e0b4f0927 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 27 Aug 2018 22:05:48 -0700 Subject: soc: qcom: rmtfs-mem: Validate that scm is available The scm device must be present in order for the rmtfs driver to configure memory permissions for the rmtfs memory region, so check that it is probed before continuing. Cc: stable@vger.kernel.org Fixes: fa65f8045137 ("soc: qcom: rmtfs-mem: Add support for assigning memory to remote") Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/rmtfs_mem.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/soc/qcom') 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; -- cgit v1.2.3 From 09e97b6c8754c91470455e69ebd827b741f80af5 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Wed, 5 Sep 2018 14:14:38 -0600 Subject: drivers: qcom: rpmh-rsc: clear wait_for_compl after use The wait_for_compl register ensures the request sequence is maintained when sending requests from the TCS. Clear the register after sending active request and during invalidate of the sleep and wake TCS. Reported-by: Raju P.L.S.S.S.N Signed-off-by: Lina Iyer Signed-off-by: Andy Gross --- drivers/soc/qcom/rpmh-rsc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/soc/qcom') 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); -- cgit v1.2.3 From 9f01b7a8f1d79c5679410e6a1d4b7e1b520f1e6d Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:45 -0500 Subject: soc: qcom: smem: rename variable in qcom_smem_get_global() Rename the variable "area" to be "region" in qcom_smem_get_global(), so its name better matches its type. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index b77573eed596..b91ecf72a236 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -278,7 +278,7 @@ struct qcom_smem { u32 item_count; unsigned num_regions; - struct smem_region regions[0]; + struct smem_region regions[]; }; static void * @@ -490,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; @@ -503,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); } } -- cgit v1.2.3 From 100d26e8ce65f33d229912be3bc563a93a786186 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:46 -0500 Subject: soc: qcom: smem: initialize region struct only when successful Hold off initializing anything for the array entry representing a memory region in qcom_smem_map_memory() until we know we've successfully mapped it. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index b91ecf72a236..938ffb01d155 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -888,6 +888,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); @@ -900,12 +901,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; } -- cgit v1.2.3 From eba757022fc2935c8a1392278a26d86761a70c60 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:47 -0500 Subject: soc: qcom: smem: always ignore partitions with 0 offset or size In qcom_smem_enumerate_partitions(), any partition table entry having a zero offset or size field is ignored. Move those checks earlier in the loop, because there's no sense in examining the host fields for those entries. Add the same checks in qcom_smem_set_global_partition(), so the scan for the global partition skips over these invalid entries. This allows a later check for zero size or offset once the global entry is found to be eliminated. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 938ffb01d155..9378bee4d7d6 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -743,9 +743,13 @@ 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]; + 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 == SMEM_GLOBAL_HOST && host0 == host1) { found = true; break; @@ -757,11 +761,6 @@ 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"); - 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); @@ -810,18 +809,16 @@ 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 && host1 != local_host) + continue; + if (host0 == local_host) remote_host = host1; else -- cgit v1.2.3 From eb68cf09092233716b31fad42cf2a4dad3959e3c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:48 -0500 Subject: soc: qcom: smem: small refactor in qcom_smem_enumerate_partitions() Combine the code that checks whether a partition table entry is associated with the local host with the assignment of the remote host id value. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 9378bee4d7d6..8d2582c99808 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -816,13 +816,12 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, host0 = le16_to_cpu(entry->host0); host1 = le16_to_cpu(entry->host1); - if (host0 != local_host && host1 != local_host) - continue; - 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, -- cgit v1.2.3 From 06ada44a807fc5c1745d2001faba3e0b4e2e060a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:49 -0500 Subject: soc: qcom: smem: verify both host ids in partition header The global partition is indicated by having both host values in its table of contents entry equal SMEM_GLOBAL_HOST=0xfffe. In qcom_smem_set_global_partition(), we check whether the header structure at the beginning of the partition contains that host value, but the check only verifies *one* of them. Change the check so the partition header must have SMEM_GLOBAL_HOST for *both* its host fields. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 8d2582c99808..deaac7416de7 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -770,7 +770,7 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) return -EINVAL; } - if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) { + if (host0 != SMEM_GLOBAL_HOST || host1 != SMEM_GLOBAL_HOST) { dev_err(smem->dev, "Global partition hosts are invalid\n"); return -EINVAL; } -- cgit v1.2.3 From abc006b7a6eaf598c3987e5ae87deb7cd8221145 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:50 -0500 Subject: soc: qcom: smem: require order of host ids to match In qcom_smem_enumerate_partitions(), we find all partitions that have a given local host id in either its host0 or its host1 field in the partition table entry. We then verify that the header structure at the start of each partition also contains the same two host ids as is found in the table of contents. There is no requirement that the order of the two host ids be the same in the table of contents and in the partition header. This patch changes that, requiring host0 to in the partition table entry to equal host0 in the partition header structure (and similar for the host1 values). Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index deaac7416de7..91f814900ca1 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -848,15 +848,9 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, return -EINVAL; } - if (host0 != local_host && host1 != local_host) { + if (host0 != host0 || host1 != host1) { dev_err(smem->dev, - "Partition %d hosts are invalid\n", i); - return -EINVAL; - } - - if (host0 != remote_host && host1 != remote_host) { - dev_err(smem->dev, - "Partition %d hosts are invalid\n", i); + "Partition %d hosts don't match\n", i); return -EINVAL; } -- cgit v1.2.3 From ada79289735fea37e755bbefc4403c989e66f4b1 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:51 -0500 Subject: soc: qcom: smem: introduce qcom_smem_partition_header() Create a new function qcom_smem_partition_header() to encapsulate validating locating a partition header and validating information found within it. This will be built up over a few commits to make it more obvious how the common function is replacing duplicated code elsewhere. Initially it just verifies the header has the right magic number. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 91f814900ca1..eb530a6770c1 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -723,6 +723,29 @@ 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) +{ + struct smem_partition_header *header; + + 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; + } + + return header; +} + static int qcom_smem_set_global_partition(struct qcom_smem *smem) { struct smem_partition_header *header; @@ -761,15 +784,13 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) return -EINVAL; } - header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); + header = qcom_smem_partition_header(smem, entry); + if (!header) + return -EINVAL; + 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; @@ -837,17 +858,13 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, return -EINVAL; } - header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); + header = qcom_smem_partition_header(smem, entry); + if (!header) + return -EINVAL; + 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); - return -EINVAL; - } - if (host0 != host0 || host1 != host1) { dev_err(smem->dev, "Partition %d hosts don't match\n", i); -- cgit v1.2.3 From 190b216c1535ca5af8db5c81e86d2192c4204b51 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:52 -0500 Subject: soc: qcom: smem: verify partition header size Add verification in qcom_smem_partition_header() that the size in a partition's header structure matches the size in its partition table entry. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index eb530a6770c1..efaeec4a0395 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -733,6 +733,7 @@ qcom_smem_partition_header(struct qcom_smem *smem, struct smem_ptable_entry *entry) { struct smem_partition_header *header; + u32 size; header = smem->regions[0].virt_base + le32_to_cpu(entry->offset); @@ -743,6 +744,13 @@ qcom_smem_partition_header(struct qcom_smem *smem, 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; + } + return header; } @@ -796,11 +804,6 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) 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, @@ -871,12 +874,6 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, 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); -- cgit v1.2.3 From 380dc4af50a61eaa8b749fac2e7e40ebf92079aa Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:53 -0500 Subject: soc: qcom: smem: verify partition offset_free_uncached Add verification in qcom_smem_partition_header() that the offset_free_uncached field in a partition's header structure does not exceed the partition's size. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index efaeec4a0395..a94888c26e18 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -751,6 +751,12 @@ qcom_smem_partition_header(struct qcom_smem *smem, 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; } @@ -759,7 +765,7 @@ 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; + u32 host0, host1; bool found = false; int i; @@ -804,13 +810,6 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) 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); @@ -874,12 +873,6 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, 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); } -- cgit v1.2.3 From 33fdbc4e5caf7ef6e7114adeab7a4a4578307ff3 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:54 -0500 Subject: soc: qcom: smem: small change in global entry loop Change the logic in the loop that finds that global host entry in the partition table not require the host0 and host1 local variables. The next patch will remove them. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index a94888c26e18..5b5cf45e2ef7 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -785,9 +785,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) if (!le32_to_cpu(entry->size)) continue; - host0 = le16_to_cpu(entry->host0); - host1 = le16_to_cpu(entry->host1); - if (host0 == SMEM_GLOBAL_HOST && host0 == host1) { + if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST) + continue; + + if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) { found = true; break; } -- cgit v1.2.3 From 7d01934455e3f5efc0019befe1b78ebe60dd7b0c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:55 -0500 Subject: soc: qcom: smem: verify partition host ids match Add verification in qcom_smem_partition_header() that the host ids found in a partition's header structure match those in its partition table entry. Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 5b5cf45e2ef7..14c8b34f6d56 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -730,7 +730,7 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem) */ static struct smem_partition_header * qcom_smem_partition_header(struct qcom_smem *smem, - struct smem_ptable_entry *entry) + struct smem_ptable_entry *entry, u16 host0, u16 host1) { struct smem_partition_header *header; u32 size; @@ -744,6 +744,17 @@ qcom_smem_partition_header(struct qcom_smem *smem, 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", @@ -765,7 +776,6 @@ 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; bool found = false; int i; @@ -799,18 +809,11 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) return -EINVAL; } - header = qcom_smem_partition_header(smem, entry); + header = qcom_smem_partition_header(smem, entry, + SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST); if (!header) return -EINVAL; - host0 = le16_to_cpu(header->host0); - host1 = le16_to_cpu(header->host1); - - if (host0 != SMEM_GLOBAL_HOST || host1 != SMEM_GLOBAL_HOST) { - dev_err(smem->dev, "Global partition hosts are invalid\n"); - return -EINVAL; - } - smem->global_partition = header; smem->global_cacheline = le32_to_cpu(entry->cacheline); @@ -861,19 +864,10 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, return -EINVAL; } - header = qcom_smem_partition_header(smem, entry); + header = qcom_smem_partition_header(smem, entry, host0, host1); if (!header) return -EINVAL; - host0 = le16_to_cpu(header->host0); - host1 = le16_to_cpu(header->host1); - - if (host0 != host0 || host1 != host1) { - dev_err(smem->dev, - "Partition %d hosts don't match\n", i); - return -EINVAL; - } - smem->partitions[remote_host] = header; smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); } -- cgit v1.2.3 From 13a920ae7898ffa075391ba36b63251f686d38a3 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 25 Jun 2018 19:58:56 -0500 Subject: soc: qcom: smem: a few last cleanups This patch contains several small cleanups: - In qcom_smem_enumerate_partitions(), change the "local_host" argument to have 16 bit unsigned type - Also in qcom_smem_enumerate_partitions(), change the type of the "host0" and "host1" local variables to be u16 - Fix error messages reporting host ids to use the right format specifier - Shorten the error messages as well, to fit on one line - Add a compile-time check to ensure the local host value passed to qcom_smem_enumerate_partitions() is in range Signed-off-by: Alex Elder Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 14c8b34f6d56..f80d040601fd 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -820,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); @@ -851,16 +851,12 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, 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); + dev_err(smem->dev, "duplicate host %hu\n", remote_host); return -EINVAL; } @@ -957,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; -- cgit v1.2.3