From 120e2a8109065fed116667238dec3b3dccc030c0 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Mon, 27 May 2019 13:01:36 +0300 Subject: interconnect: Add bulk API helpers There are drivers which just need to get multiple interconnect paths, request some predefined amounts of bandwidth and then just toggle the paths between enabled/disabled state. The aim of this patch is simplify the above and to allow drivers to put all the path names and bandwidth data into a single static icc_bulk_data table and call the icc_bulk_* functions on that table in order to scale all the interconnect paths in parallel. Suggested-by: Evan Green Suggested-by: Bjorn Andersson Signed-off-by: Georgi Djakov --- drivers/interconnect/Makefile | 2 +- drivers/interconnect/bulk.c | 119 ++++++++++++++++++++++++++++++++++++++++++ include/linux/interconnect.h | 22 ++++++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 drivers/interconnect/bulk.c diff --git a/drivers/interconnect/Makefile b/drivers/interconnect/Makefile index 4825c287ca13..d203520b0a56 100644 --- a/drivers/interconnect/Makefile +++ b/drivers/interconnect/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 CFLAGS_core.o := -I$(src) -icc-core-objs := core.o +icc-core-objs := core.o bulk.o obj-$(CONFIG_INTERCONNECT) += icc-core.o obj-$(CONFIG_INTERCONNECT_IMX) += imx/ diff --git a/drivers/interconnect/bulk.c b/drivers/interconnect/bulk.c new file mode 100644 index 000000000000..9bd418594665 --- /dev/null +++ b/drivers/interconnect/bulk.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +/** + * of_icc_bulk_get - get interconnect paths + * @dev: the device requesting the path + * @num_paths: the number of icc_bulk_data + * @paths: the table with the paths we want to get + * + * Returns 0 on success or -EERROR otherwise. + */ +int __must_check of_icc_bulk_get(struct device *dev, int num_paths, + struct icc_bulk_data *paths) +{ + int ret, i; + + for (i = 0; i < num_paths; i++) { + paths[i].path = of_icc_get(dev, paths[i].name); + if (IS_ERR(paths[i].path)) { + ret = PTR_ERR(paths[i].path); + dev_err(dev, "of_icc_get() failed on path %s (%d)\n", + paths[i].name, ret); + paths[i].path = NULL; + goto err; + } + } + + return 0; + +err: + icc_bulk_put(i, paths); + + return ret; +} +EXPORT_SYMBOL_GPL(of_icc_bulk_get); + +/** + * icc_bulk_put - put a list of interconnect paths + * @num_paths: the number of icc_bulk_data + * @paths: the icc_bulk_data table with the paths being put + */ +void icc_bulk_put(int num_paths, struct icc_bulk_data *paths) +{ + while (--num_paths >= 0) { + icc_put(paths[num_paths].path); + paths[num_paths].path = NULL; + } +} +EXPORT_SYMBOL_GPL(icc_bulk_put); + +/** + * icc_bulk_set - set bandwidth to a set of paths + * @num_paths: the number of icc_bulk_data + * @paths: the icc_bulk_data table containing the paths and bandwidth + * + * Returns 0 on success or -EERROR otherwise. + */ +int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths) +{ + int ret = 0; + int i; + + for (i = 0; i < num_paths; i++) { + ret = icc_set_bw(paths[i].path, paths[i].avg_bw, + paths[i].peak_bw); + if (ret) { + pr_err("icc_set_bw() failed on path %s (%d)\n", + paths[i].name, ret); + return ret; + } + } + + return ret; +} +EXPORT_SYMBOL_GPL(icc_bulk_set_bw); + +/** + * icc_bulk_enable - enable a previously disabled set of paths + * @num_paths: the number of icc_bulk_data + * @paths: the icc_bulk_data table containing the paths and bandwidth + * + * Returns 0 on success or -EERROR otherwise. + */ +int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths) +{ + int ret, i; + + for (i = 0; i < num_paths; i++) { + ret = icc_enable(paths[i].path); + if (ret) { + pr_err("icc_enable() failed on path %s (%d)\n", + paths[i].name, ret); + goto err; + } + } + + return 0; + +err: + icc_bulk_disable(i, paths); + + return ret; +} +EXPORT_SYMBOL_GPL(icc_bulk_enable); + +/** + * icc_bulk_disable - disable a set of interconnect paths + * @num_paths: the number of icc_bulk_data + * @paths: the icc_bulk_data table containing the paths and bandwidth + */ +void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths) +{ + while (--num_paths >= 0) + icc_disable(paths[num_paths].path); +} +EXPORT_SYMBOL_GPL(icc_bulk_disable); diff --git a/include/linux/interconnect.h b/include/linux/interconnect.h index 3a63d98613fc..e47028096ba8 100644 --- a/include/linux/interconnect.h +++ b/include/linux/interconnect.h @@ -23,6 +23,28 @@ struct icc_path; struct device; +/** + * struct icc_bulk_data - Data used for bulk icc operations. + * + * @path: reference to the path returned by icc_get() + * @name: the name from the "interconnect-names" DT property + * @avg_bw: average bandwidth in icc units + * @peak_bw: peak bandwidth in icc units + */ +struct icc_bulk_data { + struct icc_path *path; + const char *name; + u32 avg_bw; + u32 peak_bw; +}; + +int __must_check of_icc_bulk_get(struct device *dev, int num_paths, + struct icc_bulk_data *paths); +void icc_bulk_put(int num_paths, struct icc_bulk_data *paths); +int icc_bulk_set_bw(int num_paths, const struct icc_bulk_data *paths); +int icc_bulk_enable(int num_paths, const struct icc_bulk_data *paths); +void icc_bulk_disable(int num_paths, const struct icc_bulk_data *paths); + #if IS_ENABLED(CONFIG_INTERCONNECT) struct icc_path *icc_get(struct device *dev, const int src_id, -- cgit v1.2.3 From 03f8108c0acc9f399088dbb0c6bd762c39707688 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Mon, 15 Jun 2020 19:03:36 +0300 Subject: PCI: qcom: Disable power management for uPD720201 USB3 controller The uPD720201 USB3 host controller (connected to PCIe) on the Dragonboard 845c is often failing during suspend and resume. The following messages are seen over the console: PM: suspend entry (s2idle) Filesystems sync: 0.000 seconds Freezing user space processes ... (elapsed 0.001 seconds) done. OOM killer disabled. Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done. printk: Suspending console(s) (use no_console_suspend to debug) dwc3-qcom a8f8800.usb: HS-PHY not in L2 dwc3-qcom a6f8800.usb: HS-PHY not in L2 xhci_hcd 0000:01:00.0: can't change power state from D3hot to D0 (config space inaccessible) xhci_hcd 0000:01:00.0: can't change power state from D3hot to D0 (config space inaccessible) xhci_hcd 0000:01:00.0: Controller not ready at resume -19 xhci_hcd 0000:01:00.0: PCI post-resume error -19! xhci_hcd 0000:01:00.0: HC died; cleaning up Then the USB devices are not functional anymore. Let's disable the PM of the controller for now, as this will at least keep USB devices working even after suspend and resume. Signed-off-by: Georgi Djakov --- drivers/pci/controller/dwc/pcie-qcom.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 138e1a2d21cc..c1f502682a19 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -1439,6 +1439,13 @@ static void qcom_fixup_class(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_PCI << 8; } + +static void qcom_fixup_nopm(struct pci_dev *dev) +{ + dev->pm_cap = 0; + dev_info(&dev->dev, "Disabling PCI power management\n"); +} + DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0101, qcom_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0104, qcom_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0106, qcom_fixup_class); @@ -1446,6 +1453,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0107, qcom_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x0302, qcom_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1000, qcom_fixup_class); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_QCOM, 0x1001, qcom_fixup_class); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_RENESAS, 0x0014, qcom_fixup_nopm); static struct platform_driver qcom_pcie_driver = { .probe = qcom_pcie_probe, -- cgit v1.2.3 From 9d5e571609e52b30dd592db6c2f40eef81e6db65 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Tue, 9 Jun 2020 23:02:03 +0300 Subject: arm64: defconfig: Enable the PM8xxx RTC driver Enable the driver for the real time clock found in the PMICs on various Qualcomm platforms. Signed-off-by: Georgi Djakov --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 883e8bace3ed..387807e40010 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -760,6 +760,7 @@ CONFIG_RTC_DRV_S3C=y CONFIG_RTC_DRV_PL031=y CONFIG_RTC_DRV_SUN6I=y CONFIG_RTC_DRV_ARMADA38X=y +CONFIG_RTC_DRV_PM8XXX=m CONFIG_RTC_DRV_TEGRA=y CONFIG_RTC_DRV_SNVS=m CONFIG_RTC_DRV_IMX_SC=m -- cgit v1.2.3 From 02d968e2c566d94b0045ad1043c8c10fe9f5ed06 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Wed, 8 Jan 2020 10:20:12 +0200 Subject: interconnect: Mark all dummy functions as static inline There are a few dummy stub functions that are not marked as static inline yet. Currently this header file is not included in any other file outside of drivers/interconnect/, but that might not be the case in the future. If this file gets included and the framework is disabled, we will be see warnings. Let's fix this in advance. Signed-off-by: Georgi Djakov --- include/linux/interconnect-provider.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h index 0c494534b4d3..5b64e267bfb3 100644 --- a/include/linux/interconnect-provider.h +++ b/include/linux/interconnect-provider.h @@ -117,7 +117,7 @@ static inline struct icc_node *icc_node_create(int id) return ERR_PTR(-ENOTSUPP); } -void icc_node_destroy(int id) +static inline void icc_node_destroy(int id) { } @@ -126,16 +126,16 @@ static inline int icc_link_create(struct icc_node *node, const int dst_id) return -ENOTSUPP; } -int icc_link_destroy(struct icc_node *src, struct icc_node *dst) +static inline int icc_link_destroy(struct icc_node *src, struct icc_node *dst) { return -ENOTSUPP; } -void icc_node_add(struct icc_node *node, struct icc_provider *provider) +static inline void icc_node_add(struct icc_node *node, struct icc_provider *provider) { } -void icc_node_del(struct icc_node *node) +static inline void icc_node_del(struct icc_node *node) { } -- cgit v1.2.3 From 57fdc0c422a639ef275d729737c5f45fe8f86d8d Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Wed, 27 May 2020 14:06:42 +0300 Subject: interconnect: qcom: msm8916: Fix buswidth of pcnoc_s nodes The buswidth of the pcnoc_s_* nodes is not 8 but 4 bytes. Let's fix this. Reported-by: Jun Nie Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/msm8916.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c index e94f3c5228b7..42c6c5581662 100644 --- a/drivers/interconnect/qcom/msm8916.c +++ b/drivers/interconnect/qcom/msm8916.c @@ -197,13 +197,13 @@ DEFINE_QNODE(pcnoc_int_0, MSM8916_PNOC_INT_0, 8, -1, -1, MSM8916_PNOC_SNOC_MAS, DEFINE_QNODE(pcnoc_int_1, MSM8916_PNOC_INT_1, 8, -1, -1, MSM8916_PNOC_SNOC_MAS); DEFINE_QNODE(pcnoc_m_0, MSM8916_PNOC_MAS_0, 8, -1, -1, MSM8916_PNOC_INT_0); DEFINE_QNODE(pcnoc_m_1, MSM8916_PNOC_MAS_1, 8, -1, -1, MSM8916_PNOC_SNOC_MAS); -DEFINE_QNODE(pcnoc_s_0, MSM8916_PNOC_SLV_0, 8, -1, -1, MSM8916_SLAVE_CLK_CTL, MSM8916_SLAVE_TLMM, MSM8916_SLAVE_TCSR, MSM8916_SLAVE_SECURITY, MSM8916_SLAVE_MSS); -DEFINE_QNODE(pcnoc_s_1, MSM8916_PNOC_SLV_1, 8, -1, -1, MSM8916_SLAVE_IMEM_CFG, MSM8916_SLAVE_CRYPTO_0_CFG, MSM8916_SLAVE_MSG_RAM, MSM8916_SLAVE_PDM, MSM8916_SLAVE_PRNG); -DEFINE_QNODE(pcnoc_s_2, MSM8916_PNOC_SLV_2, 8, -1, -1, MSM8916_SLAVE_SPDM, MSM8916_SLAVE_BOOT_ROM, MSM8916_SLAVE_BIMC_CFG, MSM8916_SLAVE_PNOC_CFG, MSM8916_SLAVE_PMIC_ARB); -DEFINE_QNODE(pcnoc_s_3, MSM8916_PNOC_SLV_3, 8, -1, -1, MSM8916_SLAVE_MPM, MSM8916_SLAVE_SNOC_CFG, MSM8916_SLAVE_RBCPR_CFG, MSM8916_SLAVE_QDSS_CFG, MSM8916_SLAVE_DEHR_CFG); -DEFINE_QNODE(pcnoc_s_4, MSM8916_PNOC_SLV_4, 8, -1, -1, MSM8916_SLAVE_VENUS_CFG, MSM8916_SLAVE_CAMERA_CFG, MSM8916_SLAVE_DISPLAY_CFG); -DEFINE_QNODE(pcnoc_s_8, MSM8916_PNOC_SLV_8, 8, -1, -1, MSM8916_SLAVE_USB_HS, MSM8916_SLAVE_SDCC_1, MSM8916_SLAVE_BLSP_1); -DEFINE_QNODE(pcnoc_s_9, MSM8916_PNOC_SLV_9, 8, -1, -1, MSM8916_SLAVE_SDCC_2, MSM8916_SLAVE_LPASS, MSM8916_SLAVE_GRAPHICS_3D_CFG); +DEFINE_QNODE(pcnoc_s_0, MSM8916_PNOC_SLV_0, 4, -1, -1, MSM8916_SLAVE_CLK_CTL, MSM8916_SLAVE_TLMM, MSM8916_SLAVE_TCSR, MSM8916_SLAVE_SECURITY, MSM8916_SLAVE_MSS); +DEFINE_QNODE(pcnoc_s_1, MSM8916_PNOC_SLV_1, 4, -1, -1, MSM8916_SLAVE_IMEM_CFG, MSM8916_SLAVE_CRYPTO_0_CFG, MSM8916_SLAVE_MSG_RAM, MSM8916_SLAVE_PDM, MSM8916_SLAVE_PRNG); +DEFINE_QNODE(pcnoc_s_2, MSM8916_PNOC_SLV_2, 4, -1, -1, MSM8916_SLAVE_SPDM, MSM8916_SLAVE_BOOT_ROM, MSM8916_SLAVE_BIMC_CFG, MSM8916_SLAVE_PNOC_CFG, MSM8916_SLAVE_PMIC_ARB); +DEFINE_QNODE(pcnoc_s_3, MSM8916_PNOC_SLV_3, 4, -1, -1, MSM8916_SLAVE_MPM, MSM8916_SLAVE_SNOC_CFG, MSM8916_SLAVE_RBCPR_CFG, MSM8916_SLAVE_QDSS_CFG, MSM8916_SLAVE_DEHR_CFG); +DEFINE_QNODE(pcnoc_s_4, MSM8916_PNOC_SLV_4, 4, -1, -1, MSM8916_SLAVE_VENUS_CFG, MSM8916_SLAVE_CAMERA_CFG, MSM8916_SLAVE_DISPLAY_CFG); +DEFINE_QNODE(pcnoc_s_8, MSM8916_PNOC_SLV_8, 4, -1, -1, MSM8916_SLAVE_USB_HS, MSM8916_SLAVE_SDCC_1, MSM8916_SLAVE_BLSP_1); +DEFINE_QNODE(pcnoc_s_9, MSM8916_PNOC_SLV_9, 4, -1, -1, MSM8916_SLAVE_SDCC_2, MSM8916_SLAVE_LPASS, MSM8916_SLAVE_GRAPHICS_3D_CFG); DEFINE_QNODE(pcnoc_snoc_mas, MSM8916_PNOC_SNOC_MAS, 8, 29, -1, MSM8916_PNOC_SNOC_SLV); DEFINE_QNODE(pcnoc_snoc_slv, MSM8916_PNOC_SNOC_SLV, 8, -1, 45, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_BIMC, MSM8916_SNOC_INT_1); DEFINE_QNODE(qdss_int, MSM8916_SNOC_QDSS_INT, 8, -1, -1, MSM8916_SNOC_INT_0, MSM8916_SNOC_INT_BIMC); -- cgit v1.2.3 From cff43b899b4951f76a67c6889492588eb3389e0a Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Tue, 16 Jun 2020 19:00:10 +0300 Subject: interconnect: Fix of_node reference counting The src and dst node args are used by of_icc_get_from_provider(), but we currently prematurely drop the reference to the OF nodes. Let's fix this and drop the reference only when they are not used anymore. Signed-off-by: Georgi Djakov --- drivers/interconnect/core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index e5f998744501..f32f0f1f946d 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -425,18 +425,16 @@ struct icc_path *of_icc_get_by_index(struct device *dev, int idx) if (ret) return ERR_PTR(ret); - of_node_put(src_args.np); - ret = of_parse_phandle_with_args(np, "interconnects", "#interconnect-cells", idx * 2 + 1, &dst_args); if (ret) return ERR_PTR(ret); - of_node_put(dst_args.np); - src_node = of_icc_get_from_provider(&src_args); + of_node_put(src_args.np); + if (IS_ERR(src_node)) { if (PTR_ERR(src_node) != -EPROBE_DEFER) dev_err(dev, "error finding src node: %ld\n", @@ -446,6 +444,8 @@ struct icc_path *of_icc_get_by_index(struct device *dev, int idx) dst_node = of_icc_get_from_provider(&dst_args); + of_node_put(dst_args.np); + if (IS_ERR(dst_node)) { if (PTR_ERR(dst_node) != -EPROBE_DEFER) dev_err(dev, "error finding dst node: %ld\n", -- cgit v1.2.3 From 790fa508dabc8038f3e458905f554c96ccb29827 Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 19 Jun 2020 12:44:58 +0300 Subject: interconnect: qcom: msm8916: Pass the correct bandwidth to RPM The RPM expects the average bandwidth of the node and not the aggregated one. Fix this to avoid unnecessary higher clock rates being set. Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/msm8916.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c index 42c6c5581662..5017409608aa 100644 --- a/drivers/interconnect/qcom/msm8916.c +++ b/drivers/interconnect/qcom/msm8916.c @@ -389,7 +389,7 @@ static int msm8916_icc_set(struct icc_node *src, struct icc_node *dst) ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, RPM_BUS_MASTER_REQ, qn->mas_rpm_id, - sum_bw); + src->avg_bw); if (ret) { pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", qn->mas_rpm_id, ret); @@ -401,7 +401,7 @@ static int msm8916_icc_set(struct icc_node *src, struct icc_node *dst) ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, RPM_BUS_SLAVE_REQ, qn->slv_rpm_id, - sum_bw); + src->avg_bw); if (ret) { pr_err("qcom_icc_rpm_smd_send slv error %d\n", ret); -- cgit v1.2.3 From 627223c5ca0d54b0334a1178384e7ed382012f3a Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 19 Jun 2020 12:45:46 +0300 Subject: interconnect: qcom: qcs404: Pass the correct bandwidth to RPM The RPM expects the average bandwidth of the node and not the aggregated one. Fix this to avoid unnecessary higher clock rates being set. Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/qcs404.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c index d4769a5ea182..9171fa134de9 100644 --- a/drivers/interconnect/qcom/qcs404.c +++ b/drivers/interconnect/qcom/qcs404.c @@ -356,7 +356,7 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, RPM_BUS_MASTER_REQ, qn->mas_rpm_id, - sum_bw); + src->avg_bw); if (ret) { pr_err("qcom_icc_rpm_smd_send mas %d error %d\n", qn->mas_rpm_id, ret); @@ -368,7 +368,7 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE, RPM_BUS_SLAVE_REQ, qn->slv_rpm_id, - sum_bw); + src->avg_bw); if (ret) { pr_err("qcom_icc_rpm_smd_send slv error %d\n", ret); -- cgit v1.2.3