From d63486dd8e0bf843949c184843137e03bca5b8b4 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 9 Jul 2021 10:41:42 -0700 Subject: soc: qcom: aoss: Add generic compatible It seems we don't need platform specific implementation for the AOSS QMP, so let's introduce a generic compatible to avoid having to update the driver for each platform. Reviewed-by: Sibi Sankar Tested-by: Sibi Sankar Link: https://lore.kernel.org/r/20210709174142.1274554-4-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_aoss.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 934fcc4d2b05..92a1af70a649 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -602,6 +602,7 @@ static const struct of_device_id qmp_dt_match[] = { { .compatible = "qcom,sm8150-aoss-qmp", }, { .compatible = "qcom,sm8250-aoss-qmp", }, { .compatible = "qcom,sm8350-aoss-qmp", }, + { .compatible = "qcom,aoss-qmp", }, {} }; MODULE_DEVICE_TABLE(of, qmp_dt_match); -- cgit From d43b3a989bc8c06fd4bbb69a7500d180db2d68e8 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 2 Jul 2021 17:54:15 -0700 Subject: soc: qcom: rpmhpd: Use corner in power_off rpmhpd_aggregate_corner() takes a corner as parameter, but in rpmhpd_power_off() the code requests the level of the first corner instead. In all (known) current cases the first corner has level 0, so this change should be a nop, but in case that there's a power domain with a non-zero lowest level this makes sure that rpmhpd_power_off() actually requests the lowest level - which is the closest to "power off" we can get. While touching the code, also skip the unnecessary zero-initialization of "ret". Fixes: 279b7e8a62cc ("soc: qcom: rpmhpd: Add RPMh power domain driver") Reviewed-by: Rajendra Nayak Reviewed-by: Stephen Boyd Reviewed-by: Sibi Sankar Tested-by: Sibi Sankar Link: https://lore.kernel.org/r/20210703005416.2668319-2-bjorn.andersson@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/rpmhpd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index 2daa17ba54a3..fa209b479ab3 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -403,12 +403,11 @@ static int rpmhpd_power_on(struct generic_pm_domain *domain) static int rpmhpd_power_off(struct generic_pm_domain *domain) { struct rpmhpd *pd = domain_to_rpmhpd(domain); - int ret = 0; + int ret; mutex_lock(&rpmhpd_lock); - ret = rpmhpd_aggregate_corner(pd, pd->level[0]); - + ret = rpmhpd_aggregate_corner(pd, 0); if (!ret) pd->enabled = false; -- cgit From 0d361b0ac1ad99ecbe401a4eacdeb844dcdf86a2 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 27 Jun 2021 20:01:50 -0700 Subject: soc: qcom: socinfo: Don't print anything if nothing found Let's skip printing anything if there's nothing to see. This makes it so the file length is 0 instead of 1, for the newline, and helps scripts figure out if there's anything to see in these files. Cc: Sai Prakash Ranjan Cc: Douglas Anderson Cc: Dmitry Baryshkov Reviewed-by: Douglas Anderson Reviewed-by: Sai Prakash Ranjan Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20210628030150.2627905-1-swboyd@chromium.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index b2f049faa3df..9faf48302f4b 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -417,8 +417,8 @@ QCOM_OPEN(chip_id, qcom_show_chip_id); static int show_image_##type(struct seq_file *seq, void *p) \ { \ struct smem_image_version *image_version = seq->private; \ - seq_puts(seq, image_version->type); \ - seq_putc(seq, '\n'); \ + if (image_version->type[0] != '\0') \ + seq_printf(seq, "%s\n", image_version->type); \ return 0; \ } \ static int open_image_##type(struct inode *inode, struct file *file) \ -- cgit From a89f355e469dcda129c2522be4fdba00c1c74c83 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Tue, 29 Jun 2021 21:02:49 +0530 Subject: soc: qcom: aoss: Fix the out of bound usage of cooling_devs In "qmp_cooling_devices_register", the count value is initially QMP_NUM_COOLING_RESOURCES, which is 2. Based on the initial count value, the memory for cooling_devs is allocated. Then while calling the "qmp_cooling_device_add" function, count value is post-incremented for each child node. This makes the out of bound access to the cooling_dev array. Fix it by passing the QMP_NUM_COOLING_RESOURCES definition to devm_kzalloc() and initializing the count to 0. While at it, let's also free the memory allocated to cooling_dev if no cooling device is found in DT and during unroll phase. Cc: stable@vger.kernel.org # 5.4 Fixes: 05589b30b21a ("soc: qcom: Extend AOSS QMP driver to support resources that are used to wake up the SoC.") Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210629153249.73428-1-manivannan.sadhasivam@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom_aoss.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 92a1af70a649..536c3e4114fb 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -476,12 +476,12 @@ static int qmp_cooling_device_add(struct qmp *qmp, static int qmp_cooling_devices_register(struct qmp *qmp) { struct device_node *np, *child; - int count = QMP_NUM_COOLING_RESOURCES; + int count = 0; int ret; np = qmp->dev->of_node; - qmp->cooling_devs = devm_kcalloc(qmp->dev, count, + qmp->cooling_devs = devm_kcalloc(qmp->dev, QMP_NUM_COOLING_RESOURCES, sizeof(*qmp->cooling_devs), GFP_KERNEL); @@ -497,12 +497,16 @@ static int qmp_cooling_devices_register(struct qmp *qmp) goto unroll; } + if (!count) + devm_kfree(qmp->dev, qmp->cooling_devs); + return 0; unroll: while (--count >= 0) thermal_cooling_device_unregister (qmp->cooling_devs[count].cdev); + devm_kfree(qmp->dev, qmp->cooling_devs); return ret; } -- cgit From 18785c94ab6357338cf4aa872aabacbcc7178e83 Mon Sep 17 00:00:00 2001 From: Iskren Chernev Date: Sun, 27 Jun 2021 21:59:27 +0300 Subject: drivers: soc: qcom: rpmpd: Add SM6115 RPM Power Domains The SM4250/6115 have 4 rpm power domains, ported from downstream DT. Signed-off-by: Iskren Chernev Link: https://lore.kernel.org/r/20210627185927.695411-6-iskren.chernev@gmail.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/rpmpd.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 0b532a892d60..dbf494e92574 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -346,6 +346,33 @@ static const struct rpmpd_desc sdm660_desc = { .max_state = RPM_SMD_LEVEL_TURBO, }; +/* sm4250/6115 RPM Power domains */ +DEFINE_RPMPD_PAIR(sm6115, vddcx, vddcx_ao, RWCX, LEVEL, 0); +DEFINE_RPMPD_VFL(sm6115, vddcx_vfl, RWCX, 0); + +DEFINE_RPMPD_PAIR(sm6115, vddmx, vddmx_ao, RWMX, LEVEL, 0); +DEFINE_RPMPD_VFL(sm6115, vddmx_vfl, RWMX, 0); + +DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_cx, RWLC, 0); +DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_mx, RWLM, 0); + +static struct rpmpd *sm6115_rpmpds[] = { + [SM6115_VDDCX] = &sm6115_vddcx, + [SM6115_VDDCX_AO] = &sm6115_vddcx_ao, + [SM6115_VDDCX_VFL] = &sm6115_vddcx_vfl, + [SM6115_VDDMX] = &sm6115_vddmx, + [SM6115_VDDMX_AO] = &sm6115_vddmx_ao, + [SM6115_VDDMX_VFL] = &sm6115_vddmx_vfl, + [SM6115_VDD_LPI_CX] = &sm6115_vdd_lpi_cx, + [SM6115_VDD_LPI_MX] = &sm6115_vdd_lpi_mx, +}; + +static const struct rpmpd_desc sm6115_desc = { + .rpmpds = sm6115_rpmpds, + .num_pds = ARRAY_SIZE(sm6115_rpmpds), + .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, +}; + static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc }, { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, @@ -356,6 +383,7 @@ static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, { .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc }, + { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc }, { } }; MODULE_DEVICE_TABLE(of, rpmpd_match_table); -- cgit From 6feba6a62c577e98bd9214b73c17860166ac8b91 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 21 May 2021 13:44:53 -0700 Subject: PM: AVS: qcom-cpr: Use nvmem_cell_read_variable_le_u32() Let's delete the private function cpr_read_efuse() since it does the basically the same thing as the new API call nvmem_cell_read_variable_le_u32(). Differences between the new API call and the old private function: * less error printing (I assume this is OK). * will give an error if the value doesn't fit in 32-bits (the old code would have truncated silently). Reviewed-by: Bjorn Andersson Acked-by: Niklas Cassel Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20210521134437.v2.1.Id1c70158722750aec0673d60c12e46a9c66bbfed@changeid Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/cpr.c | 43 +++++-------------------------------------- 1 file changed, 5 insertions(+), 38 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c index b24cc77d1889..4ce8e816154f 100644 --- a/drivers/soc/qcom/cpr.c +++ b/drivers/soc/qcom/cpr.c @@ -801,38 +801,6 @@ unlock: return ret; } -static int cpr_read_efuse(struct device *dev, const char *cname, u32 *data) -{ - struct nvmem_cell *cell; - ssize_t len; - char *ret; - int i; - - *data = 0; - - cell = nvmem_cell_get(dev, cname); - if (IS_ERR(cell)) { - if (PTR_ERR(cell) != -EPROBE_DEFER) - dev_err(dev, "undefined cell %s\n", cname); - return PTR_ERR(cell); - } - - ret = nvmem_cell_read(cell, &len); - nvmem_cell_put(cell); - if (IS_ERR(ret)) { - dev_err(dev, "can't read cell %s\n", cname); - return PTR_ERR(ret); - } - - for (i = 0; i < len; i++) - *data |= ret[i] << (8 * i); - - kfree(ret); - dev_dbg(dev, "efuse read(%s) = %x, bytes %zd\n", cname, *data, len); - - return 0; -} - static int cpr_populate_ring_osc_idx(struct cpr_drv *drv) { @@ -843,8 +811,7 @@ cpr_populate_ring_osc_idx(struct cpr_drv *drv) int ret; for (; fuse < end; fuse++, fuses++) { - ret = cpr_read_efuse(drv->dev, fuses->ring_osc, - &data); + ret = nvmem_cell_read_variable_le_u32(drv->dev, fuses->ring_osc, &data); if (ret) return ret; fuse->ring_osc_idx = data; @@ -863,7 +830,7 @@ static int cpr_read_fuse_uV(const struct cpr_desc *desc, u32 bits = 0; int ret; - ret = cpr_read_efuse(drv->dev, init_v_efuse, &bits); + ret = nvmem_cell_read_variable_le_u32(drv->dev, init_v_efuse, &bits); if (ret) return ret; @@ -932,7 +899,7 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv) } /* Populate target quotient by scaling */ - ret = cpr_read_efuse(drv->dev, fuses->quotient, &fuse->quot); + ret = nvmem_cell_read_variable_le_u32(drv->dev, fuses->quotient, &fuse->quot); if (ret) return ret; @@ -1001,7 +968,7 @@ static int cpr_calculate_scaling(const char *quot_offset, prev_fuse = fuse - 1; if (quot_offset) { - ret = cpr_read_efuse(drv->dev, quot_offset, "_diff); + ret = nvmem_cell_read_variable_le_u32(drv->dev, quot_offset, "_diff); if (ret) return ret; @@ -1701,7 +1668,7 @@ static int cpr_probe(struct platform_device *pdev) * initialized after attaching to the power domain, * since it depends on the CPU's OPP table. */ - ret = cpr_read_efuse(dev, "cpr_fuse_revision", &cpr_rev); + ret = nvmem_cell_read_variable_le_u32(dev, "cpr_fuse_revision", &cpr_rev); if (ret) return ret; -- cgit From cb531cab62a19e97d8de0a2c9935daed93ec3736 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 25 Jun 2021 10:52:09 +0530 Subject: soc: qcom: geni: move GENI_IF_DISABLE_RO to common header GENI_IF_DISABLE_RO is used by geni spi driver as well to check the status if GENI, so move this to common header qcom-geni-se.h Reviewed-by: Bjorn Andersson Signed-off-by: Vinod Koul Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20210625052213.32260-2-vkoul@kernel.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-geni-se.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 5bdfb1565c14..fe666ea0c487 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -104,7 +104,6 @@ static const char * const icc_path_names[] = {"qup-core", "qup-config", #define GENI_OUTPUT_CTRL 0x24 #define GENI_CGC_CTRL 0x28 #define GENI_CLK_CTRL_RO 0x60 -#define GENI_IF_DISABLE_RO 0x64 #define GENI_FW_S_REVISION_RO 0x6c #define SE_GENI_BYTE_GRAN 0x254 #define SE_GENI_TX_PACKING_CFG0 0x260 -- cgit From 0fa8266294754978da34d7ea785d621f51d939f2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 25 Jun 2021 10:52:10 +0530 Subject: soc: qcom: geni: Add support for gpi dma GPI DMA is one of the DMA modes supported on geni, this adds support to enable that mode Also do better documentation of the enum geni_se_xfer_mode. Signed-off-by: Vinod Koul Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20210625052213.32260-3-vkoul@kernel.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-geni-se.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index fe666ea0c487..7d649d2cf31e 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -321,6 +321,30 @@ static void geni_se_select_dma_mode(struct geni_se *se) writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN); } +static void geni_se_select_gpi_mode(struct geni_se *se) +{ + u32 val; + + geni_se_irq_clear(se); + + writel(0, se->base + SE_IRQ_EN); + + val = readl(se->base + SE_GENI_S_IRQ_EN); + val &= ~S_CMD_DONE_EN; + writel(val, se->base + SE_GENI_S_IRQ_EN); + + val = readl(se->base + SE_GENI_M_IRQ_EN); + val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN | + M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); + writel(val, se->base + SE_GENI_M_IRQ_EN); + + writel(GENI_DMA_MODE_EN, se->base + SE_GENI_DMA_MODE_EN); + + val = readl(se->base + SE_GSI_EVENT_EN); + val |= (DMA_RX_EVENT_EN | DMA_TX_EVENT_EN | GENI_M_EVENT_EN | GENI_S_EVENT_EN); + writel(val, se->base + SE_GSI_EVENT_EN); +} + /** * geni_se_select_mode() - Select the serial engine transfer mode * @se: Pointer to the concerned serial engine. @@ -328,7 +352,7 @@ static void geni_se_select_dma_mode(struct geni_se *se) */ void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode) { - WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA); + WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA && mode != GENI_GPI_DMA); switch (mode) { case GENI_SE_FIFO: @@ -337,6 +361,9 @@ void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode) case GENI_SE_DMA: geni_se_select_dma_mode(se); break; + case GENI_GPI_DMA: + geni_se_select_gpi_mode(se); + break; case GENI_SE_INVALID: default: break; -- cgit From 593cb55b4cdd18a2946efd67c29ec4c6081dea8f Mon Sep 17 00:00:00 2001 From: Iskren Chernev Date: Sat, 31 Jul 2021 19:48:27 +0300 Subject: soc: qcom: smd-rpm: Add SM6115 compatible Add a compatible for SM6115 Signed-off-by: Iskren Chernev Link: https://lore.kernel.org/r/20210731164827.2756798-3-iskren.chernev@gmail.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smd-rpm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index bc0be1d4be5f..dfdd4f20f5fd 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -242,6 +242,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-msm8996" }, { .compatible = "qcom,rpm-msm8998" }, { .compatible = "qcom,rpm-sdm660" }, + { .compatible = "qcom,rpm-sm6115" }, { .compatible = "qcom,rpm-sm6125" }, { .compatible = "qcom,rpm-qcs404" }, {} -- cgit From ad68c620b7b296aab9cbe61802e329c04fde8385 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Mon, 15 Mar 2021 09:44:55 -0500 Subject: soc: qcom: mdt_loader: be more informative on errors In __qcom_mdt_load() there are cases where an error occurs that cause a message to be printed. In some of those cases the errno value can be helpful to understand exactly what caused the problem. Print the errno (as well as the firmware file name) where it is helpful, and in a few cases reword the error message. Consistently use the private fw_name for the file name. Signed-off-by: Alex Elder Link: https://lore.kernel.org/r/20210315144455.1770492-1-elder@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index eba7f76f9d61..bda170d7b4a2 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -166,6 +166,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, metadata = qcom_mdt_read_metadata(fw, &metadata_len); if (IS_ERR(metadata)) { ret = PTR_ERR(metadata); + dev_err(dev, "error %d reading firmware %s metadata\n", + ret, fw_name); goto out; } @@ -173,7 +175,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, kfree(metadata); if (ret) { - dev_err(dev, "invalid firmware metadata\n"); + /* Invalid firmware metadata */ + dev_err(dev, "error %d initializing firmware %s\n", + ret, fw_name); goto out; } } @@ -199,7 +203,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr); if (ret) { - dev_err(dev, "unable to setup relocation\n"); + /* Unable to set up relocation */ + dev_err(dev, "error %d setting up firmware %s\n", + ret, fw_name); goto out; } } @@ -243,9 +249,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, if (phdr->p_filesz && phdr->p_offset < fw->size) { /* Firmware is large enough to be non-split */ if (phdr->p_offset + phdr->p_filesz > fw->size) { - dev_err(dev, - "failed to load segment %d from truncated file %s\n", - i, firmware); + dev_err(dev, "file %s segment %d would be truncated\n", + fw_name, i); ret = -EINVAL; break; } @@ -257,7 +262,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw, ret = request_firmware_into_buf(&seg_fw, fw_name, dev, ptr, phdr->p_filesz); if (ret) { - dev_err(dev, "failed to load %s\n", fw_name); + dev_err(dev, "error %d loading %s\n", + ret, fw_name); break; } -- cgit From c73a6852b42c8c80cc46590dbbcfa6c448fdbc63 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 12 Jul 2021 15:57:02 +0200 Subject: soc: qcom: smsm: Implement support for get_irqchip_state At the moment there is no way for drivers to get the current state of the interrupt signal reported by a remote processor. The irqchip API has generic functionality for this, using irq_get_irqchip_state(). Implement support for getting the IRQCHIP_STATE_LINE_LEVEL by reading the remote state and checking the bit for the specified IRQ. Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20210712135703.324748-1-stephan@gerhold.net Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smsm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c index 1d3d5e3ec2b0..a48f9db98836 100644 --- a/drivers/soc/qcom/smsm.c +++ b/drivers/soc/qcom/smsm.c @@ -299,11 +299,28 @@ static int smsm_set_irq_type(struct irq_data *irqd, unsigned int type) return 0; } +static int smsm_get_irqchip_state(struct irq_data *irqd, + enum irqchip_irq_state which, bool *state) +{ + struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd); + irq_hw_number_t irq = irqd_to_hwirq(irqd); + u32 val; + + if (which != IRQCHIP_STATE_LINE_LEVEL) + return -EINVAL; + + val = readl(entry->remote_state); + *state = !!(val & BIT(irq)); + + return 0; +} + static struct irq_chip smsm_irq_chip = { .name = "smsm", .irq_mask = smsm_mask_irq, .irq_unmask = smsm_unmask_irq, .irq_set_type = smsm_set_irq_type, + .irq_get_irqchip_state = smsm_get_irqchip_state, }; /** -- cgit From e3d4571955050736bbf3eda0a9538a09d9fcfce8 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 12 Jul 2021 15:57:03 +0200 Subject: soc: qcom: smsm: Fix missed interrupts if state changes while masked The SMSM driver detects interrupt edges by tracking the last state it has seen (and has triggered the interrupt handler for). This works fine, but only if the interrupt does not change state while masked. For example, if an interrupt is unmasked while the state is HIGH, the stored last_value for that interrupt might still be LOW. Then, when the remote processor triggers smsm_intr() we assume that nothing has changed, even though the state might have changed from HIGH to LOW. Attempt to fix this by checking the current remote state before unmasking an IRQ. Use atomic operations to avoid the interrupt handler from interfering with the unmask function. This fixes modem crashes in some edge cases with the BAM-DMUX driver. Specifically, the BAM-DMUX interrupt handler is not called for the HIGH -> LOW smsm state transition if the BAM-DMUX driver is loaded (and therefore unmasks the interrupt) after the modem was already started: qcom-q6v5-mss 4080000.remoteproc: fatal error received: a2_task.c:3188: Assert FALSE failed: A2 DL PER deadlock timer expired waiting for Apps ACK Fixes: c97c4090ff72 ("soc: qcom: smsm: Add driver for Qualcomm SMSM") Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20210712135703.324748-2-stephan@gerhold.net Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smsm.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/soc/qcom') diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c index a48f9db98836..ef15d014c03a 100644 --- a/drivers/soc/qcom/smsm.c +++ b/drivers/soc/qcom/smsm.c @@ -109,7 +109,7 @@ struct smsm_entry { DECLARE_BITMAP(irq_enabled, 32); DECLARE_BITMAP(irq_rising, 32); DECLARE_BITMAP(irq_falling, 32); - u32 last_value; + unsigned long last_value; u32 *remote_state; u32 *subscription; @@ -204,8 +204,7 @@ static irqreturn_t smsm_intr(int irq, void *data) u32 val; val = readl(entry->remote_state); - changed = val ^ entry->last_value; - entry->last_value = val; + changed = val ^ xchg(&entry->last_value, val); for_each_set_bit(i, entry->irq_enabled, 32) { if (!(changed & BIT(i))) @@ -264,6 +263,12 @@ static void smsm_unmask_irq(struct irq_data *irqd) struct qcom_smsm *smsm = entry->smsm; u32 val; + /* Make sure our last cached state is up-to-date */ + if (readl(entry->remote_state) & BIT(irq)) + set_bit(irq, &entry->last_value); + else + clear_bit(irq, &entry->last_value); + set_bit(irq, entry->irq_enabled); if (entry->subscription) { -- cgit