From 4ea8e1b341e102c7a4253d978492ae97f1af37d4 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Mon, 24 May 2021 18:26:45 +0530 Subject: [PATCH 01/37] cnss2: Assert on FW mem allocation failure Add code to assert if FW requested memory allocation fails. This helps to collect logs at the time of failure. Change-Id: I8d3ff82eee545510318e0a9a2a128a71dc8a9fb3 Signed-off-by: Naman Padhiar Signed-off-by: Mohammed Siddiq --- drivers/net/wireless/cnss2/pci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 624bd8470989..383b50286350 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -3909,8 +3909,7 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) if (!fw_mem[i].va) { cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n", fw_mem[i].size, fw_mem[i].type); - - return -ENOMEM; + BUG(); } } } From cea7789bf11bb554b75513533d8cd9c86c1dfb9b Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 15 Jun 2021 18:18:48 +0530 Subject: [PATCH 02/37] irqchip: mpm: Add mpm mapping for Blair Currently both Blair and Holi use the same MPM pins mapping configuration as they use the same compatible string. USB PHY has a different GIC IRQ on Blair, so different MPM configuration is required. Change-Id: I1d72a70c0139abeac2d2ee32d103b7119a192ec9 Signed-off-by: Pavankumar Kondeti --- drivers/irqchip/Makefile | 2 +- drivers/irqchip/qcom-mpm-blair.c | 17 +++++++++++++++++ drivers/irqchip/qcom-mpm.c | 4 ++++ include/soc/qcom/mpm.h | 1 + 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 drivers/irqchip/qcom-mpm-blair.c diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 4e4ac6b2dfff..ef73e2c2cf85 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -99,7 +99,7 @@ obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o obj-$(CONFIG_QCOM_MPM) += mpm.o -mpm-objs += qcom-mpm.o qcom-mpm-holi.o qcom-mpm-sdxnightjar.o qcom-mpm-monaco.o qcom-mpm-qcs405.o +mpm-objs += qcom-mpm.o qcom-mpm-holi.o qcom-mpm-sdxnightjar.o qcom-mpm-monaco.o qcom-mpm-qcs405.o qcom-mpm-blair.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o obj-$(CONFIG_MADERA_IRQ) += irq-madera.o diff --git a/drivers/irqchip/qcom-mpm-blair.c b/drivers/irqchip/qcom-mpm-blair.c new file mode 100644 index 000000000000..b4da13878435 --- /dev/null +++ b/drivers/irqchip/qcom-mpm-blair.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#include +const struct mpm_pin mpm_blair_gic_chip_data[] = { + {5, 296}, /* lpass_irq_out_sdc */ + {12, 422}, /* qmp_usb3_lfps_rxterm_irq_cx */ + {86, 183}, /* mpm_wake,spmi_m */ + {89, 314}, /* tsens0_tsens_0C_int */ + {90, 315}, /* tsens1_tsens_0C_int */ + {93, 164}, /* eud_p0_dmse_int_mx */ + {94, 165}, /* eud_p0_dpse_int_mx */ + {-1}, +}; diff --git a/drivers/irqchip/qcom-mpm.c b/drivers/irqchip/qcom-mpm.c index acdddcbfac11..bebd0a8898fe 100644 --- a/drivers/irqchip/qcom-mpm.c +++ b/drivers/irqchip/qcom-mpm.c @@ -572,6 +572,10 @@ static const struct of_device_id mpm_gic_chip_data_table[] = { .compatible = "qcom,mpm-gic-qcs405", .data = mpm_qcs405_gic_chip_data, }, + { + .compatible = "qcom,mpm-gic-blair", + .data = mpm_blair_gic_chip_data, + }, {} }; MODULE_DEVICE_TABLE(of, mpm_gic_chip_data_table); diff --git a/include/soc/qcom/mpm.h b/include/soc/qcom/mpm.h index 49a82f6246a1..6c9cb12cddc8 100644 --- a/include/soc/qcom/mpm.h +++ b/include/soc/qcom/mpm.h @@ -20,4 +20,5 @@ extern const struct mpm_pin mpm_holi_gic_chip_data[]; extern const struct mpm_pin mpm_sdxnightjar_gic_chip_data[]; extern const struct mpm_pin mpm_monaco_gic_chip_data[]; extern const struct mpm_pin mpm_qcs405_gic_chip_data[]; +extern const struct mpm_pin mpm_blair_gic_chip_data[]; #endif /* __QCOM_MPM_H__ */ From 65f77ffcf551807ee2aaf43eb0113f3206bb382a Mon Sep 17 00:00:00 2001 From: Paras Jain Date: Tue, 22 Dec 2020 00:52:00 +0530 Subject: [PATCH 03/37] SIP crash: Unregister Net sysctl as part of unloading the module Crash observed when insmod and rmmod of nf_conntrack_sip.ko module is triggered. Change-Id: I3b0710509a0625e49d5582894d8d3e1b11c0f445 Signed-off-by: Paras Jain --- net/netfilter/nf_conntrack_sip.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 20e5b74c7723..ba9574694f98 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -2187,6 +2187,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1 static void __exit nf_conntrack_sip_fini(void) { nf_conntrack_helpers_unregister(sip, ports_c * 4); + unregister_net_sysctl_table(sip_sysctl_header); } static int __init nf_conntrack_sip_init(void) From f622aa8eeba2376ea07005d4ad64a617ac7ffd37 Mon Sep 17 00:00:00 2001 From: Jagadeesh Kona Date: Fri, 16 Apr 2021 11:57:02 +0530 Subject: [PATCH 04/37] cpufreq: qcom-cpufreq-hw: Move CPUFreq HW registers entry to sysfs Move the logging of CPUFreq HW debug registers from debugfs to sysfs under /sys/kernel/qcom-cpufreq-hw. Change-Id: I2d23052d013125ee69de852dcec621c104f0d50a Signed-off-by: Jagadeesh Kona --- drivers/cpufreq/qcom-cpufreq-hw-debug.c | 65 ++++++++++++------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/drivers/cpufreq/qcom-cpufreq-hw-debug.c b/drivers/cpufreq/qcom-cpufreq-hw-debug.c index 7aa1266cbd4f..d7a1bad08cdf 100644 --- a/drivers/cpufreq/qcom-cpufreq-hw-debug.c +++ b/drivers/cpufreq/qcom-cpufreq-hw-debug.c @@ -5,7 +5,6 @@ #define pr_fmt(fmt) "cpufreq_hw_debug: %s: " fmt, __func__ -#include #include #include #include @@ -19,6 +18,7 @@ enum debug_hw_regs_data { REG_PSTATE_STATUS, REG_EPSS_DEBUG_STATUS, REG_EPSS_DEBUG_SRB, + REG_EPSS_DEBUG_LUT, REG_ARRAY_SIZE, }; @@ -26,7 +26,6 @@ enum debug_hw_regs_data { struct cpufreq_hwregs { void __iomem *base[REG_ARRAY_SIZE]; int domain_cnt; - struct dentry *debugfs_base; }; struct cpufreq_register_data { @@ -36,6 +35,8 @@ struct cpufreq_register_data { static struct cpufreq_hwregs *hw_regs; static const u16 *offsets; +static struct kobj_attribute cpufreq_hwregs_attr; +static struct kobject *cpufreqhw_kobj; static const u16 cpufreq_qcom_std_data[] = { [REG_PERF_STATE] = 0x920, @@ -49,12 +50,14 @@ static const u16 cpufreq_qcom_std_epss_data[] = { [REG_PSTATE_STATUS] = 0x020, [REG_EPSS_DEBUG_STATUS] = 0x01c, [REG_EPSS_DEBUG_SRB] = 0x0bc, + [REG_EPSS_DEBUG_LUT] = 0x100, }; -static int print_cpufreq_hw_debug_regs(struct seq_file *s, void *unused) +static ssize_t cpufreq_hwregs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { int i, j, size = ARRAY_SIZE(cpufreq_qcom_std_data); - u32 regval; + u32 regval, count = 0; static struct cpufreq_register_data data[] = { {"PERF_STATE_DESIRED", REG_PERF_STATE}, @@ -62,35 +65,26 @@ static int print_cpufreq_hw_debug_regs(struct seq_file *s, void *unused) {"PSTATE_STATUS", REG_PSTATE_STATUS}, {"EPSS_DEBUG_STATUS", REG_EPSS_DEBUG_STATUS}, {"EPSS_DEBUG_SRB", REG_EPSS_DEBUG_SRB}, + {"EPSS_DEBUG_LUT", REG_EPSS_DEBUG_LUT}, }; if (offsets == cpufreq_qcom_std_epss_data) size = ARRAY_SIZE(cpufreq_qcom_std_epss_data); for (i = 0; i < hw_regs->domain_cnt; i++) { - seq_printf(s, "FREQUENCY DOMAIN %d\n", i); + count += scnprintf(buf + count, PAGE_SIZE, + "FREQUENCY DOMAIN %d\n", i); for (j = 0; j < size; j++) { regval = readl_relaxed(hw_regs->base[i] + offsets[data[j].offset]); - seq_printf(s, "%25s: 0x%.8x\n", data[j].name, regval); + count += scnprintf(buf + count, PAGE_SIZE, + "%25s: 0x%.8x\n", data[j].name, regval); } } - return 0; + return count; } -static int print_cpufreq_hw_reg_open(struct inode *inode, struct file *file) -{ - return single_open(file, print_cpufreq_hw_debug_regs, NULL); -} - -static const struct file_operations cpufreq_debug_register_fops = { - .open = print_cpufreq_hw_reg_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - static int cpufreq_panic_callback(struct notifier_block *nfb, unsigned long event, void *unused) { @@ -103,6 +97,7 @@ static int cpufreq_panic_callback(struct notifier_block *nfb, {"PSTATE_STATUS", REG_PSTATE_STATUS}, {"EPSS_DEBUG_STATUS", REG_EPSS_DEBUG_STATUS}, {"EPSS_DEBUG_SRB", REG_EPSS_DEBUG_SRB}, + {"EPSS_DEBUG_LUT", REG_EPSS_DEBUG_LUT}, }; if (offsets == cpufreq_qcom_std_epss_data) @@ -181,22 +176,23 @@ static int enable_cpufreq_hw_debug(struct platform_device *pdev) return ret; } - hw_regs->debugfs_base = debugfs_create_dir("qcom-cpufreq-hw", NULL); - if (!hw_regs->debugfs_base) { - dev_err(&pdev->dev, "Failed to create debugfs entry\n"); - return -ENODEV; + cpufreqhw_kobj = kobject_create_and_add("qcom-cpufreq-hw", + kernel_kobj); + if (!cpufreqhw_kobj) + return -ENOMEM; + + sysfs_attr_init(&cpufreq_hwregs_attr.attr); + cpufreq_hwregs_attr.attr.name = "print_cpufreq_debug_regs"; + cpufreq_hwregs_attr.show = cpufreq_hwregs_show; + cpufreq_hwregs_attr.attr.mode = 0444; + + ret = sysfs_create_file(cpufreqhw_kobj, &cpufreq_hwregs_attr.attr); + if (ret) { + dev_err(&pdev->dev, "Failed to create sysfs entry\n"); + kobject_put(cpufreqhw_kobj); } - if (!debugfs_create_file("print_cpufreq_debug_regs", 0444, - hw_regs->debugfs_base, NULL, &cpufreq_debug_register_fops)) - goto debugfs_fail; - - return 0; - -debugfs_fail: - dev_err(&pdev->dev, "Failed to create debugfs entry so cleaning up\n"); - debugfs_remove_recursive(hw_regs->debugfs_base); - return -ENODEV; + return ret; } static int qcom_cpufreq_hw_debug_probe(struct platform_device *pdev) @@ -206,7 +202,8 @@ static int qcom_cpufreq_hw_debug_probe(struct platform_device *pdev) static int qcom_cpufreq_hw_debug_remove(struct platform_device *pdev) { - debugfs_remove_recursive(hw_regs->debugfs_base); + sysfs_remove_file(kernel_kobj, &cpufreq_hwregs_attr.attr); + kobject_put(cpufreqhw_kobj); return 0; } From a214749c017829aaa1a5ca2ac0a264dd0e8e54c7 Mon Sep 17 00:00:00 2001 From: Yogesh Lal Date: Mon, 14 Jun 2021 17:08:21 +0530 Subject: [PATCH 05/37] defconfig: sdxlemur: Cleaning up config Removing redundant configs not needed by sdxlemur. Change-Id: Ic7cb73ce578a71e2b1affdbe6b9abd22a3f79136 Signed-off-by: Yogesh Lal --- arch/arm/configs/vendor/sdxlemur.config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 5974ea0c7c99..5759d09323eb 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -319,9 +319,7 @@ CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_SPS_DMA=y CONFIG_I2C_MSM_V2=y CONFIG_SPI_QUP=y -CONFIG_BLK_CGROUP=y CONFIG_IOSCHED_BFQ=y -CONFIG_BFQ_GROUP_IOSCHED=y CONFIG_MMC=y CONFIG_SDC_QTI=y CONFIG_MMC_SDHCI=y @@ -368,3 +366,6 @@ CONFIG_PCIEASPM_POWER_SUPERSAVE=y CONFIG_PAGE_POOL=y CONFIG_PHYLINK=m CONFIG_QPS615=m +# CONFIG_BLK_CGROUP is not set +# CONFIG_BLK_DEBUG_FS is not set +# CONFIG_VT is not set From 7987c648626940ccaae5f09869249e4b848cc562 Mon Sep 17 00:00:00 2001 From: Jeya R Date: Tue, 8 Jun 2021 04:37:04 -0700 Subject: [PATCH 06/37] msm: adsprpc: Handle ramdump collection Collect the ram dumps when process is initialized and process is not cleaned on DSP to fix UAF on init memory. Change-Id: I3ddae176039efa57e057eca730e7ed1cec706484 Acked-by: Krishnaiah Tadakamalla Signed-off-by: Jeya R --- drivers/char/adsprpc.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 24008d67a721..45a525d402d0 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -2280,7 +2280,13 @@ static void fastrpc_ramdump_collection(int cid) spin_lock(&me->hlock); hlist_for_each_entry_safe(fl, n, &me->drivers, hn) { - if (fl->cid == cid && fl->init_mem) { + /* + * On SSR call back, dumps collected only when process is initialized, + * And, process is not cleaned on DSP to avoid UAF for init_mem. + */ + if (fl->cid == cid && fl->init_mem && + fl->file_close < FASTRPC_PROCESS_DSP_EXIT_COMPLETE && + fl->dsp_proc_init) { hlist_add_head(&fl->init_mem->hn_init, &chan->initmems); fl->is_ramdump_pend = true; } @@ -3308,7 +3314,7 @@ static int fastrpc_wait_on_async_queue( read_async_job: interrupted = wait_event_interruptible(fl->async_wait_queue, atomic_read(&fl->async_queue_job_count)); - if (!fl || fl->file_close == FASTRPC_PROCESS_EXIT_START) { + if (!fl || fl->file_close >= FASTRPC_PROCESS_EXIT_START) { err = -EBADF; goto bail; } @@ -4213,9 +4219,9 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) ioctl.perf_kernel = NULL; ioctl.perf_dsp = NULL; ioctl.job = NULL; - spin_lock(&fl->hlock); + spin_lock(&fl->apps->hlock); fl->file_close = FASTRPC_PROCESS_DSP_EXIT_INIT; - spin_unlock(&fl->hlock); + spin_unlock(&fl->apps->hlock); /* * Pass 2 for "kernel" arg to send kernel msg to DSP * with non-zero msg PID for the DSP to directly use @@ -4223,9 +4229,9 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) */ VERIFY(err, 0 == (err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, KERNEL_MSG_WITH_NONZERO_PID, &ioctl))); - spin_lock(&fl->hlock); + spin_lock(&fl->apps->hlock); fl->file_close = FASTRPC_PROCESS_DSP_EXIT_COMPLETE; - spin_unlock(&fl->hlock); + spin_unlock(&fl->apps->hlock); if (err && fl->dsp_proc_init) ADSPRPC_ERR( "releasing DSP process failed with %d (0x%x) for %s\n", @@ -5164,12 +5170,11 @@ static int fastrpc_file_free(struct fastrpc_file *fl) if (!fl) return 0; cid = fl->cid; - spin_lock(&fl->hlock); + spin_lock(&fl->apps->hlock); fl->file_close = FASTRPC_PROCESS_EXIT_START; - spin_unlock(&fl->hlock); + spin_unlock(&fl->apps->hlock); (void)fastrpc_release_current_dsp_process(fl); - spin_lock(&fl->apps->hlock); if (!fl->is_ramdump_pend) { spin_unlock(&fl->apps->hlock); @@ -5185,7 +5190,6 @@ skip_dump_wait: spin_unlock(&fl->apps->hlock); kfree(fl->debug_buf); kfree(fl->gidlist.gids); - if (!fl->sctx) { kfree(fl->dev_pm_qos_req); kfree(fl); From f02f5b9cdd4f7e2c98ac25e6dd111e42d43fb7a5 Mon Sep 17 00:00:00 2001 From: Ray Chi Date: Wed, 17 Mar 2021 19:47:31 +0800 Subject: [PATCH 07/37] ANDROID: usb: dwc3: gadget: don't cancel the started requests Currently, there is an application on Mac that it will send ClearFeature(halt_ep) request before transfering USB data. If the device receives the ClearFeature(halt_ep) request, the started requests would be removed and restart the transfer. However, userspace services don't know this behavior. The services will free the requests instead of retry and resend the requests. It will cause the USB host can't get response so that it will try to recover by issuing a reset signal. Finally, it will take the infinite loop. send reqeust > reset > re-enumeration > send request > reset > ... To avoid this symptom, this patch will keep the started requests so that userspace services didn't free the requests. Bug: 178904115 Bug: 177879761 Signed-off-by: Ray Chi Change-Id: I52acf48871fd7f86cfcc51fb41c67d21ea895d69 Signed-off-by: Saravana Kannan Git-commit: 92de566762db61b138765a26e4afaacc7d7f7816 Git-Repo: https://android.googlesource.com/kernel/common/ Signed-off-by: Udipto Goswami --- drivers/usb/dwc3/gadget.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2edfa2fa4b42..fdc52c8d940e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1866,8 +1866,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) { struct dwc3_gadget_ep_cmd_params params; struct dwc3 *dwc = dep->dwc; - struct dwc3_request *req; - struct dwc3_request *tmp; int ret; if (!dep->endpoint.desc) { @@ -1926,15 +1924,13 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) if (!dep->gsi) { dwc3_stop_active_transfer(dep, true, true); - list_for_each_entry_safe(req, tmp, &dep->started_list, list) - dwc3_gadget_move_cancelled_request(req); + if (!list_empty(&dep->started_list)) + dep->flags |= DWC3_EP_DELAY_START; if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) { dep->flags |= DWC3_EP_PENDING_CLEAR_STALL; return 0; } - - dwc3_gadget_ep_cleanup_cancelled_requests(dep); } ret = dwc3_send_clear_stall_ep_cmd(dep); From 552f119915df9f7367f03349077128acc2de9615 Mon Sep 17 00:00:00 2001 From: Kamal Agrawal Date: Sat, 12 Jun 2021 04:07:14 +0530 Subject: [PATCH 08/37] msm: kgsl: Use non-atomic snapshot memory if it is unused Over time, memory gets fragmented, and eventually, a system that is up for a long time may have only a few physically contiguous pages. Hence, there is a chance of atomic snapshot memory allocation failure. Use non-atomic snapshot memory if it is unused as it is allocated during probe time. Change-Id: I725adeb80614a775f92213ebe9768f4f2f1c70a2 Signed-off-by: Kamal Agrawal Signed-off-by: Rohan Sethi --- drivers/gpu/msm/kgsl_snapshot.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index d3aa3de2bc7c..f75fa57fa30f 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -687,13 +687,18 @@ static void kgsl_device_snapshot_atomic(struct kgsl_device *device) } device->snapshot_memory_atomic.size = device->snapshot_memory.size; - device->snapshot_memory_atomic.ptr = devm_kzalloc(&device->pdev->dev, - device->snapshot_memory_atomic.size, GFP_ATOMIC); + if (!device->snapshot_faultcount) { + /* Use non-atomic snapshot memory if it is unused */ + device->snapshot_memory_atomic.ptr = device->snapshot_memory.ptr; + } else { + device->snapshot_memory_atomic.ptr = devm_kzalloc(&device->pdev->dev, + device->snapshot_memory_atomic.size, GFP_ATOMIC); - if (!device->snapshot_memory_atomic.ptr) { - dev_err(device->dev, - "KGSL failed to allocate memory for atomic snapshot\n"); - return; + if (!device->snapshot_memory_atomic.ptr) { + dev_err(device->dev, + "KGSL failed to allocate memory for atomic snapshot\n"); + return; + } } /* Allocate memory for the snapshot instance */ From 398c89ff034375ec7a2fca8a2872f31cf608594e Mon Sep 17 00:00:00 2001 From: Prateek Raj Singh Date: Thu, 10 Jun 2021 13:45:46 +0530 Subject: [PATCH 09/37] FM: Reduce high scan time Changed logic to find Lower Band Limit from Search Up from current channel with Wrap enable to tuning to Lower Band Limit + chan space and Search Down with Wrap disable. Change-Id: I79a686238d96db5dd5df9436b346b465435ae4f5 Signed-off-by: Prateek Raj Singh --- .../radio/rtc6226/radio-rtc6226-common.c | 32 ++++++++++++++++--- drivers/media/radio/rtc6226/radio-rtc6226.h | 2 +- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/media/radio/rtc6226/radio-rtc6226-common.c b/drivers/media/radio/rtc6226/radio-rtc6226-common.c index e1c9de541f57..ea08d264ac7f 100644 --- a/drivers/media/radio/rtc6226/radio-rtc6226-common.c +++ b/drivers/media/radio/rtc6226/radio-rtc6226-common.c @@ -312,6 +312,7 @@ void rtc6226_scan(struct work_struct *work) struct kfifo *data_b; int len = 0; u32 next_freq_khz; + u8 factor; int retval = 0; int i, rssi; @@ -427,7 +428,26 @@ void rtc6226_scan(struct work_struct *work) TUNE_STEP_SIZE) == next_freq_khz) { FMDERR("%s Seek one more time if lower freq is valid\n", __func__); - retval = rtc6226_set_seek(radio, SRCH_UP, WRAP_ENABLE); + // Tuned to band low limit + chan spacing then seek down with + // bandlimit config + if (radio->space == 0) + factor = 20; + else if (radio->space == 1) + factor = 10; + else + factor = 5; + retval = rtc6226_set_freq(radio, + (radio->recv_conf.band_low_limit + factor) * TUNE_STEP_SIZE); + if (retval < 0) + goto seek_tune_fail; + /* wait for tune to complete. */ + if (!wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(TUNE_TIMEOUT_MSEC))) { + FMDERR("In %s, didn't receive STC for tune\n", __func__); + rtc6226_q_event(radio, RTC6226_EVT_ERROR); + return; + } + retval = rtc6226_set_seek(radio, SRCH_DOWN, WRAP_DISABLE); if (retval < 0) { FMDERR("%s seek fail %d\n", __func__, retval); goto seek_tune_fail; @@ -454,10 +474,12 @@ void rtc6226_scan(struct work_struct *work) rssi = radio->registers[RSSI] & RSSI_RSSI; FMDBG("%s freq %d, rssi %d rssi threshold %d\n", __func__, next_freq_khz, rssi, radio->rssi_th); - if ((radio->recv_conf.band_low_limit * - TUNE_STEP_SIZE) == - next_freq_khz && - rssi >= radio->rssi_th) { + // Reach to band low limit, + // if SF is 0, means frequency at low limit is a commercial + // station Or a invalid channel + if (((radio->registers[STATUS] & STATUS_SF) == 0) || + (radio->recv_conf.band_high_limit * + TUNE_STEP_SIZE) == next_freq_khz) { FMDERR("lower band freq is valid\n"); rtc6226_q_event(radio, RTC6226_EVT_TUNE_SUCC); diff --git a/drivers/media/radio/rtc6226/radio-rtc6226.h b/drivers/media/radio/rtc6226/radio-rtc6226.h index 5e6bba18ea6d..8f412cd96623 100644 --- a/drivers/media/radio/rtc6226/radio-rtc6226.h +++ b/drivers/media/radio/rtc6226/radio-rtc6226.h @@ -200,7 +200,7 @@ #define SCAN_PENDING 3 #define START_SCAN 1 #define TUNE_TIMEOUT_MSEC 3000 -#define SEEK_TIMEOUT_MSEC 15000 +#define SEEK_TIMEOUT_MSEC 30000 #define RTC6226_MIN_SRCH_MODE 0x00 #define RTC6226_MAX_SRCH_MODE 0x02 From fec58e3766fc77f1d14bfbd529a20308abc6d8f6 Mon Sep 17 00:00:00 2001 From: Akshaya Damodaran Date: Tue, 4 May 2021 18:06:06 -0700 Subject: [PATCH 10/37] msm: Remove IPA offload config for Realtek driver Remove IPA offload config as IOSSv1 glue driver has also been removed for Realtek. Change-Id: I3007c300a27cac1eda114109a6f085efb4b4abb3 Signed-off-by: Akshaya Damodaran --- drivers/platform/msm/Kconfig | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index de4ed7ff5a8a..5bb96011b7f8 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -180,15 +180,6 @@ config R8125_IOSS To compile this driver as a module, choose M here. Module will be called r8125_ioss. If unsure, say N. -config R8125_IPA_OFFLOAD - bool "Enable IPA offload on Realtek R8125 driver" - depends on IPA3 - help - Enables IPA Ethernet Offload path on Realtek R8125 driver. It is - designed to support generic HW processing of UL/DL IP packets for - various use cases independent of radio technology. When this is - disabled Realtek R8125 driver switches to embedded software path. - config AQFWD_IOSS tristate "AQC glue driver for IOSS v2" depends on AQFWD From 4e0b8d44f6f361518bf15424ccd8ae364d446d4a Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Sat, 12 Jun 2021 20:16:57 +0530 Subject: [PATCH 11/37] msm: kgsl: Keep private intact until last refcount is put Currently, we are partially freeing private once last file is closed but closing last file doesn't necessarily means that all refcount on private is also put. This results in having a partially initialized private struct which is not yet freed and also can't be re-used. As a result if an application is just opening and closing kgsl device in a loop we will end up allocating and initializing a new private every time. This also allows application to mis-use this and create more than allowed limit of 200 contexts as they can use newly created private to create new context every time. To fix this, keep private intact until last refcount is put. This ensures we can re-use same private if same pid is doing kgsl open and close repeatedly and also ensures that an app can't breach 200 context limit. Change-Id: Ia1d1071275c7691a3d50bc15477b71387c5806d6 Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl.c | 53 +++++++++++++++----------------- drivers/gpu/msm/kgsl_sharedmem.c | 25 ++++++--------- 2 files changed, 34 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index fac02e36999b..2388ccd48b70 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -869,11 +869,25 @@ static void kgsl_destroy_process_private(struct kref *kref) struct kgsl_process_private *private = container_of(kref, struct kgsl_process_private, refcount); + mutex_lock(&kgsl_driver.process_mutex); + debugfs_remove_recursive(private->debug_root); + kgsl_process_uninit_sysfs(private); + + /* When using global pagetables, do not detach global pagetable */ + if (private->pagetable->name != KGSL_MMU_GLOBAL_PT) + kgsl_mmu_detach_pagetable(private->pagetable); + + /* Remove the process struct from the master list */ + write_lock(&kgsl_driver.proclist_lock); + list_del(&private->list); + write_unlock(&kgsl_driver.proclist_lock); + mutex_unlock(&kgsl_driver.process_mutex); + put_pid(private->pid); idr_destroy(&private->mem_idr); idr_destroy(&private->syncsource_idr); - /* When using global pagetables, do not detach global pagetable */ + /* When using global pagetables, do not put global pagetable */ if (private->pagetable->name != KGSL_MMU_GLOBAL_PT) kgsl_mmu_putpagetable(private->pagetable); @@ -962,8 +976,15 @@ static struct kgsl_process_private *kgsl_process_private_new( kfree(private); private = ERR_PTR(err); + return private; } + kgsl_process_init_sysfs(device, private); + kgsl_process_init_debugfs(private); + write_lock(&kgsl_driver.proclist_lock); + list_add(&private->list, &kgsl_driver.process_list); + write_unlock(&kgsl_driver.proclist_lock); + return private; } @@ -1008,8 +1029,8 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv, } /* - * If this is the last file on the process take down the debug - * directories and garbage collect any outstanding resources + * If this is the last file on the process garbage collect + * any outstanding resources */ process_release_memory(private); @@ -1017,18 +1038,6 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv, /* Release all syncsource objects from process private */ kgsl_syncsource_process_release_syncsources(private); - debugfs_remove_recursive(private->debug_root); - kgsl_process_uninit_sysfs(private); - - /* When using global pagetables, do not detach global pagetable */ - if (private->pagetable->name != KGSL_MMU_GLOBAL_PT) - kgsl_mmu_detach_pagetable(private->pagetable); - - /* Remove the process struct from the master list */ - write_lock(&kgsl_driver.proclist_lock); - list_del(&private->list); - write_unlock(&kgsl_driver.proclist_lock); - mutex_unlock(&kgsl_driver.process_mutex); kgsl_process_private_put(private); @@ -1046,19 +1055,7 @@ static struct kgsl_process_private *kgsl_process_private_open( if (IS_ERR(private)) goto done; - /* - * If this is a new process create the debug directories and add it to - * the process list - */ - - if (private->fd_count++ == 0) { - kgsl_process_init_sysfs(device, private); - kgsl_process_init_debugfs(private); - - write_lock(&kgsl_driver.proclist_lock); - list_add(&private->list, &kgsl_driver.process_list); - write_unlock(&kgsl_driver.proclist_lock); - } + private->fd_count++; done: mutex_unlock(&kgsl_driver.process_mutex); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 8bb7bd4aadc7..599c5b61e9f8 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -202,10 +202,10 @@ static ssize_t mem_entry_sysfs_show(struct kobject *kobj, ssize_t ret; /* - * kgsl_process_init_sysfs takes a refcount to the process_private, - * which is put when the kobj is released. This implies that priv will - * not be freed until this function completes, and no further locking - * is needed. + * sysfs_remove_file waits for reads to complete before the node is + * deleted and process private is freed only once kobj is released. + * This implies that priv will not be freed until this function + * completes, and no further locking is needed. */ priv = kobj ? container_of(kobj, struct kgsl_process_private, kobj) : NULL; @@ -228,10 +228,10 @@ static ssize_t memtype_sysfs_show(struct kobject *kobj, int id = 0; /* - * kgsl_process_init_sysfs takes a refcount to the process_private, - * which is put when the kobj is released. This implies that priv will - * not be freed until this function completes, and no further locking - * is needed. + * sysfs_remove_file waits for reads to complete before the node is + * deleted and process private is freed only once kobj is released. + * This implies that priv will not be freed until this function + * completes, and no further locking is needed. */ priv = container_of(kobj, struct kgsl_process_private, kobj_memtype); memtype = container_of(attr, struct kgsl_memtype, attr); @@ -261,13 +261,9 @@ static ssize_t memtype_sysfs_show(struct kobject *kobj, return scnprintf(buf, PAGE_SIZE, "%llu\n", size); } +/* Dummy release function - we have nothing to do here */ static void mem_entry_release(struct kobject *kobj) { - struct kgsl_process_private *priv; - - priv = container_of(kobj, struct kgsl_process_private, kobj); - /* Put the refcount we got in kgsl_process_init_sysfs */ - kgsl_process_private_put(priv); } static const struct sysfs_ops mem_entry_sysfs_ops = { @@ -329,9 +325,6 @@ void kgsl_process_init_sysfs(struct kgsl_device *device, { int i; - /* Keep private valid until the sysfs enries are removed. */ - kgsl_process_private_get(private); - if (kobject_init_and_add(&private->kobj, &ktype_mem_entry, kgsl_driver.prockobj, "%d", pid_nr(private->pid))) { dev_err(device->dev, "Unable to add sysfs for process %d\n", From 84403d23fb96f1a9804da9dd2bda45a79e0ba31c Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Wed, 2 Jun 2021 14:20:18 +0530 Subject: [PATCH 12/37] camera: add camera headers into exclude list Currently, header test puts videodev2.h into exclude list, which avoid its inclusion while performing header test. There are few camera headers which includes videodev2.h and fails to compile during header test on some host machine. Ideally, the headers files which includes videodev2.h should get excluded from header test as they eventually becomes incompatible due to videodev2.h . This patch add camera headers to exclude list. Change-Id: Ia8b7dc8ec635d568a026b948854448c77aae7770 Signed-off-by: Mukesh Ojha --- usr/include/Makefile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/usr/include/Makefile b/usr/include/Makefile index bfc7f8eda7d4..95e0da5500dd 100644 --- a/usr/include/Makefile +++ b/usr/include/Makefile @@ -63,6 +63,20 @@ header-test- += xen/evtchn.h header-test- += xen/gntdev.h header-test- += xen/privcmd.h +header-test- += camera/media/cam_jpeg.h +header-test- += camera/media/cam_icp.h +header-test- += camera/media/cam_isp.h +header-test- += camera/media/cam_cpas.h +header-test- += camera/media/cam_sensor.h +header-test- += camera/media/cam_fd.h +header-test- += camera/media/cam_tfe.h +header-test- += camera/media/cam_custom.h +header-test- += camera/media/cam_ope.h +header-test- += camera/media/cam_sync.h +header-test- += camera/media/cam_req_mgr.h +header-test- += camera/media/cam_lrme.h +header-test- += camera/media/cam_defs.h + header-test- += ais/media/ais_isp.h header-test- += ais/media/cam_lrme.h header-test- += ais/media/cam_cpas.h From c1da4dfce4173a4dc35bd6b4b955647c370b02fa Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Tue, 12 Jan 2021 21:49:10 +0530 Subject: [PATCH 13/37] msm: pci: Configure clkreq gpio wakeup capability at runtime By default pinctrl driver is disabling wakeup capability for gpios for which interrupt is not registered. This could cause wakeup from L1SS sleep not working. Hence fix it by enabling/disabling wakeup capability for clkreq gpio as part of DRV suspend/resume handling. Change-Id: If8fcb0a3a638c560bfe1f614aa00b7fd872c6b98 Signed-off-by: Vivek Pernamitta Signed-off-by: Vijayavardhan Vennapusa --- drivers/pci/controller/pci-msm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/pci/controller/pci-msm.c b/drivers/pci/controller/pci-msm.c index 604af34daea5..e58be80b51b2 100644 --- a/drivers/pci/controller/pci-msm.c +++ b/drivers/pci/controller/pci-msm.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "../pci.h" @@ -764,6 +765,7 @@ struct msm_pcie_dev_t { uint32_t gpio_n; uint32_t parf_deemph; uint32_t parf_swing; + uint32_t clkreq_gpio; struct msm_pcie_vreg_info_t *cx_vreg; struct msm_pcie_clk_info_t *rate_change_clk; @@ -6266,6 +6268,12 @@ static int msm_pcie_probe(struct platform_device *pdev) PCIE_DBG(pcie_dev, "RC%d: aux clock frequency: %d.\n", pcie_dev->rc_idx, pcie_dev->aux_clk_freq); + of_property_read_u32(of_node, "qcom,clkreq-gpio", + &pcie_dev->clkreq_gpio); + + PCIE_DBG(pcie_dev, "RC%d: clkreq gpio no:%u\n", + pcie_dev->rc_idx, pcie_dev->clkreq_gpio); + pcie_dev->shadow_en = true; pcie_dev->aer_enable = true; @@ -7725,6 +7733,10 @@ static int msm_pcie_drv_resume(struct msm_pcie_dev_t *pcie_dev) PCIE_DBG(pcie_dev, "PCIe RC%d: LTSSM_STATE: %s\n", pcie_dev->rc_idx, TO_LTSSM_STR(val & 0x3f)); + msm_gpio_mpm_wake_set(pcie_dev->clkreq_gpio, false); + + PCIE_DBG(pcie_dev, "PCIe: RC%d: disable wake up cap for CLKREQ GPIO\n", + pcie_dev->rc_idx); mutex_unlock(&pcie_dev->setup_lock); mutex_unlock(&pcie_dev->recovery_lock); @@ -7747,6 +7759,10 @@ static int msm_pcie_drv_suspend(struct msm_pcie_dev_t *pcie_dev, } mutex_lock(&pcie_dev->recovery_lock); + msm_gpio_mpm_wake_set(pcie_dev->clkreq_gpio, true); + + PCIE_DBG(pcie_dev, "PCIe: RC%d:Enable wake up cap for CLKREQ GPIO\n", + pcie_dev->rc_idx); /* disable global irq - no more linkdown/aer detection */ disable_irq(pcie_dev->irq[MSM_PCIE_INT_GLOBAL_INT].num); From 76db2b85025246650433e2b52adc45db632ed5a7 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Tue, 15 Jun 2021 22:21:23 +0530 Subject: [PATCH 14/37] interconnect: qcom: holi: Configure QoS during probe Configure QoS settings during probe for all nodes instead of each node individually upon first client request. Change-Id: I66e8776c8c27ca55382bca78e963ca8db1055637 Signed-off-by: Odelu Kukatla --- drivers/interconnect/qcom/holi.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/interconnect/qcom/holi.c b/drivers/interconnect/qcom/holi.c index d0edbfd1e1e9..a6a92e8719c8 100644 --- a/drivers/interconnect/qcom/holi.c +++ b/drivers/interconnect/qcom/holi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. * */ @@ -1718,6 +1718,13 @@ static int qnoc_probe(struct platform_device *pdev) return ret; } + ret = clk_bulk_prepare_enable(qp->num_qos_clks, qp->qos_clks); + if (ret) { + clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); + dev_err(&pdev->dev, "failed to enable QoS clocks\n"); + return ret; + } + for (i = 0; i < num_nodes; i++) { size_t j; @@ -1732,6 +1739,11 @@ static int qnoc_probe(struct platform_device *pdev) goto err; } + if (qnodes[i]->qosbox) { + qnodes[i]->noc_ops->set_qos(qnodes[i]); + qnodes[i]->qosbox->initialized = true; + } + node->name = qnodes[i]->name; node->data = qnodes[i]; icc_node_add(node, provider); @@ -1743,6 +1755,8 @@ static int qnoc_probe(struct platform_device *pdev) } data->num_nodes = num_nodes; + clk_bulk_disable_unprepare(qp->num_qos_clks, qp->qos_clks); + platform_set_drvdata(pdev, qp); dev_info(dev, "Registered HOLI ICC\n"); @@ -1758,6 +1772,7 @@ err: icc_node_destroy(node->id); } + clk_bulk_disable_unprepare(qp->num_qos_clks, qp->qos_clks); clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks); icc_provider_del(provider); return ret; From 8c5382949d5f2a8a97baacb9281e43687a245c0b Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Tue, 15 Jun 2021 23:03:37 +0530 Subject: [PATCH 15/37] spi: spi-msm-geni: Unset GSI mode flag if TVM usage is active This change overrides the GSI mode flag, as generally for any TVM usecase we enable la-vm flag. So that should be sufficient to manage the TVM enabled SE instance. This way any requirement of the GSI mode should not be conflicting or impacting TVM or non GSI usecases. Change-Id: I8c8ab8edb3866139ac07d1af55ddf294807b027b Signed-off-by: Mukesh Kumar Savaliya --- drivers/spi/spi-msm-geni.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-msm-geni.c b/drivers/spi/spi-msm-geni.c index 954144323254..0b71df4757e6 100644 --- a/drivers/spi/spi-msm-geni.c +++ b/drivers/spi/spi-msm-geni.c @@ -1350,9 +1350,14 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) struct se_geni_rsc *rsc; int ret = 0; - rsc = &mas->spi_rsc; - ret = pinctrl_select_state(rsc->geni_pinctrl, - rsc->geni_gpio_active); + if (!mas->is_la_vm) { + /* Do this only for non TVM LA usecase */ + /* May not be needed here, but maintain parity */ + rsc = &mas->spi_rsc; + ret = pinctrl_select_state(rsc->geni_pinctrl, + rsc->geni_gpio_active); + } + if (ret) GENI_SE_ERR(mas->ipc, false, NULL, "%s: Error %d pinctrl_select_state\n", __func__, ret); @@ -1400,17 +1405,17 @@ static int spi_geni_unprepare_transfer_hardware(struct spi_master *spi) if (mas->shared_ee || mas->is_le_vm) return 0; - if (mas->is_la_vm) - /* Client on LA VM to controls resources, hence return */ - return 0; - if (mas->gsi_mode) { struct se_geni_rsc *rsc; int ret = 0; - rsc = &mas->spi_rsc; - ret = pinctrl_select_state(rsc->geni_pinctrl, + if (!mas->is_la_vm) { + /* Do this only for non TVM LA usecase */ + rsc = &mas->spi_rsc; + ret = pinctrl_select_state(rsc->geni_pinctrl, rsc->geni_gpio_sleep); + } + if (ret) GENI_SE_ERR(mas->ipc, false, NULL, "%s: Error %d pinctrl_select_state\n", __func__, ret); From 8838ca560032990d23d62a67cf9b38caaa02e8dc Mon Sep 17 00:00:00 2001 From: Gauri Joshi Date: Mon, 10 May 2021 23:59:29 -0700 Subject: [PATCH 16/37] msm: mhi-dev: Add support for AIO write API Diag client uses asynchronous writes for data transfer. Adding write_iter API in mhi to support the same. Change-Id: If14ebdd4aa848046abd15ea93d939691c6962fcd Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 63 ++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 3a69f9359b45..2d04c2cbf5b0 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -424,6 +425,8 @@ static ssize_t mhi_uci_ctrl_client_read(struct file *file, char __user *buf, size_t count, loff_t *offp); static ssize_t mhi_uci_client_write(struct file *file, const char __user *buf, size_t count, loff_t *offp); +static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, + struct iov_iter *buf); static int mhi_uci_client_open(struct inode *mhi_inode, struct file*); static int mhi_uci_ctrl_open(struct inode *mhi_inode, struct file*); static int mhi_uci_client_release(struct inode *mhi_inode, @@ -1480,6 +1483,65 @@ error_memcpy: } +static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, + struct iov_iter *buf) +{ + struct uci_client *uci_handle = NULL; + void *data_loc; + unsigned long memcpy_result; + int rc; + struct file *file = iocb->ki_filp; + ssize_t count = iov_iter_count(buf); + + if (!file || !buf || !count || !file->private_data) { + uci_log(UCI_DBG_DBG, "Invalid access to write-iter\n"); + return -EINVAL; + } + + uci_handle = file->private_data; + if (!uci_handle->send || !uci_handle->out_handle) { + uci_log(UCI_DBG_DBG, "Invalid handle or send\n"); + return -EINVAL; + } + if (atomic_read(&uci_ctxt.mhi_disabled)) { + uci_log(UCI_DBG_ERROR, + "Client %d attempted to write while MHI is disabled\n", + uci_handle->out_chan); + return -EIO; + } + + if (!mhi_uci_are_channels_connected(uci_handle)) { + uci_log(UCI_DBG_ERROR, "%s:Channels are not connected\n", + __func__); + return -ENODEV; + } + + if (count > TRB_MAX_DATA_SIZE) { + uci_log(UCI_DBG_ERROR, + "Too big write size: %lu, max supported size is %d\n", + count, TRB_MAX_DATA_SIZE); + return -EFBIG; + } + + data_loc = kmalloc(count, GFP_KERNEL); + if (!data_loc) + return -ENOMEM; + + memcpy_result = copy_from_iter_full(data_loc, count, buf); + if (!memcpy_result) { + rc = -EFAULT; + goto error_memcpy; + } + + rc = mhi_uci_send_packet(uci_handle, data_loc, count); + if (rc == count) + return rc; + +error_memcpy: + kfree(data_loc); + return rc; +} + void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi, enum mhi_ctrl_info ch_state) { @@ -1877,6 +1939,7 @@ static const struct file_operations mhi_uci_ctrl_client_fops = { static const struct file_operations mhi_uci_client_fops = { .read = mhi_uci_client_read, .write = mhi_uci_client_write, + .write_iter = mhi_uci_client_write_iter, .open = mhi_uci_client_open, .release = mhi_uci_client_release, .poll = mhi_uci_client_poll, From 98e95994cc5e2e684c450b0ba69203a355ca24a2 Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Mon, 2 Nov 2020 14:51:05 +0530 Subject: [PATCH 17/37] msm: mhi: Send Ch cmd ack in async fashion The CH completion commands are sent in async fashion, whereas the ch cmd ack event is send in a sync fashion. This can lead to the host receiving completions post the reset ch ack. These ch completion events post ch reset would be treated as OOS events. Making changes to send cmd ack events in async fashion to maintain the ordering that is being sent to the host. Change-Id: Ib2d568ea1d69486f3d1ebf4e7b209bba3315eba5 Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi.c | 209 +++++++++++++++++++++++++---- drivers/platform/msm/mhi_dev/mhi.h | 18 ++- 2 files changed, 198 insertions(+), 29 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 4f5bfc135cbd..0eeef414892c 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -87,6 +87,10 @@ static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq); static void mhi_dev_event_msi_cb(void *req); +static void mhi_dev_cmd_event_msi_cb(void *req); + +static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi); + static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS]; static DECLARE_COMPLETION(read_from_host); @@ -262,7 +266,7 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq) { struct ep_pcie_msi_config cfg; struct mhi_addr msi_addr; - struct mhi_dev_channel *ch = ereq->context; + struct mhi_dev_channel *ch; uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring; struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx]; union mhi_dev_ring_ctx *ctx; @@ -283,14 +287,23 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq) msi_addr.phy_addr = ring->msi_buf_dma_handle; ereq->event_type = SEND_MSI; - ereq->msi_cb = mhi_dev_event_msi_cb; + if (!ereq->is_cmd_cpl) { + ch = ereq->context; + ereq->msi_cb = mhi_dev_event_msi_cb; + ch->msi_cnt++; + mhi_log(MHI_MSG_VERBOSE, + "Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n", + ctx->ev.msivec, msi_addr.host_pa, + *ring->msi_buf, ch->ch_id, + ch->msi_cnt, ereq->flush_num); + } else { + ereq->msi_cb = mhi_dev_cmd_event_msi_cb; + mhi_log(MHI_MSG_VERBOSE, + "Sending MSI %d to 0x%llx as data = 0x%x for cmd ack, ereq flush_num %d\n", + ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, + ereq->flush_num); + } - ch->msi_cnt++; - - mhi_log(MHI_MSG_VERBOSE, - "Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n", - ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id, - ch->msi_cnt, ereq->flush_num); mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC); return 0; @@ -314,6 +327,27 @@ static void mhi_dev_event_rd_offset_completion_cb(void *req) sizeof(uint64_t), DMA_TO_DEVICE); } +static void mhi_dev_cmd_event_msi_cb(void *req) +{ + struct mhi_cmd_cmpl_ctx *cmd_ctx; + struct mhi_dev *mhi; + struct event_req *ereq = req; + unsigned long flags; + + mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n", + ereq->flush_num); + + /*Cmd completion handling*/ + mhi = ereq->context; + cmd_ctx = mhi->cmd_ctx; + cmd_ctx->cmd_buf_wp += ereq->num_events; + if (cmd_ctx->cmd_buf_wp == NUM_CMD_EVENTS_DEFAULT) + cmd_ctx->cmd_buf_wp = 0; + spin_lock_irqsave(&mhi->lock, flags); + list_add_tail(&ereq->list, &cmd_ctx->cmd_req_buffers); + spin_unlock_irqrestore(&mhi->lock, flags); +} + static void mhi_dev_event_msi_cb(void *req) { struct event_req *ereq = req; @@ -401,7 +435,8 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx) } static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, - struct event_req *ereq, uint32_t evt_len) + struct event_req *ereq, uint32_t evt_len, + enum mhi_dev_tr_compl_evt_type event_type) { int rc = 0; uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring; @@ -430,25 +465,25 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, return rc; } } - ch = ereq->context; - /* Check the limits of the buffer to be flushed */ - if (ereq->tr_events < ch->tr_events || - (ereq->tr_events + ereq->num_events) > - (ch->tr_events + ch->evt_buf_size)) { - pr_err("%s: Invalid completion event buffer!\n", __func__); - mhi_log(MHI_MSG_ERROR, - "Invalid cmpl evt buf - start %pK, end %pK\n", - ereq->tr_events, ereq->tr_events + ereq->num_events); - return -EINVAL; - } + mutex_lock(&ring->event_lock); - mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n", - ereq->num_events, ch->ch_id); + /* add the events */ ereq->client_cb = mhi_dev_event_buf_completion_cb; + ereq->is_cmd_cpl = (event_type == SEND_CMD_CMP) ? true:false; ereq->event_type = SEND_EVENT_BUFFER; + if (!ereq->is_cmd_cpl) { + ch = ereq->context; + mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n", + ereq->num_events, ch->ch_id); + } else { + mhi_log(MHI_MSG_VERBOSE, + "Flushing %d cmpl events of cmd ring\n", + ereq->num_events); + } + rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len); if (rc) { pr_err("%s(): error in adding element rc %d\n", __func__, rc); @@ -506,6 +541,55 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring, return rc; } +static int mhi_dev_flush_cmd_completion_events(struct mhi_dev *mhi, + union mhi_dev_ring_element_type *el) +{ + struct mhi_cmd_cmpl_ctx *cmd_ctx = mhi->cmd_ctx; + unsigned long flags; + struct event_req *flush_ereq; + union mhi_dev_ring_element_type *compl_ev; + int rc = 0; + + /*cmd completions are sent on event ring 0 always*/ + if (!mhi->cmd_ctx) { + if (mhi_dev_alloc_cmd_ack_buf_req(mhi)) { + mhi_log(MHI_MSG_ERROR, "Alloc cmd ack buff failed"); + return -ENOMEM; + } + } + cmd_ctx = mhi->cmd_ctx; + if (list_empty(&cmd_ctx->cmd_req_buffers)) { + mhi_log(MHI_MSG_ERROR, "cmd req buff list is empty"); + return -ENOMEM; + } + + spin_lock_irqsave(&mhi->lock, flags); + flush_ereq = container_of(cmd_ctx->cmd_req_buffers.next, + struct event_req, list); + list_del_init(&flush_ereq->list); + flush_ereq->context = mhi; + spin_unlock_irqrestore(&mhi->lock, flags); + + compl_ev = cmd_ctx->cmd_events + cmd_ctx->cmd_buf_rp; + memcpy(compl_ev, el, sizeof(union mhi_dev_ring_element_type)); + cmd_ctx->cmd_buf_rp++; + if (cmd_ctx->cmd_buf_rp == NUM_CMD_EVENTS_DEFAULT) + cmd_ctx->cmd_buf_rp = 0; + flush_ereq->tr_events = compl_ev; + rc = mhi_dev_send_multiple_tr_events(mhi, + 0, + flush_ereq, + (1 * + sizeof(union mhi_dev_ring_element_type)), + SEND_CMD_CMP); + if (rc) { + mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); + return rc; + } + + return rc; +} + static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, struct mhi_dev_channel *ch) { @@ -539,11 +623,25 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, flush_ereq->flush_num = ch->flush_req_cnt; mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n", ch->flush_req_cnt, ch->ch_id); + + /* Check the limits of the buffer to be flushed */ + if (flush_ereq->tr_events < ch->tr_events || + (flush_ereq->tr_events + flush_ereq->num_events) > + (ch->tr_events + ch->evt_buf_size)) { + pr_err("%s: Invalid completion event buffer!\n", + __func__); + mhi_log(MHI_MSG_ERROR, + "Invalid cmpl evt buf - start %pK, end %pK\n", + flush_ereq->tr_events, + flush_ereq->tr_events + flush_ereq->num_events); + return -EINVAL; + } rc = mhi_dev_send_multiple_tr_events(mhi, mhi->ch_ctx_cache[ch->ch_id].err_indx, flush_ereq, (flush_ereq->num_events * - sizeof(union mhi_dev_ring_element_type))); + sizeof(union mhi_dev_ring_element_type)), + SEND_EVENT_BUFFER); if (rc) { mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n"); break; @@ -1608,7 +1706,7 @@ int mhi_dev_send_state_change_event(struct mhi_dev *mhi, event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG; event.evt_state_change.mhistate = state; - return mhi_dev_send_event(mhi, 0, &event); + return mhi_dev_flush_cmd_completion_events(mhi, &event); } EXPORT_SYMBOL(mhi_dev_send_state_change_event); @@ -1619,7 +1717,7 @@ int mhi_dev_send_ee_event(struct mhi_dev *mhi, enum mhi_dev_execenv exec_env) event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY; event.evt_ee_state.execenv = exec_env; - return mhi_dev_send_event(mhi, 0, &event); + return mhi_dev_flush_cmd_completion_events(mhi, &event); } EXPORT_SYMBOL(mhi_dev_send_ee_event); @@ -1669,7 +1767,7 @@ static int mhi_dev_send_cmd_comp_event(struct mhi_dev *mhi, (size_t) event.evt_cmd_comp.ptr); event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT; event.evt_cmd_comp.code = code; - return mhi_dev_send_event(mhi, 0, &event); + return mhi_dev_flush_cmd_completion_events(mhi, &event); } static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id, @@ -1852,7 +1950,7 @@ send_start_completion_event: event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_UNDEFINED; - rc = mhi_dev_send_event(mhi, 0, &event); + rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { pr_err("stop event send failed\n"); return; @@ -1912,7 +2010,7 @@ send_start_completion_event: event.evt_cmd_comp.code = MHI_CMD_COMPL_CODE_UNDEFINED; - rc = mhi_dev_send_event(mhi, 0, &event); + rc = mhi_dev_flush_cmd_completion_events(mhi, &event); if (rc) { pr_err("stop event send failed\n"); return; @@ -2723,6 +2821,61 @@ static uint32_t mhi_dev_get_evt_ring_size(struct mhi_dev *mhi, uint32_t ch_id) mhi->ch_ctx_cache[ch_id].err_indx].ring_size; } +static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi) +{ + int rc = 0; + uint32_t i; + struct mhi_cmd_cmpl_ctx *cmd_ctx; + union mhi_dev_ring_element_type *cmd_events; + + mhi->cmd_ctx = kmalloc(sizeof(struct mhi_cmd_cmpl_ctx), + GFP_KERNEL); + if (!mhi->cmd_ctx) + return -ENOMEM; + + cmd_ctx = mhi->cmd_ctx; + /* Allocate event requests */ + cmd_ctx->ereqs = kcalloc(NUM_CMD_EVENTS_DEFAULT, + sizeof(*cmd_ctx->ereqs), + GFP_KERNEL); + if (!cmd_ctx->ereqs) { + goto free_ereqs; + return -ENOMEM; + } + + /* Allocate buffers to queue transfer completion events */ + cmd_ctx->cmd_events = kcalloc(NUM_CMD_EVENTS_DEFAULT, + sizeof(*cmd_events), + GFP_KERNEL); + if (!cmd_ctx->cmd_events) { + rc = -ENOMEM; + goto free_ereqs; + } + + /* Organize event flush requests into a linked list */ + INIT_LIST_HEAD(&cmd_ctx->cmd_req_buffers); + + for (i = 0; i < NUM_CMD_EVENTS_DEFAULT; ++i) { + list_add_tail(&cmd_ctx->ereqs[i].list, + &cmd_ctx->cmd_req_buffers); + } + + /* + * Initialize cmpl event buffer indexes - cmd_buf_rp and + * cmd_buf_wp point to the first and last free index available. + */ + cmd_ctx->cmd_buf_rp = 0; + cmd_ctx->cmd_buf_wp = NUM_CMD_EVENTS_DEFAULT - 1; + + return 0; +free_ereqs: + kfree(mhi->cmd_ctx); + kfree(cmd_ctx->ereqs); + cmd_ctx->ereqs = NULL; + mhi->cmd_ctx = NULL; + return rc; +} + static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi, struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring) { diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 10e9ca3145dc..7fec5e68a001 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -271,6 +271,8 @@ struct mhi_config { /* maximum transfer completion events buffer */ #define NUM_TR_EVENTS_DEFAULT 128 +#define NUM_CMD_EVENTS_DEFAULT 20 + /* Set flush threshold to 80% of event buf size */ #define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10) @@ -354,7 +356,8 @@ enum mhi_dev_ch_operation { enum mhi_dev_tr_compl_evt_type { SEND_EVENT_BUFFER, SEND_EVENT_RD_OFFSET, - SEND_MSI + SEND_MSI, + SEND_CMD_CMP, }; enum mhi_dev_transfer_type { @@ -448,6 +451,18 @@ struct event_req { void (*msi_cb)(void *req); struct list_head list; u32 flush_num; + bool is_cmd_cpl; +}; + +struct mhi_cmd_cmpl_ctx { + /* Indices for completion event buffer */ + uint32_t cmd_buf_rp; + uint32_t cmd_buf_wp; + uint32_t cmd_buf_size; + bool mem_allocated; + struct list_head cmd_req_buffers; + struct event_req *ereqs; + union mhi_dev_ring_element_type *cmd_events; }; struct mhi_dev_channel { @@ -531,6 +546,7 @@ struct mhi_dev { struct mhi_dev_ring *ring; int mhi_irq; struct mhi_dev_channel *ch; + struct mhi_cmd_cmpl_ctx *cmd_ctx; int ctrl_int; int cmd_int; From 6dcfbd35bdda9b51f59d7e9dcd70509fb6709910 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Thu, 12 Dec 2019 14:57:24 +0100 Subject: [PATCH 18/37] init: use do_mount() instead of ksys_mount() In prepare_namespace(), do_mount() can be used instead of ksys_mount() as the first and third argument are const strings in the kernel, the second and fourth argument are passed through anyway, and the fifth argument is NULL. In do_mount_root(), ksys_mount() is called with the first and third argument being already kernelspace strings, which do not need to be copied over from userspace to kernelspace (again). The second and fourth arguments are passed through to do_mount() anyway. The fifth argument, while already residing in kernelspace, needs to be put into a page of its own. Then, do_mount() can be used instead of ksys_mount(). Once this is done, there are no in-kernel users to ksys_mount() left, which can therefore be removed. Change-Id: Ie21248b26e4a98796e092e20c9b8cb8126dc5eee Signed-off-by: Dominik Brodowski Patch-mainline: linux-kernel@vger.kernel.org @ 12/12/2019, 14:57 [pragalla@codeaurora.org:fix merge conflicts and port changes to 5.4 kernel] Signed-off-by: Pradeep P V K --- init/do_mounts.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/init/do_mounts.c b/init/do_mounts.c index 9634ecf3743d..871dbc3e9cb5 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -386,9 +386,21 @@ static void __init get_fs_names(char *page) static int __init do_mount_root(char *name, char *fs, int flags, void *data) { struct super_block *s; - int err = ksys_mount(name, "/root", fs, flags, data); - if (err) - return err; + char *data_page; + struct page *p; + int ret; + + /* do_mount() requires a full page as fifth argument */ + p = alloc_page(GFP_KERNEL); + if (!p) + return -ENOMEM; + + data_page = page_address(p); + strscpy(data_page, data, PAGE_SIZE - 1); + + ret = ksys_mount(name, "/root", fs, flags, data_page); + if (ret) + goto out; ksys_chdir("/root"); s = current->fs->pwd.dentry->d_sb; @@ -398,7 +410,10 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data) s->s_type->name, sb_rdonly(s) ? " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); - return 0; + +out: + put_page(p); + return ret; } void __init mount_block_root(char *name, int flags) From 67ac2d68628e4c2924bcecdca049172db25048e8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 15 Dec 2019 19:50:23 -0800 Subject: [PATCH 19/37] Fix root mounting with no mount options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "trivial conversion" in commit cccaa5e33525 ("init: use do_mount() instead of ksys_mount()") was totally broken, since it didn't handle the case of a NULL mount data pointer and while I had "tested" it (and presumably Dominik had too) that was hidden by me having options. Change-Id: I2b1db7b68e0e398ce803da40b37595c286c97d9c Cc: Dominik Brodowski Cc: Arnd Bergmann Reported-by: Ondřej Jirman Reported-by: Guenter Roeck Reported-by: Naresh Kamboju Reported-and-tested-by: Borislav Petkov Tested-by: Chris Clayton Tested-by: Eric Biggers Tested-by: Geert Uytterhoeven Tested-by: Guido Günther Signed-off-by: Linus Torvalds Git-commit: 7de7de7ca0ae0fc70515ee3154af33af75edae2c Git-repo: https://github.com/torvalds/linux.git [pragalla@codeaurora.org:fix merge conflicts and port changes to 5.4 kernel] Signed-off-by: Pradeep P V K --- init/do_mounts.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/init/do_mounts.c b/init/do_mounts.c index 871dbc3e9cb5..fa364cf4c131 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -386,17 +386,20 @@ static void __init get_fs_names(char *page) static int __init do_mount_root(char *name, char *fs, int flags, void *data) { struct super_block *s; - char *data_page; - struct page *p; + char *data_page = NULL; + struct page *p = NULL; int ret; - /* do_mount() requires a full page as fifth argument */ - p = alloc_page(GFP_KERNEL); - if (!p) - return -ENOMEM; + if (data) { + /* do_mount() requires a full page as fifth argument */ + p = alloc_page(GFP_KERNEL); + if (!p) + return -ENOMEM; - data_page = page_address(p); - strscpy(data_page, data, PAGE_SIZE - 1); + data_page = page_address(p); + /* zero-pad. do_mount() will make sure it's terminated */ + strscpy(data_page, data, PAGE_SIZE); + } ret = ksys_mount(name, "/root", fs, flags, data_page); if (ret) @@ -412,7 +415,8 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data) MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); out: - put_page(p); + if (p) + put_page(p); return ret; } From 7b6c37ada226f88031007a9853b0c802af37dd3d Mon Sep 17 00:00:00 2001 From: Vijay Patil Date: Fri, 18 Jun 2021 18:21:04 +0530 Subject: [PATCH 20/37] icnss2: Enhance debugging information Print subsystem notify event string for wpss & modem instead of event code. Print proper file type in log while downloading BDF and REGDB file. Log the error immediately if request_firmware API get fail. Change-Id: I32a07895faf2bce640e0bfe89e348c36b02c5150 Signed-off-by: Vijay Patil --- drivers/soc/qcom/icnss2/main.c | 36 ++++++++++++++++++++++++-- drivers/soc/qcom/icnss2/qmi.c | 47 ++++++++++++++++++++++++---------- 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/drivers/soc/qcom/icnss2/main.c b/drivers/soc/qcom/icnss2/main.c index 05c4c0499ae9..49d0d8a74a0f 100644 --- a/drivers/soc/qcom/icnss2/main.c +++ b/drivers/soc/qcom/icnss2/main.c @@ -1656,6 +1656,36 @@ static void icnss_update_state_send_modem_shutdown(struct icnss_priv *priv, } } +static char *icnss_subsys_notify_state_to_str(enum subsys_notif_type code) +{ + switch (code) { + case SUBSYS_BEFORE_SHUTDOWN: + return "BEFORE_SHUTDOWN"; + case SUBSYS_AFTER_SHUTDOWN: + return "AFTER_SHUTDOWN"; + case SUBSYS_BEFORE_POWERUP: + return "BEFORE_POWERUP"; + case SUBSYS_AFTER_POWERUP: + return "AFTER_POWERUP"; + case SUBSYS_BEFORE_AUTH_AND_RESET: + return "BEFORE_AUTH_AND_RESET"; + case SUBSYS_RAMDUMP_NOTIFICATION: + return "RAMDUMP_NOTIFICATION"; + case SUBSYS_POWERUP_FAILURE: + return "POWERUP_FAILURE"; + case SUBSYS_PROXY_VOTE: + return "PROXY_VOTE"; + case SUBSYS_PROXY_UNVOTE: + return "PROXY_UNVOTE"; + case SUBSYS_SOC_RESET: + return "SOC_RESET"; + case SUBSYS_NOTIF_TYPE_COUNT: + return "NOTIF_TYPE_COUNT"; + default: + return "UNKNOWN"; + } +}; + static int icnss_wpss_notifier_nb(struct notifier_block *nb, unsigned long code, void *data) @@ -1666,7 +1696,8 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb, wpss_ssr_nb); struct icnss_uevent_fw_down_data fw_down_data = {0}; - icnss_pr_vdbg("WPSS-Notify: event %lu\n", code); + icnss_pr_vdbg("WPSS-Notify: event %s(%lu)\n", + icnss_subsys_notify_state_to_str(code), code); if (code == SUBSYS_AFTER_SHUTDOWN) { icnss_pr_info("Collecting msa0 segment dump\n"); @@ -1723,7 +1754,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, modem_ssr_nb); struct icnss_uevent_fw_down_data fw_down_data = {0}; - icnss_pr_vdbg("Modem-Notify: event %lu\n", code); + icnss_pr_vdbg("Modem-Notify: event %s(%lu)\n", + icnss_subsys_notify_state_to_str(code), code); if (code == SUBSYS_AFTER_SHUTDOWN) { icnss_pr_info("Collecting msa0 segment dump\n"); diff --git a/drivers/soc/qcom/icnss2/qmi.c b/drivers/soc/qcom/icnss2/qmi.c index 95b58adcf92e..b523a357ec95 100644 --- a/drivers/soc/qcom/icnss2/qmi.c +++ b/drivers/soc/qcom/icnss2/qmi.c @@ -976,6 +976,22 @@ static int icnss_get_bdf_file_name(struct icnss_priv *priv, return ret; } +static char *icnss_bdf_type_to_str(enum icnss_bdf_type bdf_type) +{ + switch (bdf_type) { + case ICNSS_BDF_BIN: + return "BDF"; + case ICNSS_BDF_ELF: + return "BDF"; + case ICNSS_BDF_REGDB: + return "REGDB"; + case ICNSS_BDF_DUMMY: + return "BDF"; + default: + return "UNKNOWN"; + } +}; + int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type) { struct wlfw_bdf_download_req_msg_v01 *req; @@ -987,8 +1003,8 @@ int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type) unsigned int remaining; int ret = 0; - icnss_pr_dbg("Sending BDF download message, state: 0x%lx, type: %d\n", - priv->state, bdf_type); + icnss_pr_dbg("Sending %s download message, state: 0x%lx, type: %d\n", + icnss_bdf_type_to_str(bdf_type), priv->state, bdf_type); req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) @@ -1012,7 +1028,8 @@ int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type) ret = request_firmware(&fw_entry, filename, &priv->pdev->dev); if (ret) { - icnss_pr_err("Failed to load BDF: %s\n", filename); + icnss_pr_err("Failed to load %s: %s ret:%d\n", + icnss_bdf_type_to_str(bdf_type), filename, ret); goto err_req_fw; } @@ -1020,7 +1037,8 @@ int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type) remaining = fw_entry->size; bypass_bdf: - icnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining); + icnss_pr_dbg("Downloading %s: %s, size: %u\n", + icnss_bdf_type_to_str(bdf_type), filename, remaining); while (remaining) { req->valid = 1; @@ -1046,8 +1064,8 @@ bypass_bdf: ret = qmi_txn_init(&priv->qmi, &txn, wlfw_bdf_download_resp_msg_v01_ei, resp); if (ret < 0) { - icnss_pr_err("Failed to initialize txn for BDF download request, err: %d\n", - ret); + icnss_pr_err("Failed to initialize txn for %s download request, err: %d\n", + icnss_bdf_type_to_str(bdf_type), ret); goto err_send; } @@ -1058,21 +1076,22 @@ bypass_bdf: wlfw_bdf_download_req_msg_v01_ei, req); if (ret < 0) { qmi_txn_cancel(&txn); - icnss_pr_err("Failed to send respond BDF download request, err: %d\n", - ret); + icnss_pr_err("Failed to send respond %s download request, err: %d\n", + icnss_bdf_type_to_str(bdf_type), ret); goto err_send; } ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout); if (ret < 0) { - icnss_pr_err("Failed to wait for response of BDF download request, err: %d\n", - ret); + icnss_pr_err("Failed to wait for response of %s download request, err: %d\n", + icnss_bdf_type_to_str(bdf_type), ret); goto err_send; } if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { - icnss_pr_err("BDF download request failed, result: %d, err: %d\n", - resp->resp.result, resp->resp.error); + icnss_pr_err("%s download request failed, result: %d, err: %d\n", + icnss_bdf_type_to_str(bdf_type), resp->resp.result, + resp->resp.error); ret = -resp->resp.result; goto err_send; } @@ -1250,8 +1269,8 @@ int icnss_wlfw_qdss_dnld_send_sync(struct icnss_priv *priv) ret = request_firmware(&fw_entry, filename, &priv->pdev->dev); if (ret) { - icnss_pr_err("Failed to load QDSS: %s\n", - filename); + icnss_pr_err("Failed to load QDSS: %s ret:%d\n", + filename, ret); goto err_req_fw; } From 29c57b487aad93cee82b17a71d1511708262526d Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Fri, 26 Mar 2021 11:58:15 +0530 Subject: [PATCH 21/37] msm: mhi_dev: Poll for ipa_dma_disable during MHI suspend Poll for ipa_dma_disable prior to entering mhi suspend, until it returns success. this is to prevent IPA disable failure in case on pending transfers. Change-Id: I38143284447b86ce34c47e100e6fe0c23cf28f0b Signed-off-by: Subramanian Ananthanarayanan Signed-off-by: Nitesh Gupta Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_sm.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 7e3be7654729..655764d8664d 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -22,7 +22,10 @@ #define MHI_SM_FUNC_ENTRY() MHI_SM_DBG("ENTRY\n") #define MHI_SM_FUNC_EXIT() MHI_SM_DBG("EXIT\n") -#define PCIE_EP_TIMER_US 500000000 +#define PCIE_EP_TIMER_US 500000000 +#define MHI_IPA_DISABLE_DELAY_MS 10 +#define MHI_IPA_DISABLE_COUNTER 20 + static inline const char *mhi_sm_dev_event_str(enum mhi_dev_event state) { @@ -591,7 +594,7 @@ static int mhi_sm_prepare_suspend(enum mhi_dev_state new_state) { enum mhi_dev_state old_state; struct ep_pcie_inactivity inact_param; - int res = 0, rc; + int res = 0, rc, wait_timeout = 0; MHI_SM_DBG("Switching event:%d\n", new_state); @@ -668,11 +671,24 @@ static int mhi_sm_prepare_suspend(enum mhi_dev_state new_state) (new_state == MHI_DEV_M3_STATE))) { if (mhi_sm_ctx->mhi_dev->use_ipa) { MHI_SM_DBG("Disable IPA with ipa_dma_disable()\n"); - res = ipa_dma_disable(); - if (res) { - MHI_SM_ERR("IPA disable failed\n"); + while (wait_timeout < MHI_IPA_DISABLE_COUNTER) { + /* wait for the disable to finish */ + res = ipa_dma_disable(); + if (!res) + break; + MHI_SM_ERR + ("IPA disable fail cnt:%d\n", + wait_timeout); + msleep(MHI_IPA_DISABLE_DELAY_MS); + wait_timeout++; + } + + if (wait_timeout >= MHI_IPA_DISABLE_COUNTER) { + MHI_SM_ERR + ("Fail to disable IPA for M3\n"); goto exit; } + MHI_SM_ERR("IPA DMA successfully disabled\n"); } } From ea25f63fe3ebaa3877d7b097f8a5dd271f28a8a3 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Fri, 28 Jun 2019 19:04:47 -0700 Subject: [PATCH 22/37] net: qrtr: Add support for a mhi device transport Add a transport that uses the mhi device APIs. The mhi device APIs are used to transfer data from a device to the host over MHI. The modem will generally be configured as a device and this transport is intended to be used on the modem controller co-processor. commit net: qrtr: Add support for a mhi device transport (89754e5ed45dd). Change-Id: Ie9276fe6c0846581192aff881e59baa5fecf1ca4 Signed-off-by: Chris Lew Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/Kconfig | 9 ++ net/qrtr/Makefile | 2 + net/qrtr/mhi_dev.c | 249 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 net/qrtr/mhi_dev.c diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig index 78c078284532..0fde52dbc565 100644 --- a/net/qrtr/Kconfig +++ b/net/qrtr/Kconfig @@ -68,4 +68,13 @@ config QRTR_HAVEN Router communication between two virtual machines. The transport uses dynamically shared memory and haven doorbells. +config QRTR_MHI_DEV + tristate "MHI Device IPC Router channels" + depends on MSM_MHI_DEV || (COMPILE_TEST && MSM_MHI_DEV=n) + help + Say Y here to support MHI base ipcrouter channels for device + endpoint mode. MHI is the transport used for external modem + connections. This driver enables QRTR to run on the modem device + side. + endif # QRTR diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile index dfca913847d4..ecb9b5a29c58 100644 --- a/net/qrtr/Makefile +++ b/net/qrtr/Makefile @@ -7,5 +7,7 @@ obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o qrtr-tun-y := tun.o obj-$(CONFIG_QRTR_MHI) += qrtr-mhi.o qrtr-mhi-y := mhi.o +obj-$(CONFIG_QRTR_MHI_DEV) += qrtr-mhi-dev.o +qrtr-mhi-dev-y := mhi_dev.o obj-$(CONFIG_QRTR_HAVEN) += qrtr-haven.o qrtr-haven-y := haven.o diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c new file mode 100644 index 000000000000..4a926b535c83 --- /dev/null +++ b/net/qrtr/mhi_dev.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include "qrtr.h" + +#define QRTR_MAX_PKT_SIZE SZ_32K + +/* MHI DEV Enums are defined from Host perspective */ +#define QRTR_MHI_DEV_OUT MHI_CLIENT_IPCR_IN +#define QRTR_MHI_DEV_IN MHI_CLIENT_IPCR_OUT + +/** + * struct qrtr_mhi_dev_ep - qrtr mhi device endpoint + * @ep: endpoint + * @dev: device from platform bus + * @out: channel handle from mhi dev + * @out_tre: complete when channel is ready to send + * @out_lock: hold when resetting completion variable + * @in: channel handle from mhi dev + * @buf_in: buffer to hold incoming data + * @net_id: subnet id used by qrtr core + * @rt: realtime option used by qrtr core + */ +struct qrtr_mhi_dev_ep { + struct qrtr_endpoint ep; + struct device *dev; + struct mhi_dev_client *out; + struct completion out_tre; + struct mutex out_lock; /* for out critical sections */ + struct mhi_dev_client *in; + void *buf_in; + + u32 net_id; + bool rt; +}; + +static struct qrtr_mhi_dev_ep *qrtr_mhi_device_endpoint; + +static int qrtr_mhi_dev_send(struct qrtr_endpoint *ep, struct sk_buff *skb) +{ + struct qrtr_mhi_dev_ep *qep; + struct mhi_req req = { 0 }; + int rc; + + qep = container_of(ep, struct qrtr_mhi_dev_ep, ep); + rc = skb_linearize(skb); + if (rc) { + kfree_skb(skb); + return rc; + } + + req.chan = QRTR_MHI_DEV_OUT; + req.client = qep->out; + req.mode = DMA_SYNC; + req.buf = skb->data; + req.len = skb->len; + + do { + wait_for_completion(&qep->out_tre); + + mutex_lock(&qep->out_lock); + rc = mhi_dev_write_channel(&req); + if (rc == 0) + reinit_completion(&qep->out_tre); + mutex_unlock(&qep->out_lock); + } while (!rc); + + if (rc != skb->len) { + dev_err(qep->dev, "send failed rc:%d len:%d\n", rc, skb->len); + kfree_skb(skb); + return rc; + } + + consume_skb(skb); + return 0; +} + +static void qrtr_mhi_dev_read(struct qrtr_mhi_dev_ep *qep) +{ + struct mhi_req req = { 0 }; + int rc; + + req.chan = QRTR_MHI_DEV_IN; + req.client = qep->in; + req.mode = DMA_SYNC; + req.buf = qep->buf_in; + req.len = QRTR_MAX_PKT_SIZE; + + rc = mhi_dev_read_channel(&req); + if (rc < 0) { + dev_err(qep->dev, "failed to read channel %d\n", rc); + return; + } + + rc = qrtr_endpoint_post(&qep->ep, req.buf, req.transfer_len); + if (rc == -EINVAL) + dev_err(qep->dev, "invalid ipcrouter packet\n"); +} + +static void qrtr_mhi_dev_event_cb(struct mhi_dev_client_cb_reason *reason) +{ + struct qrtr_mhi_dev_ep *qep; + + qep = qrtr_mhi_device_endpoint; + if (!qep) + return; + + if (reason->reason == MHI_DEV_TRE_AVAILABLE) { + pr_debug("TRE available event for chan %d\n", reason->ch_id); + if (reason->ch_id == QRTR_MHI_DEV_IN) { + qrtr_mhi_dev_read(qep); + } else { + mutex_lock(&qep->out_lock); + complete_all(&qep->out_tre); + mutex_unlock(&qep->out_lock); + } + } +} + +static int qrtr_mhi_dev_open_channels(struct qrtr_mhi_dev_ep *qep) +{ + int rc; + + /* write channel */ + rc = mhi_dev_open_channel(QRTR_MHI_DEV_OUT, &qep->out, + qrtr_mhi_dev_event_cb); + if (rc < 0) + return rc; + + /* read channel */ + rc = mhi_dev_open_channel(QRTR_MHI_DEV_IN, &qep->in, + qrtr_mhi_dev_event_cb); + if (rc < 0) { + mhi_dev_close_channel(qep->out); + return rc; + } + return 0; +} + +static void qrtr_mhi_dev_close_channels(struct qrtr_mhi_dev_ep *qep) +{ + int rc; + + rc = mhi_dev_close_channel(qep->out); + if (rc < 0) + dev_err(qep->dev, "failed to close out channel %d\n", rc); + + rc = mhi_dev_close_channel(qep->in); + if (rc < 0) + dev_err(qep->dev, "failed to close in channel %d\n", rc); +} + +static void qrtr_mhi_dev_state_cb(struct mhi_dev_client_cb_data *cb_data) +{ + struct qrtr_mhi_dev_ep *qep; + int rc; + + if (!cb_data || !cb_data->user_data) + return; + qep = cb_data->user_data; + + switch (cb_data->ctrl_info) { + case MHI_STATE_CONNECTED: + rc = qrtr_mhi_dev_open_channels(qep); + if (rc) { + dev_err(qep->dev, "open failed %d\n", rc); + return; + } + + rc = qrtr_endpoint_register(&qep->ep, qep->net_id, qep->rt); + if (rc) { + dev_err(qep->dev, "register failed %d\n", rc); + qrtr_mhi_dev_close_channels(qep); + } + break; + case MHI_STATE_DISCONNECTED: + qrtr_endpoint_unregister(&qep->ep); + qrtr_mhi_dev_close_channels(qep); + break; + default: + break; + } +} + +static int qrtr_mhi_dev_probe(struct platform_device *pdev) +{ + struct qrtr_mhi_dev_ep *qep; + struct device_node *node; + int rc; + + qep = devm_kzalloc(&pdev->dev, sizeof(*qep), GFP_KERNEL); + if (!qep) + return -ENOMEM; + qep->dev = &pdev->dev; + + node = pdev->dev.of_node; + rc = of_property_read_u32(node, "qcom,net-id", &qep->net_id); + if (rc < 0) + qep->net_id = QRTR_EP_NET_ID_AUTO; + qep->rt = of_property_read_bool(node, "qcom,low-latency"); + + qep->buf_in = devm_kzalloc(&pdev->dev, QRTR_MAX_PKT_SIZE, GFP_KERNEL); + if (!qep->buf_in) + return -ENOMEM; + + qrtr_mhi_device_endpoint = qep; + + mutex_init(&qep->out_lock); + init_completion(&qep->out_tre); + qep->ep.xmit = qrtr_mhi_dev_send; + rc = mhi_register_state_cb(qrtr_mhi_dev_state_cb, qep, + QRTR_MHI_DEV_OUT); + if (rc) + return rc; + + return 0; +} + +static const struct of_device_id qrtr_mhi_dev_match_table[] = { + { .compatible = "qcom,qrtr-mhi-dev"}, + {}, +}; + +static struct platform_driver qrtr_mhi_dev_driver = { + .probe = qrtr_mhi_dev_probe, + .driver = { + .name = "qrtr_mhi_dev", + .of_match_table = qrtr_mhi_dev_match_table, + }, +}; +module_platform_driver(qrtr_mhi_dev_driver); + +MODULE_DESCRIPTION("QTI IPC-Router MHI device interface driver"); +MODULE_LICENSE("GPL v2"); From c5719367783b89b5bb732448abeddc7bfb0891da Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 3 Jun 2021 11:08:31 +0530 Subject: [PATCH 23/37] net: qrtr: Change the in and out channels MHI's IN channel is QRTR's OUT channel and vice-versa. commit net: qrtr: Change the in and out channels (5c9c165066de0). Change-Id: If16790e629263cfa2787a08326c079b58f42617b Signed-off-by: Chris Lew Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/mhi_dev.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c index 4a926b535c83..74cc2f6dbfdb 100644 --- a/net/qrtr/mhi_dev.c +++ b/net/qrtr/mhi_dev.c @@ -137,16 +137,16 @@ static int qrtr_mhi_dev_open_channels(struct qrtr_mhi_dev_ep *qep) int rc; /* write channel */ - rc = mhi_dev_open_channel(QRTR_MHI_DEV_OUT, &qep->out, + rc = mhi_dev_open_channel(QRTR_MHI_DEV_IN, &qep->in, qrtr_mhi_dev_event_cb); if (rc < 0) return rc; /* read channel */ - rc = mhi_dev_open_channel(QRTR_MHI_DEV_IN, &qep->in, + rc = mhi_dev_open_channel(QRTR_MHI_DEV_OUT, &qep->out, qrtr_mhi_dev_event_cb); if (rc < 0) { - mhi_dev_close_channel(qep->out); + mhi_dev_close_channel(qep->in); return rc; } return 0; @@ -156,13 +156,13 @@ static void qrtr_mhi_dev_close_channels(struct qrtr_mhi_dev_ep *qep) { int rc; - rc = mhi_dev_close_channel(qep->out); - if (rc < 0) - dev_err(qep->dev, "failed to close out channel %d\n", rc); - rc = mhi_dev_close_channel(qep->in); if (rc < 0) dev_err(qep->dev, "failed to close in channel %d\n", rc); + + rc = mhi_dev_close_channel(qep->out); + if (rc < 0) + dev_err(qep->dev, "failed to close out channel %d\n", rc); } static void qrtr_mhi_dev_state_cb(struct mhi_dev_client_cb_data *cb_data) @@ -224,7 +224,7 @@ static int qrtr_mhi_dev_probe(struct platform_device *pdev) init_completion(&qep->out_tre); qep->ep.xmit = qrtr_mhi_dev_send; rc = mhi_register_state_cb(qrtr_mhi_dev_state_cb, qep, - QRTR_MHI_DEV_OUT); + QRTR_MHI_DEV_IN); if (rc) return rc; From 66aeb46272843f97c2847a259cabf8ce6e523217 Mon Sep 17 00:00:00 2001 From: Jay Jayanna Date: Fri, 19 Jul 2019 15:29:31 -0700 Subject: [PATCH 24/37] net: qrtr: Loop on mhi_dev_read_channel until it returns 0 qrtr_mhi_dev_event_cb will be called only once if there is more than one packet at that time. Hence, call mhi_dev_read_channel in a loop until it returns zero. commit net: qrtr: Loop on mhi_dev_read_channel until it returns 0 (1a79f2584ef87). Change-Id: I2f171cb45e66c1c439fcc7d0027c22d0edb4fb19 Signed-off-by: Jay Jayanna Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/mhi_dev.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c index 74cc2f6dbfdb..f828574ddd6c 100644 --- a/net/qrtr/mhi_dev.c +++ b/net/qrtr/mhi_dev.c @@ -94,6 +94,7 @@ static void qrtr_mhi_dev_read(struct qrtr_mhi_dev_ep *qep) { struct mhi_req req = { 0 }; int rc; + int bytes_read; req.chan = QRTR_MHI_DEV_IN; req.client = qep->in; @@ -101,15 +102,18 @@ static void qrtr_mhi_dev_read(struct qrtr_mhi_dev_ep *qep) req.buf = qep->buf_in; req.len = QRTR_MAX_PKT_SIZE; - rc = mhi_dev_read_channel(&req); - if (rc < 0) { - dev_err(qep->dev, "failed to read channel %d\n", rc); - return; - } + do { + bytes_read = mhi_dev_read_channel(&req); + if (bytes_read < 0) { + dev_err(qep->dev, "failed to read channel %d\n", + bytes_read); + return; + } - rc = qrtr_endpoint_post(&qep->ep, req.buf, req.transfer_len); - if (rc == -EINVAL) - dev_err(qep->dev, "invalid ipcrouter packet\n"); + rc = qrtr_endpoint_post(&qep->ep, req.buf, req.transfer_len); + if (rc == -EINVAL) + dev_err(qep->dev, "invalid ipcrouter packet\n"); + } while (bytes_read > 0); } static void qrtr_mhi_dev_event_cb(struct mhi_dev_client_cb_reason *reason) From f1b60eb49631a1b77e01612de1f9ccb354c17777 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Thu, 31 Oct 2019 23:58:17 +0530 Subject: [PATCH 25/37] net: qrtr: mhi_dev: Only post valid data mhi_dev_read_channel returns the number of bytes read. Do not post a packet to qrtr if the length returned is 0. This prevents an issue where qrtr receives duplicates packets from the mhi_dev transport. commit net: qrtr: mhi_dev: Only post valid data (b4451ceb04138). Change-Id: Ib1a31665730293baa9af61a9ae61bd8bdf6cab6f Signed-off-by: Sricharan R Signed-off-by: Chris Lew Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/mhi_dev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c index f828574ddd6c..cb138d5653a5 100644 --- a/net/qrtr/mhi_dev.c +++ b/net/qrtr/mhi_dev.c @@ -109,6 +109,8 @@ static void qrtr_mhi_dev_read(struct qrtr_mhi_dev_ep *qep) bytes_read); return; } + if (bytes_read == 0) + return; rc = qrtr_endpoint_post(&qep->ep, req.buf, req.transfer_len); if (rc == -EINVAL) From 74ac2ceb7f01095f2ce53577d0f336c8b503da03 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Mon, 28 Oct 2019 14:55:07 -0700 Subject: [PATCH 26/37] msm: mhi_dev: Update release function in MHI After MHI device receives a reset command the internal state machine suspends all activity on the channel and processes the device reset. Clients are notified on the channel close. Existing close function checks if there are pending data to be read but since the device is in the process of cleaning the transfer buffers and the channels are suspended this check is not required. commit msm: mhi_dev: Update release function in MHI (6772e50d7b8fc). Change-Id: Iafc5249762b1468ee2cca4ac141522ce0356d403 Signed-off-by: Siddartha Mohanadoss Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/mhi_dev.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c index cb138d5653a5..0c45f9ade275 100644 --- a/net/qrtr/mhi_dev.c +++ b/net/qrtr/mhi_dev.c @@ -160,15 +160,9 @@ static int qrtr_mhi_dev_open_channels(struct qrtr_mhi_dev_ep *qep) static void qrtr_mhi_dev_close_channels(struct qrtr_mhi_dev_ep *qep) { - int rc; - rc = mhi_dev_close_channel(qep->in); - if (rc < 0) - dev_err(qep->dev, "failed to close in channel %d\n", rc); - - rc = mhi_dev_close_channel(qep->out); - if (rc < 0) - dev_err(qep->dev, "failed to close out channel %d\n", rc); + mhi_dev_close_channel(qep->in); + mhi_dev_close_channel(qep->out); } static void qrtr_mhi_dev_state_cb(struct mhi_dev_client_cb_data *cb_data) From d7842ded9157853c368045a8ce50f2b245cad31b Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Fri, 10 Apr 2020 10:40:45 +0530 Subject: [PATCH 27/37] qrtr: mhi-dev: Wait for RX channel to be enumerated Registering only for endpoint RX channel to complete enumeration and starting to open both RX/TX channels leads to race condition on TX channel. Since the host does TX followed by RX init. Wait for endpoint TX channel init to synchronise with host. commit qrtr: mhi-dev: Wait for RX channel to be enumerated (5593a67ad0546). Change-Id: Ied002a89b51f71fa30cb7557f7dce27cfe1fd202 Signed-off-by: Sricharan R Signed-off-by: Arun Kumar Neelakantam Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/mhi_dev.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c index 0c45f9ade275..1eb5649eb50b 100644 --- a/net/qrtr/mhi_dev.c +++ b/net/qrtr/mhi_dev.c @@ -223,8 +223,11 @@ static int qrtr_mhi_dev_probe(struct platform_device *pdev) mutex_init(&qep->out_lock); init_completion(&qep->out_tre); qep->ep.xmit = qrtr_mhi_dev_send; + /* HOST init TX first followed by RX, so register for endpoint TX + * which makes both channel ready by checking one channel state. + */ rc = mhi_register_state_cb(qrtr_mhi_dev_state_cb, qep, - QRTR_MHI_DEV_IN); + QRTR_MHI_DEV_OUT); if (rc) return rc; From 2c04602122aeccb1252276f29314afbcce57cd10 Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Fri, 29 May 2020 20:16:27 +0530 Subject: [PATCH 28/37] net: qrtr: mhi_dev: Handle mhi register error case Handle -EEXIST error case while register state callback with mhi device. If channel is open during registration no callback will issue instead mhi stack return -EEXIST to notify the client. Further state change notification will be informed via registered callback. commit net: qrtr: mhi_dev: Handle mhi register error case (f1eeca90b18b7). Change-Id: Icf60de35d23393a0808ef90058c1108e950d02b9 Signed-off-by: Arun Prakash Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/mhi_dev.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c index 1eb5649eb50b..3f6091c1656b 100644 --- a/net/qrtr/mhi_dev.c +++ b/net/qrtr/mhi_dev.c @@ -202,6 +202,7 @@ static int qrtr_mhi_dev_probe(struct platform_device *pdev) struct qrtr_mhi_dev_ep *qep; struct device_node *node; int rc; + struct mhi_dev_client_cb_data cb_data; qep = devm_kzalloc(&pdev->dev, sizeof(*qep), GFP_KERNEL); if (!qep) @@ -228,8 +229,21 @@ static int qrtr_mhi_dev_probe(struct platform_device *pdev) */ rc = mhi_register_state_cb(qrtr_mhi_dev_state_cb, qep, QRTR_MHI_DEV_OUT); - if (rc) + if (rc == -EEXIST) { + /** + * MHI stack will return -EEXIST if mhi channel is already + * opend by the host and will not invoke reqistered callback. + * But future state change notification will inform through + * registered callback. + */ + complete_all(&qep->out_tre); + cb_data.user_data = (void *)qep; + cb_data.channel = QRTR_MHI_DEV_OUT; + cb_data.ctrl_info = MHI_STATE_CONNECTED; + qrtr_mhi_dev_state_cb(&cb_data); + } else if (rc) { return rc; + } return 0; } From 0fb619aac4f9429cb064601371c0c2a308b06b65 Mon Sep 17 00:00:00 2001 From: Manoharan Vijaya Raghavan Date: Thu, 3 Jun 2021 10:10:00 +0530 Subject: [PATCH 29/37] arm: defconfig: Enable QRTR over MHI device Enable QRTR over MHI device. Change-Id: Ie34e0ca68346bd1370c55d3fcbb3d4ba44dc6cae Signed-off-by: Manoharan Vijaya Raghavan --- arch/arm/configs/vendor/sdxlemur.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 5759d09323eb..658c6e4a97dc 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -171,6 +171,7 @@ CONFIG_NET_SCH_PRIO=y CONFIG_NET_SCH_TBF=y CONFIG_QRTR=y CONFIG_QRTR_MHI=y +CONFIG_QRTR_MHI_DEV=y CONFIG_QRTR_SMD=y CONFIG_NETDEVICES=y CONFIG_MAILBOX=y From f1cc6d4bb6c8d9bb46db4706d6d23b61ce3a12e9 Mon Sep 17 00:00:00 2001 From: Manoharan Vijaya Raghavan Date: Tue, 22 Jun 2021 13:22:33 +0530 Subject: [PATCH 30/37] arm: defconfig: Fix qrtr node id conflict for sdx65 The default Node ID 1 has conflict, as node ID 1 is being used in IPQ-RC too. Hence fix the Node ID to be 2, (similar to sdx55). Change-Id: I887b6523119531158e33d706b3b9fca2281d9bf5 Signed-off-by: Manoharan Vijaya Raghavan --- arch/arm/configs/vendor/sdxlemur.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 658c6e4a97dc..97f39227174d 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -172,6 +172,7 @@ CONFIG_NET_SCH_TBF=y CONFIG_QRTR=y CONFIG_QRTR_MHI=y CONFIG_QRTR_MHI_DEV=y +CONFIG_QRTR_NODE_ID=2 CONFIG_QRTR_SMD=y CONFIG_NETDEVICES=y CONFIG_MAILBOX=y From aead58632ecceed5126ac6c58379c70b5b547037 Mon Sep 17 00:00:00 2001 From: Manoharan Vijaya Raghavan Date: Thu, 3 Jun 2021 13:12:46 +0530 Subject: [PATCH 31/37] net: qrtr: ns: Fix Announce services for all nodes ns service was notifying only local node ID services after a pci disconnect and reconnect. Fix it to iterate over all nodes and announce services of all nodes. Change-Id: I4f91a71ad847b815318a7de47134f6b9c57dff53 Signed-off-by: Manoharan Vijaya Raghavan --- net/qrtr/ns.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c index d138ca1d27bc..845f21c8e1d0 100644 --- a/net/qrtr/ns.c +++ b/net/qrtr/ns.c @@ -227,24 +227,26 @@ static int announce_servers(struct sockaddr_qrtr *sq) struct qrtr_server *srv; struct qrtr_node *node; unsigned long index; + unsigned long node_idx; int ret; - node = node_get(qrtr_ns.local_node); - if (!node) - return 0; - /* Announce the list of servers registered in this node */ - xa_for_each(&node->servers, index, srv) { - ret = service_announce_new(sq, srv); - if (ret < 0) { - if (ret == -ENODEV) - continue; + xa_for_each(&nodes, node_idx, node) { + if (node->id == sq->sq_node) { + pr_info("Avoiding duplicate announce for NODE ID %u\n", node->id); + continue; + } + xa_for_each(&node->servers, index, srv) { + ret = service_announce_new(sq, srv); + if (ret < 0) { + if (ret == -ENODEV) + continue; - pr_err("failed to announce new service %d\n", ret); - return ret; + pr_err("failed to announce new service %d\n", ret); + return ret; + } } } - return 0; } From 51d46d049b239f4de8d6ea1e336cbeabc8df7a5a Mon Sep 17 00:00:00 2001 From: Mayank Grover Date: Thu, 11 Mar 2021 16:37:45 +0530 Subject: [PATCH 32/37] drivers: pinctrl: Add support to access tlmm spare registers Add support to read and write SPARE registers in TLMM block. Change-Id: I6426b86510256983b509c5f48c2ab02f80b48ef8 Signed-off-by: Mayank Grover --- drivers/pinctrl/qcom/pinctrl-msm.c | 40 ++++++++++++++++++++++++++++ drivers/pinctrl/qcom/pinctrl-msm.h | 12 +++++++++ include/linux/pinctrl/qcom-pinctrl.h | 6 ++++- 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 85f8548d04ee..4f5442c37985 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -37,6 +37,7 @@ #define MAX_NR_TILES 4 #define PS_HOLD_OFFSET 0x820 #define QUP_MASK GENMASK(5, 0) +#define SPARE_MASK GENMASK(15, 8) /** * struct msm_pinctrl - state for a pinctrl-msm device @@ -1505,6 +1506,45 @@ int msm_qup_read(unsigned int mode) return -ENOENT; } +int msm_spare_write(int spare_reg, u32 val) +{ + u32 offset; + const struct msm_spare_tlmm *regs = msm_pinctrl_data->soc->spare_regs; + int num_regs = msm_pinctrl_data->soc->nspare_regs; + + if (!regs || spare_reg >= num_regs) + return -ENOENT; + + offset = regs[spare_reg].offset; + if (offset != 0) { + writel_relaxed(val & SPARE_MASK, + msm_pinctrl_data->regs[0] + offset); + return 0; + } + + return -ENOENT; +} +EXPORT_SYMBOL(msm_spare_write); + +int msm_spare_read(int spare_reg) +{ + u32 offset, val; + const struct msm_spare_tlmm *regs = msm_pinctrl_data->soc->spare_regs; + int num_regs = msm_pinctrl_data->soc->nspare_regs; + + if (!regs || spare_reg >= num_regs) + return -ENOENT; + + offset = regs[spare_reg].offset; + if (offset != 0) { + val = readl_relaxed(msm_pinctrl_data->regs[0] + offset); + return val & SPARE_MASK; + } + + return -ENOENT; +} +EXPORT_SYMBOL(msm_spare_read); + /* * msm_gpio_mpm_wake_set - API to make interrupt wakeup capable * @dev: Device corrsponding to pinctrl diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h index 5bcac8855500..687b4a2f3435 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.h +++ b/drivers/pinctrl/qcom/pinctrl-msm.h @@ -125,6 +125,16 @@ struct pinctrl_qup { u32 offset; }; +/* + * struct msm_spare_tlmm - TLMM spare registers config + * @spare_reg: spare register number + * @offset: Offset of spare register + */ +struct msm_spare_tlmm { + int spare_reg; + u32 offset; +}; + /** * struct msm_gpio_wakeirq_map - Map of GPIOs and their wakeup pins * @gpio: The GPIOs that are wakeup capable @@ -169,6 +179,8 @@ struct msm_pinctrl_soc_data { unsigned int n_no_wake_gpios; struct pinctrl_qup *qup_regs; unsigned int nqup_regs; + const struct msm_spare_tlmm *spare_regs; + unsigned int nspare_regs; struct msm_dir_conn *dir_conn; }; diff --git a/include/linux/pinctrl/qcom-pinctrl.h b/include/linux/pinctrl/qcom-pinctrl.h index a3629fb09802..14b20ed634da 100644 --- a/include/linux/pinctrl/qcom-pinctrl.h +++ b/include/linux/pinctrl/qcom-pinctrl.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019,2021 The Linux Foundation. All rights reserved. */ #ifndef __LINUX_PINCTRL_MSM_H__ @@ -15,4 +15,8 @@ int msm_qup_read(u32 mode); /* API to write to mpm_wakeup registers */ int msm_gpio_mpm_wake_set(unsigned int gpio, bool enable); +/* APIS to TLMM Spare registers */ +int msm_spare_write(int spare_reg, u32 val); +int msm_spare_read(int spare_reg); + #endif /* __LINUX_PINCTRL_MSM_H__ */ From 1711db1ab9522945551132e772ab6e9c12a1bc13 Mon Sep 17 00:00:00 2001 From: Mayank Grover Date: Thu, 18 Mar 2021 11:50:21 +0530 Subject: [PATCH 33/37] pinctrl: qcom: Add blair tlmm spare registers Add support to enable access for tlmm spare registers for blair. Change-Id: I250c0fd796ca80e019c6d5732394817c7527cc1c Signed-off-by: Mayank Grover --- drivers/pinctrl/qcom/pinctrl-blair.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-blair.c b/drivers/pinctrl/qcom/pinctrl-blair.c index 56689c707d48..8d4b6a3f83ff 100644 --- a/drivers/pinctrl/qcom/pinctrl-blair.c +++ b/drivers/pinctrl/qcom/pinctrl-blair.c @@ -118,7 +118,23 @@ .offset = qup_offset, \ } +#define TLMM_NORTH_SPARE_OFFSET 0x1B3000 +#define TLMM_NORTH_SPARE1_OFFSET 0x1B4000 +#define SPARE_REG(sparereg, spare_offset) \ + { \ + .spare_reg = tlmm_##sparereg, \ + .offset = spare_offset, \ + } + +enum blair_tlmm_spare { + tlmm_west_spare, + tlmm_west_spare1, + tlmm_north_spare, + tlmm_north_spare1, + tlmm_south_spare, + tlmm_south_spare1, +}; static const struct pinctrl_pin_desc blair_pins[] = { PINCTRL_PIN(0, "GPIO_0"), @@ -1312,6 +1328,15 @@ static const struct msm_function blair_functions[] = { FUNCTION(USB_PHY), }; +static const struct msm_spare_tlmm blair_spare_regs[] = { + SPARE_REG(west_spare, 0), + SPARE_REG(west_spare1, 0), + SPARE_REG(north_spare, TLMM_NORTH_SPARE_OFFSET), + SPARE_REG(north_spare1, TLMM_NORTH_SPARE1_OFFSET), + SPARE_REG(south_spare, 0), + SPARE_REG(south_spare1, 0), +}; + /* Every pin is maintained as a single group, and missing or non-existing pin * would be maintained as dummy group to synchronize pin group index with * pin descriptor registered with pinctrl core. @@ -1652,6 +1677,8 @@ static const struct msm_pinctrl_soc_data blair_pinctrl = { .ngpios = 157, .wakeirq_map = blair_mpm_map, .nwakeirq_map = ARRAY_SIZE(blair_mpm_map), + .spare_regs = blair_spare_regs, + .nspare_regs = ARRAY_SIZE(blair_spare_regs), }; static int blair_pinctrl_probe(struct platform_device *pdev) From 485572902c62da909ca4a29ff4f11d904930beea Mon Sep 17 00:00:00 2001 From: Gauri Joshi Date: Fri, 4 Jun 2021 16:51:01 -0700 Subject: [PATCH 34/37] msm: mhi-dev: Send channel state broadcasts for QRTR channels Set the channel attribute for QRTR channels (MHI_CLIENT_IPCR_OUT and MHI_CLIENT_IPCR_IN) so that QRTR client gets the uevent broadcast when the channel state changes. Change the naming for the structure to mhi_chan_attr_table since kernel clients are also configured using the same structure. Change-Id: I40232a09c27d7410d772055448d0354fb0c359b1 Signed-off-by: Gauri Joshi --- drivers/platform/msm/mhi_dev/mhi_uci.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 2d04c2cbf5b0..d33ddfe5ea81 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -96,8 +96,11 @@ static void mhi_uci_generic_client_cb(struct mhi_dev_client_cb_data *cb_data); static void mhi_uci_at_ctrl_client_cb(struct mhi_dev_client_cb_data *cb_data); static void mhi_uci_at_ctrl_tre_cb(struct mhi_dev_client_cb_reason *reason); -/* UCI channel attributes table */ -static const struct chan_attr uci_chan_attr_table[] = { +/* MHI channel attributes table + * Skip node creation for IPCR channels but still allow uevent broadcast to + * QRTR client by setting the broadcast flag + */ +static const struct chan_attr mhi_chan_attr_table[] = { { MHI_CLIENT_LOOPBACK_OUT, TRB_MAX_DATA_SIZE, @@ -267,7 +270,7 @@ static const struct chan_attr uci_chan_attr_table[] = { NULL, NULL, false, - false, + true, true }, { @@ -1224,8 +1227,8 @@ static int mhi_state_uevent(struct device *dev, struct kobj_uevent_env *env) mhi_parse_state(buf, &nbytes, info); add_uevent_var(env, "MHI_STATE=%s", buf); - for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i++) { - chan_attrib = &uci_chan_attr_table[i]; + for (i = 0; i < ARRAY_SIZE(mhi_chan_attr_table); i++) { + chan_attrib = &mhi_chan_attr_table[i]; if (chan_attrib->state_bcast) { uci_log(UCI_DBG_ERROR, "Calling notify for ch %d\n", chan_attrib->chan_id); @@ -1548,8 +1551,8 @@ void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi, unsigned int i; const struct chan_attr *chan_attrib; - for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i++) { - chan_attrib = &uci_chan_attr_table[i]; + for (i = 0; i < ARRAY_SIZE(mhi_chan_attr_table); i++) { + chan_attrib = &mhi_chan_attr_table[i]; if (chan_attrib->state_bcast) { uci_log(UCI_DBG_ERROR, "Calling notify for ch %d\n", chan_attrib->chan_id); @@ -2101,8 +2104,8 @@ static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt) struct uci_client *client; const struct chan_attr *chan_attrib; - for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i += 2) { - chan_attrib = &uci_chan_attr_table[i]; + for (i = 0; i < ARRAY_SIZE(mhi_chan_attr_table); i += 2) { + chan_attrib = &mhi_chan_attr_table[i]; index = CHAN_TO_CLIENT(chan_attrib->chan_id); client = &uci_ctxt->client_handles[index]; client->out_chan_attr = chan_attrib; From 3cb01862db8935d16089d45acb47bc4847363237 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Fri, 20 Mar 2020 21:01:58 +0530 Subject: [PATCH 35/37] usb: dwc3-msm: Enable pwr_evt_irq for wakeup after LPM is done Platforms using Synopsys SS phy are enabling pwr_evt_irq for wakeup events in host mode as a part of dwc3_msm_suspend, but before all the resources have been relinquished. So it is possible that an IRQ is fired before dwc->in_lpm could be set to 1. Because of this, the pwr_event_handler will try to read STAT_REG without issuing resume_work leading to unclocked access. Fix this by enabling pwr_evt_irq only after in_lpm flag is set to 1, hence ensuring resume when the irq is fired. Change-Id: I9772f427ecd10c2922c998cf0d57734362413051 Signed-off-by: Ajay Agarwal --- drivers/usb/dwc3/dwc3-msm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 77afbed72763..b13bb0d2c1a7 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3308,7 +3308,6 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; } else if (mdwc->use_pwr_event_for_wakeup) { dwc3_msm_set_ss_pwr_events(mdwc, true); - enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); } /* make sure above writes are completed before turning off clocks */ @@ -3376,6 +3375,10 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, mdwc->lpm_flags |= MDWC3_ASYNC_IRQ_WAKE_CAPABILITY; } + if (mdwc->use_pwr_event_for_wakeup && + !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) + enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); + dev_info(mdwc->dev, "DWC3 in low power mode\n"); dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm)); From 11760143e663ad78e3718295d6011db5dc39247f Mon Sep 17 00:00:00 2001 From: Rohith Kollalsi Date: Sun, 20 Jun 2021 23:46:57 +0530 Subject: [PATCH 36/37] usb: dwc3: Use pwr_evt_irq to wakeup if dp/dm directly connected to GIC Currently support to enable/disable dplus hsphy irq and dminus hsphy irq in case of resume/suspend is present only for pdc interrupts. This support should be present even for non pdc interrupts if the platform uses snps usb hs phy. Absence of this support leads to dp/dm hsphy irq not being fired and usb stuck in lpm in host mode eventhough there is a disconnect or remote wakeup issued from hs/fs device connected to it. Hence add support to enable/disable dp hsphy irq and dm hsphy irq for platforms that use snps hs phy. On platforms which use snps phy and mpm interrupts, dp/dm lines are directly connected to gic when cpu is active, mpm is involved only when cpu is not active. Now in cpu active case, in host mode if usb goes to lpm with hs/fs/ls device connected and unplug/remote wakeup is issued, dp falling edge is monitored in software to detect that. But gic is not capable of detecting a falling edge. Hence this change adds support to program power event irq to wakeup the system in this case. Note that gic takes care of dp rising edge wakeup events like usb connect over otg when usb is in lpm and in host mode. Only in case where dp falling edge is monitored i.e in case of hs/fs/ls device connect and usb enteres lpm, then power event irq is used to detect wakeup event as GIC cannot detect falling edge. Change-Id: I085b86c7df52daeedfb35cb71657c5163c2d5aaa Signed-off-by: Rohith Kollalsi --- drivers/usb/dwc3/dwc3-msm.c | 96 +++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index b13bb0d2c1a7..3b439bf49bdf 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -490,11 +490,15 @@ struct dwc3_msm { bool suspend; bool use_pdc_interrupts; enum dwc3_id_state id_state; - bool use_pwr_event_for_wakeup; + unsigned long use_pwr_event_for_wakeup; +#define PWR_EVENT_SS_WAKEUP BIT(0) +#define PWR_EVENT_HS_WAKEUP BIT(1) + unsigned long lpm_flags; #define MDWC3_SS_PHY_SUSPEND BIT(0) #define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY BIT(1) #define MDWC3_POWER_COLLAPSE BIT(2) +#define MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP BIT(3) struct extcon_nb *extcon; int ext_idx; @@ -3047,7 +3051,7 @@ static void configure_usb_wakeup_interrupt(struct dwc3_msm *mdwc, } } -static void enable_usb_pdc_interrupt(struct dwc3_msm *mdwc, bool enable) +static void configure_usb_wakeup_interrupts(struct dwc3_msm *mdwc, bool enable) { if (!enable) goto disable_usb_irq; @@ -3131,7 +3135,7 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc, } } -static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on) +static void dwc3_msm_set_pwr_events(struct dwc3_msm *mdwc, bool on) { u32 irq_mask, irq_stat; @@ -3142,12 +3146,28 @@ static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on) irq_mask = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG); - if (on) - irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK | - PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); - else - irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK | - PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); + if (on) { + /* + * In case of platforms which use mpm interrupts, in case where + * suspend happens with a hs/fs/ls device connected in host mode. + * DP/DM falling edge will be monitored, but gic doesn't have + * capability to detect falling edge. So program power event irq + * to notify exit from lpm in such case. + */ + if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_HS_WAKEUP) + irq_mask |= PWR_EVNT_LPM_OUT_L2_MASK; + if ((mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) + && !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) + irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK | + PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); + } else { + if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_HS_WAKEUP) + irq_mask &= ~PWR_EVNT_LPM_OUT_L2_MASK; + if ((mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) + && !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) + irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK | + PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK); + } dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG, irq_mask); } @@ -3280,7 +3300,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, ((mdwc->hs_phy->flags & (PHY_HSFS_MODE | PHY_LS_MODE)) && !dwc3_msm_is_superspeed(mdwc))); can_suspend_ssphy = dwc->maximum_speed >= USB_SPEED_SUPER && - (!mdwc->use_pwr_event_for_wakeup || no_active_ss || + (!(mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) || no_active_ss || !enable_wakeup); /* Suspend SS PHY */ if (can_suspend_ssphy) { @@ -3306,10 +3326,21 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, usb_phy_set_suspend(mdwc->ss_phy, 1); usb_phy_set_suspend(mdwc->ss_phy1, 1); mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; - } else if (mdwc->use_pwr_event_for_wakeup) { - dwc3_msm_set_ss_pwr_events(mdwc, true); + } else if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) { + mdwc->lpm_flags |= MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP; } + /* + * When operating in HS host mode, check if pwr event IRQ is + * required for wakeup. + */ + if (mdwc->in_host_mode && (mdwc->use_pwr_event_for_wakeup + & PWR_EVENT_HS_WAKEUP)) + mdwc->lpm_flags |= MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP; + + if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP) + dwc3_msm_set_pwr_events(mdwc, true); + /* make sure above writes are completed before turning off clocks */ wmb(); @@ -3361,11 +3392,13 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, /* * with the core in power collapse, we dont require wakeup * using HS_PHY_IRQ or SS_PHY_IRQ. Hence enable wakeup only in - * case of host bus suspend and device bus suspend. + * case of host bus suspend and device bus suspend. Also in + * case of platforms with mpm interrupts and snps phy, enable + * dpse hsphy irq and dmse hsphy irq as done for pdc interrupts. */ if (!(mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) && enable_wakeup) { - if (mdwc->use_pdc_interrupts) { - enable_usb_pdc_interrupt(mdwc, true); + if (mdwc->use_pdc_interrupts || !mdwc->wakeup_irq[HS_PHY_IRQ].irq) { + configure_usb_wakeup_interrupts(mdwc, true); } else { uirq = &mdwc->wakeup_irq[HS_PHY_IRQ]; configure_nonpdc_usb_interrupt(mdwc, uirq, true); @@ -3375,8 +3408,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, mdwc->lpm_flags |= MDWC3_ASYNC_IRQ_WAKE_CAPABILITY; } - if (mdwc->use_pwr_event_for_wakeup && - !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) + if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP) enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); dev_info(mdwc->dev, "DWC3 in low power mode\n"); @@ -3471,10 +3503,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) * Disable any wakeup events that were enabled if pwr_event_irq * is used as wakeup interrupt. */ - if (mdwc->use_pwr_event_for_wakeup && - !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) { + if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP) { disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); - dwc3_msm_set_ss_pwr_events(mdwc, false); + dwc3_msm_set_pwr_events(mdwc, false); + mdwc->lpm_flags &= ~MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP; } /* Resume SS PHY */ @@ -3545,8 +3577,8 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Disable wakeup capable for HS_PHY IRQ & SS_PHY_IRQ if enabled */ if (mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY) { - if (mdwc->use_pdc_interrupts) { - enable_usb_pdc_interrupt(mdwc, false); + if (mdwc->use_pdc_interrupts || !mdwc->wakeup_irq[HS_PHY_IRQ].irq) { + configure_usb_wakeup_interrupts(mdwc, false); } else { uirq = &mdwc->wakeup_irq[HS_PHY_IRQ]; configure_nonpdc_usb_interrupt(mdwc, uirq, false); @@ -3794,6 +3826,13 @@ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc) irq_clear |= PWR_EVNT_LPM_OUT_L1_MASK; } + /* Handle exit from L2 events */ + if (irq_stat & PWR_EVNT_LPM_OUT_L2_MASK) { + dev_dbg(mdwc->dev, "%s: handling PWR_EVNT_LPM_OUT_L2_MASK\n", + __func__); + irq_stat &= ~PWR_EVNT_LPM_OUT_L2_MASK; + irq_clear |= PWR_EVNT_LPM_OUT_L2_MASK; + } /* Unhandled events */ if (irq_stat) dev_dbg(mdwc->dev, "%s: unexpected PWR_EVNT, irq_stat=%X\n", @@ -4898,8 +4937,17 @@ static int dwc3_msm_probe(struct platform_device *pdev) * On platforms with SS PHY that do not support ss_phy_irq for wakeup * events, use pwr_event_irq for wakeup events in superspeed mode. */ - mdwc->use_pwr_event_for_wakeup = dwc->maximum_speed >= USB_SPEED_SUPER - && !mdwc->wakeup_irq[SS_PHY_IRQ].irq; + if (dwc->maximum_speed >= USB_SPEED_SUPER + && !mdwc->wakeup_irq[SS_PHY_IRQ].irq) + mdwc->use_pwr_event_for_wakeup |= PWR_EVENT_SS_WAKEUP; + + /* + * On platforms with mpm interrupts and snps phy, when operating in + * HS host mode use power event irq for wakeup events as GIC is not + * capable to detect falling edge of dp/dm hsphy irq. + */ + if (!mdwc->use_pdc_interrupts && !mdwc->wakeup_irq[HS_PHY_IRQ].irq) + mdwc->use_pwr_event_for_wakeup |= PWR_EVENT_HS_WAKEUP; /* * Clocks and regulators will not be turned on until the first time From 7c784bfe485d86f7770aed6ce098503370917900 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Fri, 25 Jun 2021 11:17:07 +0530 Subject: [PATCH 37/37] Revert "block: Enable BFQ io scheduler as default" 'commit abc0fc15dcec ("block: Enable BFQ io scheduler as default")' This is to fix the Native Daemon and Zygote Preload regressions during bootup. Change-Id: I4cfb40d0622319ce84d17fa409a4fcb5ab429dbc Signed-off-by: Pradeep P V K --- block/elevator.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index 9340e2388c62..076ba7308e65 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -630,10 +630,7 @@ static struct elevator_type *elevator_get_default(struct request_queue *q) { if (q->nr_hw_queues != 1) return NULL; -#if defined(CONFIG_SDC_QTI) || defined(CONFIG_SCSI_UFSHCD_QTI) - if (IS_ENABLED(CONFIG_IOSCHED_BFQ)) - return elevator_get(q, "bfq", false); -#endif + return elevator_get(q, "mq-deadline", false); }