From a13ebeb960e4f80a2f322bfecf4ac7a97cba9a69 Mon Sep 17 00:00:00 2001 From: Sai Chaitanya Kaveti Date: Wed, 28 Sep 2022 20:59:38 +0530 Subject: [PATCH 01/36] msm: ep_pcie: Sending PME for device initiated D3cold exit According to the PCIe specification, PME message is to be sent for device initiated D3cold to D0 transition. To support this sending PME immediately after link training while transitioning from D3cold to D0. As retention flops are not available for sdxlemur, sticky bits in the registers are not retained during low power state. PME enable bit is being cleared because of this. To handle this added a flag to check the status of pme_en after D3 event and set pme_en during link training if the flag is set. Change-Id: I474a675a35566c2ff051374c9d212c47d08d622d Signed-off-by: Sai Chaitanya Kaveti --- drivers/platform/msm/ep_pcie/ep_pcie_com.h | 5 ++ drivers/platform/msm/ep_pcie/ep_pcie_core.c | 83 +++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index 00f5e42ebb24..40202988c989 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -94,6 +94,8 @@ #define PCIE20_SUBSYSTEM 0x2c #define PCIE20_CAP_ID_NXT_PTR 0x40 #define PCIE20_CON_STATUS 0x44 +#define PCIE20_MASK_PME_EN BIT(8) +#define PCIE20_MASK_PME_STATUS BIT(15) #define PCIE20_MSI_CAP_ID_NEXT_CTRL 0x50 #define PCIE20_MSI_LOWER 0x54 #define PCIE20_MSI_UPPER 0x58 @@ -360,6 +362,7 @@ struct ep_pcie_dev_t { bool mhi_soc_reset_en; bool aoss_rst_clear; bool avoid_reboot_in_d3hot; + bool pme_in_wake_from_d3cold; u32 dbi_base_reg; u32 slv_space_reg; u32 phy_status_reg; @@ -411,6 +414,8 @@ struct ep_pcie_dev_t { int perst_irq; atomic_t host_wake_pending; bool conf_ipa_msi_iatu; + bool wake_from_d3cold; + bool pme_en_d3; struct ep_pcie_register_event *event_reg; struct work_struct handle_bme_work; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index 671063b7dd63..2c45fc9d7ab3 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "ep_pcie_com.h" #include @@ -46,6 +47,9 @@ #define ICC_AVG_BW 500 #define ICC_PEAK_BW 800 #define PERST_RAW_RESET_STATUS BIT(11) +#define PCIE_PME_COUNT 2 +#define PCIE_PME_SLEEP_DELAY_US 10000 +#define PCIE_PME_RESEND_DELAY_US 100000 /* debug mask sys interface */ static int ep_pcie_debug_mask; @@ -120,6 +124,7 @@ static const struct ep_pcie_irq_info_t ep_pcie_irq_info[EP_PCIE_MAX_IRQ] = { }; static int ep_pcie_core_wakeup_host_internal(enum ep_pcie_event event); +static void ep_pcie_core_issue_inband_pme(void); int ep_pcie_get_debug_mask(void) { @@ -790,6 +795,17 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev, bool configured) ep_pcie_write_mask(dev->dm_core + PCIE20_CAP_ID_NXT_PTR, 0, BIT(31)|BIT(30)|BIT(27)); + if (dev->pme_in_wake_from_d3cold && dev->pme_en_d3) { + /* + * PME_ENABLE is cleared after d3cold state if + * retention flops are not present in the target. + * Set PME_ENABLE, if it is seen as set during + * d3hot to send PME message + */ + ep_pcie_write_mask(dev->dm_core + PCIE20_CON_STATUS, 0, PCIE20_MASK_PME_EN); + dev->pme_en_d3 = false; + } + /* Set the Endpoint L0s Acceptable Latency to 1us (max) */ ep_pcie_write_reg_field(dev->dm_core, PCIE20_DEVICE_CAPABILITIES, @@ -1675,6 +1691,46 @@ static void ep_pcie_core_toggle_wake_gpio(bool is_on) } +static void ep_pcie_core_issue_pme_for_wake_from_d3cold(void) +{ + struct ep_pcie_dev_t *dev = &ep_pcie_dev; + u32 pme_count = 0, pme_reg; + bool pme_en, pme_status; + + pme_reg = readl_relaxed(dev->dm_core + PCIE20_CON_STATUS); + pme_en = pme_reg & PCIE20_MASK_PME_EN; + pme_status = pme_reg & PCIE20_MASK_PME_STATUS; + + EP_PCIE_INFO(dev, "PCIe V%d: pme_reg: 0x%x, pme_en: %d, pme_status: %d\n", + dev->rev, pme_reg, pme_en, pme_status); + + if (pme_en) { + do { + /* Sending PME for device initiated d3_cold exit */ + ep_pcie_core_issue_inband_pme(); + /*Polling for pme_status to be 0 for 100ms*/ + readx_poll_timeout(readl_relaxed, dev->dm_core + PCIE20_CON_STATUS, pme_reg, + !(pme_reg & PCIE20_MASK_PME_STATUS), PCIE_PME_SLEEP_DELAY_US, + PCIE_PME_RESEND_DELAY_US); + + pme_status = pme_reg & PCIE20_MASK_PME_STATUS; + EP_PCIE_DBG(dev, "PCIe V%d: pme_status:%d\n", dev->rev, pme_status); + + pme_count++; + + if (!pme_status) + break; + + } while (pme_count < PCIE_PME_COUNT); + + if (pme_status && pme_count == PCIE_PME_COUNT) { + EP_PCIE_INFO(dev, + "PCIe V%d: Host failed to acknowledge PME for device-initiated wake\n", + dev->rev); + } + } +} + int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) { int ret = 0; @@ -1951,6 +2007,16 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) dev->rev); } + if (dev->pme_in_wake_from_d3cold && dev->wake_from_d3cold) { + /* + * Sending PME after link training for device + * initiated D3cold to D0 transition, based on + * PCIe specification + */ + ep_pcie_core_issue_pme_for_wake_from_d3cold(); + dev->wake_from_d3cold = false; + } + checkbme: /* Clear AOSS_CC_RESET_STATUS::PERST_RAW_RESET_STATUS when linking up */ if (dev->aoss_rst_clear) @@ -2277,6 +2343,9 @@ static irqreturn_t ep_pcie_handle_dstate_change_irq(int irq, void *data) dev->rev, dev->d3_counter); ep_pcie_write_mask(dev->parf + PCIE20_PARF_PM_CTRL, 0, BIT(1)); + dev->pme_en_d3 = readl_relaxed(dev->dm_core + + PCIE20_CON_STATUS) & PCIE20_MASK_PME_EN; + if (dev->enumerated) ep_pcie_notify_event(dev, EP_PCIE_EVENT_PM_D3_HOT); else @@ -3147,6 +3216,13 @@ static int ep_pcie_core_wakeup_host_internal(enum ep_pcie_event event) if (!atomic_read(&dev->perst_deast)) { /*D3 cold handling*/ ep_pcie_core_toggle_wake_gpio(true); + if (dev->pme_in_wake_from_d3cold) { + /* + * Set below flag for device initiated + * d3cold wake to send PME message + */ + dev->wake_from_d3cold = true; + } } else if (dev->l23_ready) { EP_PCIE_ERR(dev, "PCIe V%d: request to assert WAKE# when in D3hot\n", @@ -3423,6 +3499,13 @@ static int ep_pcie_probe(struct platform_device *pdev) "PCIe V%d: PME during reboot/panic (in D3hot) is %s needed\n", ep_pcie_dev.rev, ep_pcie_dev.avoid_reboot_in_d3hot ? "" : "not"); + ep_pcie_dev.pme_in_wake_from_d3cold = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,pme-in-wake-from-d3cold"); + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: PME is%s sent during wake from d3cold\n", + ep_pcie_dev.rev, ep_pcie_dev.pme_in_wake_from_d3cold ? "" : " not"); + ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,mhi-soc-reset-offset", &ep_pcie_dev.mhi_soc_reset_offset); From 1461e3662292a9258e785c69fac14063359f00af Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 10 Jun 2022 16:12:27 +0100 Subject: [PATCH 02/36] arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer commit c50f11c6196f45c92ca48b16a5071615d4ae0572 upstream. Invalidating the buffer memory in arch_sync_dma_for_device() for FROM_DEVICE transfers When using the streaming DMA API to map a buffer prior to inbound non-coherent DMA (i.e. DMA_FROM_DEVICE), we invalidate any dirty CPU cachelines so that they will not be written back during the transfer and corrupt the buffer contents written by the DMA. This, however, poses two potential problems: (1) If the DMA transfer does not write to every byte in the buffer, then the unwritten bytes will contain stale data once the transfer has completed. (2) If the buffer has a virtual alias in userspace, then stale data may be visible via this alias during the period between performing the cache invalidation and the DMA writes landing in memory. Address both of these issues by cleaning (aka writing-back) the dirty lines in arch_sync_dma_for_device(DMA_FROM_DEVICE) instead of discarding them using invalidation. Change-Id: Ibfda7d1f68d11d76c7b603f083d8ee773a37cc22 Cc: Ard Biesheuvel Cc: Christoph Hellwig Cc: Robin Murphy Cc: Russell King Cc: Link: https://lore.kernel.org/r/20220606152150.GA31568@willie-the-truck Signed-off-by: Will Deacon Reviewed-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20220610151228.4562-2-will@kernel.org Signed-off-by: Catalin Marinas Signed-off-by: Greg Kroah-Hartman Git-commit: 7b9c3bfbad2510478ac29221d2c40a09184ce6a1 Git-repo: https://android.googlesource.com/kernel/common/ Signed-off-by: Srinivasarao Pathipati --- arch/arm64/mm/cache.S | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index 0ee30f93b546..a3ac18c2ec24 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -301,8 +301,6 @@ ENDPIPROC(__dma_flush_area) * - dir - DMA direction */ ENTRY(__dma_map_area) - cmp w2, #DMA_FROM_DEVICE - b.eq __dma_inv_area b __dma_clean_area ENDPIPROC(__dma_map_area) From 484e438642203290e344eb7a62bebae678cc9823 Mon Sep 17 00:00:00 2001 From: Charan Teja Kalla Date: Wed, 30 Nov 2022 16:32:58 +0530 Subject: [PATCH 03/36] ANDROID: arm64: mm: perform clean & invalidation in __dma_map_area commit c50f11c6196f ("arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer") break assumptions of some device drivers about invalidation that happens as part of __dma_map_area(DMA_FROM_DEVICE). An example include drivers using dmabuf API dma_buf_begin_cpu_access() and dma_buf_end_cpu_access() to achieve buffer invalidation. Fix this breakage by replacing clean with clean and invalidation in __dma_map_area() for DMA inbound case. Bug: 260978220 Change-Id: Id1a2750c2036de693cd52e8f7316f1d820b5a262 Fixes: c50f11c6196f ("arm64: mm: Don't invalidate FROM_DEVICE buffers at start of DMA transfer") Signed-off-by: Charan Teja Kalla Signed-off-by: Shiraz Hashim Signed-off-by: Prakash Gupta Signed-off-by: Pavankumar Kondeti Git-commit: cbbd7242818690f7d67825e96500c398c86f5044 Git-repo: https://android.googlesource.com/kernel/common/ Signed-off-by: Srinivasarao Pathipati --- arch/arm64/mm/cache.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index a3ac18c2ec24..26ffb0686a98 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -301,6 +301,8 @@ ENDPIPROC(__dma_flush_area) * - dir - DMA direction */ ENTRY(__dma_map_area) + cmp w2, #DMA_FROM_DEVICE + b.eq __dma_flush_area b __dma_clean_area ENDPIPROC(__dma_map_area) From 9dcfdde71f4455775739295d79cdfaa8d796dcf7 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Thu, 1 Dec 2022 18:52:09 +0530 Subject: [PATCH 04/36] memshare: Free QMI handle only if its valid Avoid possible use-after-free access for a QMI handle during driver deinit by ensuring the free happens only for valid QMI handle and is marked NULL post free. Change-Id: I4314dff560de2fc3aea30d636f935d7a02067a57 Signed-off-by: Manoj Prabhu B --- drivers/soc/qcom/memshare/msm_memshare.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/soc/qcom/memshare/msm_memshare.c b/drivers/soc/qcom/memshare/msm_memshare.c index db8c87aba568..6d1badcf1afd 100644 --- a/drivers/soc/qcom/memshare/msm_memshare.c +++ b/drivers/soc/qcom/memshare/msm_memshare.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -779,6 +780,7 @@ static void memshare_init_worker(struct work_struct *work) dev_err(memsh_drv->dev, "memshare: Creating mem_share_svc qmi handle failed\n"); kfree(mem_share_svc_handle); + mem_share_svc_handle = NULL; destroy_workqueue(mem_share_svc_workqueue); return; } @@ -787,8 +789,11 @@ static void memshare_init_worker(struct work_struct *work) if (rc < 0) { dev_err(memsh_drv->dev, "memshare: Registering mem share svc failed %d\n", rc); - qmi_handle_release(mem_share_svc_handle); - kfree(mem_share_svc_handle); + if (mem_share_svc_handle) { + qmi_handle_release(mem_share_svc_handle); + kfree(mem_share_svc_handle); + mem_share_svc_handle = NULL; + } destroy_workqueue(mem_share_svc_workqueue); return; } @@ -971,8 +976,11 @@ static int memshare_remove(struct platform_device *pdev) return 0; flush_workqueue(mem_share_svc_workqueue); - qmi_handle_release(mem_share_svc_handle); - kfree(mem_share_svc_handle); + if (mem_share_svc_handle) { + qmi_handle_release(mem_share_svc_handle); + kfree(mem_share_svc_handle); + mem_share_svc_handle = NULL; + } destroy_workqueue(mem_share_svc_workqueue); return 0; } From a18edb25fe022dd853d7fccc71563339f9dc48e7 Mon Sep 17 00:00:00 2001 From: Srinivasarao Pathipati Date: Thu, 15 Dec 2022 15:43:40 +0530 Subject: [PATCH 05/36] Reverts below USB and netfilter patches bcbaf12 UPSTREAM: usb: dwc3: Try usb-role-switch first in dwc3_drd_init 4ccf7af usb: dwc3: gadget: Avoid duplicate requests to enable Run/Stop a5bdea5 usb: dwc3: gadget: Don't modify GEVNTCOUNT in pullup() 67bf926 usb: dwc3: gadget: Refactor pullup() 24e4f63 usb: dwc3: gadget: Prevent repeat pullup() 62b6cbc usb: dwc3: Issue core soft reset before enabling run/stop e24f90d usb: dwc3: gadget: Avoid starting DWC3 gadget during UDC unbind d288c63 usb: dwc3: disable USB core PHY management 36f7b71 netfilter: nf_conntrack_irc: Fix forged IP logic d0a24bc netfilter: nf_conntrack_irc: Tighten matching on DCC message. Change-Id: Ic2e52fe1a18c7643d001f408a0442b99d1cf3d6b Signed-off-by: Srinivasarao Pathipati --- drivers/usb/dwc3/core.c | 2 +- drivers/usb/dwc3/core.h | 4 -- drivers/usb/dwc3/drd.c | 11 +++-- drivers/usb/dwc3/gadget.c | 85 +++++++++++++++----------------- drivers/usb/dwc3/host.c | 10 ---- net/netfilter/nf_conntrack_irc.c | 39 +++------------ 6 files changed, 55 insertions(+), 96 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 4307a87625ab..3d4ce9c3aa64 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -227,7 +227,7 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure */ -int dwc3_core_soft_reset(struct dwc3 *dwc) +static int dwc3_core_soft_reset(struct dwc3 *dwc) { u32 reg; int retries = 1000; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7e5fd66343a3..e5b6a1acfd39 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -998,7 +998,6 @@ struct dwc3_scratchpad_array { * @tx_max_burst_prd: max periodic ESS transmit burst size * @hsphy_interface: "utmi" or "ulpi" * @connected: true when we're connected to a host, false otherwise - * @softconnect: true when gadget connect is called, false when disconnect runs * @delayed_status: true when gadget driver asks for delayed status * @ep0_bounced: true when we used bounce buffer * @ep0_expect_in: true when we expect a DATA IN transfer @@ -1203,7 +1202,6 @@ struct dwc3 { const char *hsphy_interface; unsigned connected:1; - unsigned softconnect:1; unsigned delayed_status:1; unsigned ep0_bounced:1; unsigned ep0_expect_in:1; @@ -1428,8 +1426,6 @@ bool dwc3_has_imod(struct dwc3 *dwc); int dwc3_event_buffers_setup(struct dwc3 *dwc); void dwc3_event_buffers_cleanup(struct dwc3 *dwc); -int dwc3_core_soft_reset(struct dwc3 *dwc); - #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) int dwc3_host_init(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc); diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 0260850c784c..db68d48c2267 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -566,15 +566,16 @@ int dwc3_drd_init(struct dwc3 *dwc) { int ret, irq; - if (ROLE_SWITCH && - device_property_read_bool(dwc->dev, "usb-role-switch")) - return dwc3_setup_role_switch(dwc); - dwc->edev = dwc3_get_extcon(dwc); if (IS_ERR(dwc->edev)) return PTR_ERR(dwc->edev); - if (dwc->edev) { + if (ROLE_SWITCH && + device_property_read_bool(dwc->dev, "usb-role-switch")) { + ret = dwc3_setup_role_switch(dwc); + if (ret < 0) + return ret; + } else if (dwc->edev) { dwc->edev_nb.notifier_call = dwc3_drd_notifier; ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, &dwc->edev_nb); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a40935f3592b..80fee7ea83ca 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2008,42 +2008,14 @@ static void dwc3_gadget_disable_irq(struct dwc3 *dwc); static void __dwc3_gadget_stop(struct dwc3 *dwc); static int __dwc3_gadget_start(struct dwc3 *dwc); -static int dwc3_gadget_soft_disconnect(struct dwc3 *dwc) -{ - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - dwc->connected = false; - - /* - * In the Synopsys DesignWare Cores USB3 Databook Rev. 3.30a - * Section 4.1.8 Table 4-7, it states that for a device-initiated - * disconnect, the SW needs to ensure that it sends "a DEPENDXFER - * command for any active transfers" before clearing the RunStop - * bit. - */ - dwc3_stop_active_transfers(dwc); - __dwc3_gadget_stop(dwc); - spin_unlock_irqrestore(&dwc->lock, flags); - - /* - * Note: if the GEVNTCOUNT indicates events in the event buffer, the - * driver needs to acknowledge them before the controller can halt. - * Simply let the interrupt handler acknowledges and handle the - * remaining event generated by the controller while polling for - * DSTS.DEVCTLHLT. - */ - return dwc3_gadget_run_stop(dwc, false, false); -} - static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) { struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; int ret; is_on = !!is_on; - dwc->softconnect = is_on; /* * Per databook, when we want to stop the gadget, if a control transfer * is still in process, complete it and get the core into setup phase. @@ -2079,27 +2051,50 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) return 0; } - if (dwc->pullups_connected == is_on) { - pm_runtime_put(dwc->dev); - return 0; - } + /* + * Synchronize and disable any further event handling while controller + * is being enabled/disabled. + */ + disable_irq(dwc->irq_gadget); + + spin_lock_irqsave(&dwc->lock, flags); if (!is_on) { - ret = dwc3_gadget_soft_disconnect(dwc); - } else { - /* - * In the Synopsys DWC_usb31 1.90a programming guide section - * 4.1.9, it specifies that for a reconnect after a - * device-initiated disconnect requires a core soft reset - * (DCTL.CSftRst) before enabling the run/stop bit. - */ - dwc3_core_soft_reset(dwc); + u32 count; - dwc3_event_buffers_setup(dwc); + dwc->connected = false; + /* + * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a + * Section 4.1.8 Table 4-7, it states that for a device-initiated + * disconnect, the SW needs to ensure that it sends "a DEPENDXFER + * command for any active transfers" before clearing the RunStop + * bit. + */ + dwc3_stop_active_transfers(dwc); + __dwc3_gadget_stop(dwc); + + /* + * In the Synopsis DesignWare Cores USB3 Databook Rev. 3.30a + * Section 1.3.4, it mentions that for the DEVCTRLHLT bit, the + * "software needs to acknowledge the events that are generated + * (by writing to GEVNTCOUNTn) while it is waiting for this bit + * to be set to '1'." + */ + count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); + count &= DWC3_GEVNTCOUNT_MASK; + if (count > 0) { + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count); + dwc->ev_buf->lpos = (dwc->ev_buf->lpos + count) % + dwc->ev_buf->length; + } + } else { __dwc3_gadget_start(dwc); - ret = dwc3_gadget_run_stop(dwc, true, false); } + ret = dwc3_gadget_run_stop(dwc, is_on, false); + spin_unlock_irqrestore(&dwc->lock, flags); + enable_irq(dwc->irq_gadget); + pm_runtime_put(dwc->dev); return ret; @@ -3796,7 +3791,7 @@ int dwc3_gadget_resume(struct dwc3 *dwc) { int ret; - if (!dwc->gadget_driver || !dwc->softconnect) + if (!dwc->gadget_driver) return 0; ret = __dwc3_gadget_start(dwc); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index a4eacc5cf58a..38bcb079ffc7 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -9,13 +9,8 @@ #include -#include "../host/xhci-plat.h" #include "core.h" -static const struct xhci_plat_priv dwc3_xhci_plat_priv = { - .quirks = XHCI_SKIP_PHY_INIT, -}; - static int dwc3_host_get_irq(struct dwc3 *dwc) { struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); @@ -90,11 +85,6 @@ int dwc3_host_init(struct dwc3 *dwc) goto err; } - ret = platform_device_add_data(xhci, &dwc3_xhci_plat_priv, - sizeof(dwc3_xhci_plat_priv)); - if (ret) - goto err; - memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); if (dwc->usb3_lpm_capable) diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index 65b5b05fe38d..e40988a2f22f 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -148,37 +148,15 @@ static int help(struct sk_buff *skb, unsigned int protoff, data = ib_ptr; data_limit = ib_ptr + skb->len - dataoff; - /* Skip any whitespace */ - while (data < data_limit - 10) { - if (*data == ' ' || *data == '\r' || *data == '\n') - data++; - else - break; - } - - /* strlen("PRIVMSG x ")=10 */ - if (data < data_limit - 10) { - if (strncasecmp("PRIVMSG ", data, 8)) - goto out; - data += 8; - } - - /* strlen(" :\1DCC SENT t AAAAAAAA P\1\n")=26 - * 7+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=26 - */ - while (data < data_limit - (21 + MINMATCHLEN)) { - /* Find first " :", the start of message */ - if (memcmp(data, " :", 2)) { + /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 + * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ + while (data < data_limit - (19 + MINMATCHLEN)) { + if (memcmp(data, "\1DCC ", 5)) { data++; continue; } - data += 2; - - /* then check that place only for the DCC command */ - if (memcmp(data, "\1DCC ", 5)) - goto out; data += 5; - /* we have at least (21+MINMATCHLEN)-(2+5) bytes valid data left */ + /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ iph = ip_hdr(skb); pr_debug("DCC found in master %pI4:%u %pI4:%u\n", @@ -194,7 +172,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, pr_debug("DCC %s detected\n", dccprotos[i]); /* we have at least - * (21+MINMATCHLEN)-7-dccprotos[i].matchlen bytes valid + * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid * data left (== 14/13 bytes) */ if (parse_dcc(data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { @@ -207,9 +185,8 @@ static int help(struct sk_buff *skb, unsigned int protoff, /* dcc_ip can be the internal OR external (NAT'ed) IP */ tuple = &ct->tuplehash[dir].tuple; - if ((tuple->src.u3.ip != dcc_ip && - ct->tuplehash[!dir].tuple.dst.u3.ip != dcc_ip) || - dcc_port == 0) { + if (tuple->src.u3.ip != dcc_ip && + tuple->dst.u3.ip != dcc_ip) { net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", &tuple->src.u3.ip, &dcc_ip, dcc_port); From 533e2889b8943e7ac35ddf9cfe199247c753780b Mon Sep 17 00:00:00 2001 From: Alan Chen Date: Tue, 20 Dec 2022 11:30:47 -0800 Subject: [PATCH 06/36] cnss2: Add data length validation in cnss_wlfw_qdss_data_send_sync() Add a data length validation check in fw response message in qdss_data_send_sync(). Change-Id: I197b8d52c06e35f5fcf0f8fee94429fdcf500fcb CRs-Fixed: 3359589 Signed-off-by: Alan Chen --- drivers/net/wireless/cnss2/qmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 157c90506d30..7fdda4a58eff 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -930,7 +930,8 @@ int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_n resp->total_size == total_size) && (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) && (resp->data_valid == 1 && - resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01)) { + resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) && + resp->data_len <= remaining) { memcpy(p_qdss_trace_data_temp, resp->data, resp->data_len); } else { From a845583f32e81c1bcffbd8e5d0dd1a26cb026a43 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Tue, 20 Dec 2022 17:25:30 +0530 Subject: [PATCH 07/36] cnss2: Validate maximum number of memory segments For WIN use case maximum number of memory segments requested by FW is increased to 52 in QMI layer. Since CNSS2 driver uses same QMI header files and message structures the same maximum number of segment is applicable for CNSS2. It means for memory allocation, FW can request 52 memory segments to CNSS2 via QMI indication but local CNSS2 variable which get segment info from indication supports maximum 32 segments. To fix it, change CNSS2 array variable size to same as number of maximum segment supported in QMI layer. Change-Id: I661b55b53cb31327da12f064d0a516884159eb5b Signed-off-by: Naman Padhiar --- drivers/net/wireless/cnss2/main.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 97115c84b1a8..7775eaa5a5e3 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -31,7 +31,6 @@ #define MAX_NO_OF_MAC_ADDR 4 #define QMI_WLFW_MAX_TIMESTAMP_LEN 32 -#define QMI_WLFW_MAX_NUM_MEM_SEG 32 #define QMI_WLFW_MAX_BUILD_ID_LEN 128 #define CNSS_RDDM_TIMEOUT_MS 20000 #define RECOVERY_TIMEOUT 60000 @@ -456,10 +455,10 @@ struct cnss_plat_data { char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN + 1]; u32 otp_version; u32 fw_mem_seg_len; - struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG]; + struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; struct cnss_fw_mem m3_mem; u32 qdss_mem_seg_len; - struct cnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG]; + struct cnss_fw_mem qdss_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; u32 *qdss_reg; struct cnss_pin_connect_result pin_result; struct dentry *root_dentry; From 06cfd223bfb0998cab2b2e62c13a4189a2f44e21 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 15 Dec 2022 12:22:27 +0530 Subject: [PATCH 08/36] iio: qcom-spmi-adc5: remove the remove callback Remove the driver remove callback as there is no significant cleanup action done in it for the ADC driver. Change-Id: I2a11ac4d15cc94e652c7b238da4cc47f28dbf8a3 Signed-off-by: Jishnu Prakash --- drivers/iio/adc/qcom-spmi-adc5.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index 7c0dd5e3fffe..d4c1e58c0d21 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1454,21 +1455,12 @@ static int adc5_probe(struct platform_device *pdev) return devm_iio_device_register(dev, indio_dev); } -static int adc5_exit(struct platform_device *pdev) -{ - struct adc5_chip *adc = platform_get_drvdata(pdev); - - mutex_destroy(&adc->lock); - return 0; -} - static struct platform_driver adc5_driver = { .driver = { .name = "qcom-spmi-adc5", .of_match_table = adc5_match_table, }, .probe = adc5_probe, - .remove = adc5_exit, }; module_platform_driver(adc5_driver); From ccce7f7c52f7374772626a9994fa6444cbc67bcd Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 29 Nov 2022 02:52:46 +0530 Subject: [PATCH 09/36] cpu-topology: Change the size of allocation for cpu's raw_capacity Allocating raw_capacity nodes as per max possible cpus gives issues when there are cores in between which are not available. Allocate as many elements for holding raw_capacity as is last set bit position in possible mask. Change-Id: I90055f96c320b15960efac10d8d92c69413eeb6b Signed-off-by: Avaneesh Kumar Dwivedi --- drivers/base/arch_topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 81169261a549..05c765c6d087 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -167,7 +167,7 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) &cpu_capacity); if (!ret) { if (!raw_capacity) { - raw_capacity = kcalloc(num_possible_cpus(), + raw_capacity = kcalloc(cpumask_last(cpu_possible_mask), sizeof(*raw_capacity), GFP_KERNEL); if (!raw_capacity) { From 3ebdc2df40b94d3e27c86ffd708245faf5667ffa Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 29 Nov 2022 02:47:08 +0530 Subject: [PATCH 10/36] devfreq: memlat: Change number of array elements for holding core_stats Memlat driver allocates as many array elements in core_stats array as many possible cpus While when any of core is not available in between we need to consider what is first and last cpu in possible mask, accordingly initialize the core_stats array. Change-Id: I26420d2b061b712f94c3e496cff12811ea4a678a Signed-off-by: Avaneesh Kumar Dwivedi --- drivers/devfreq/arm-memlat-mon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index 37ebff621d17..4fc8f76918e4 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -907,7 +907,7 @@ static int memlat_mon_probe(struct platform_device *pdev, bool is_compute) } } - num_cpus = cpumask_weight(&mon->cpus); + num_cpus = (cpumask_last(&mon->cpus) - cpumask_first(&mon->cpus)) + 1; hw = &mon->hw; hw->of_node = of_parse_phandle(dev->of_node, "qcom,target-dev", 0); From 9c72c5a227e57e3791069f464ae6161dc7d66d41 Mon Sep 17 00:00:00 2001 From: Alan Chen Date: Wed, 21 Dec 2022 17:52:30 -0800 Subject: [PATCH 11/36] icnss2: Add data length validation in cnss_wlfw_qdss_data_send_sync() Add a data length validation check in fw response message in qdss_data_send_sync(). Change-Id: I750f46549bc914698baaf4e24f1710536ca8e356 CRs-Fixed: 3366343 Signed-off-by: Alan Chen --- drivers/soc/qcom/icnss2/qmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/icnss2/qmi.c b/drivers/soc/qcom/icnss2/qmi.c index 26bbacaa6621..5290daccb276 100644 --- a/drivers/soc/qcom/icnss2/qmi.c +++ b/drivers/soc/qcom/icnss2/qmi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "icnss2_qmi: " fmt @@ -1198,7 +1199,8 @@ int icnss_wlfw_qdss_data_send_sync(struct icnss_priv *priv, char *file_name, resp->total_size == total_size) && (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) && (resp->data_valid == 1 && - resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01)) { + resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) && + resp->data_len <= remaining) { memcpy(p_qdss_trace_data_temp, resp->data, resp->data_len); } else { From a97331a732b668bddc332edccffe7e678c503191 Mon Sep 17 00:00:00 2001 From: Sarannya S Date: Wed, 28 Dec 2022 17:33:28 +0530 Subject: [PATCH 12/36] net: qrtr: haven: Add bounds check in rx path Validate the values read from shared memory in the receive path. In the case where a VM is misbehaving, the qrtr haven transport should return immediately and print a warning. Change-Id: Ieccd3f99ec0cf321f136600760e7f66e125f765a Signed-off-by: Sarannya S --- net/qrtr/haven.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/qrtr/haven.c b/net/qrtr/haven.c index b37e779c7e7f..c66564c0f00b 100644 --- a/net/qrtr/haven.c +++ b/net/qrtr/haven.c @@ -148,6 +148,9 @@ static void haven_rx_peak(struct haven_pipe *pipe, void *data, if (tail >= pipe->length) tail -= pipe->length; + if (WARN_ON_ONCE(tail > pipe->length)) + return; + len = min_t(size_t, count, pipe->length - tail); if (len) memcpy_fromio(data, pipe->fifo + tail, len); From ab6f0337d4ef22717d6e1f094b480a3e6038c133 Mon Sep 17 00:00:00 2001 From: Kishore Kumar Ravi Date: Mon, 2 Jan 2023 12:40:38 +0530 Subject: [PATCH 13/36] rpmsg: glink: Remove dev_set_name to avoid KASAN issue KASAN repots use after free issue for dev_set_name call. Remove dev_set_name to override KASAN issue. Change-Id: If59ef4671dbd71692f36ee605c14bea4602f41e5 Signed-off-by: Kishore Kumar Ravi --- drivers/rpmsg/qcom_glink_slatecom.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_slatecom.c b/drivers/rpmsg/qcom_glink_slatecom.c index 7d912ac3e7fb..e2a4f49042cf 100644 --- a/drivers/rpmsg/qcom_glink_slatecom.c +++ b/drivers/rpmsg/qcom_glink_slatecom.c @@ -2225,7 +2225,6 @@ static int glink_slatecom_probe(struct platform_device *pdev) dev = glink->dev; dev->of_node = pdev->dev.of_node; dev->release = glink_slatecom_release; - dev_set_name(dev, "%s", dev->of_node->name); dev_set_drvdata(dev, glink); ret = of_property_read_string(dev->of_node, "label", &glink->name); From 3434256d68ecdaf50cf6ac442649a9175ac0159b Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Mon, 26 Dec 2022 01:34:20 -0800 Subject: [PATCH 14/36] msm: ipa: Add DSCP PCP mapping info ioctl Adding DSCP PCP mapping ioctl support for easymesh R3. Change-Id: I7a7fcc3fdc22cdf1970638e8163bda7ef74dc7b3 Signed-off-by: Michael Adisumarta --- include/uapi/linux/msm_ipa.h | 51 ++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 594cc65c2d0c..9b6786c29b21 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -150,6 +150,7 @@ #define IPA_IOCTL_DEL_MACSEC_MAPPING 93 #define IPA_IOCTL_QUERY_CACHED_DRIVER_MSG 94 #define IPA_IOCTL_SET_EXT_ROUTER_MODE 95 +#define IPA_IOCTL_ADD_DEL_DSCP_PCP_MAPPING 96 /** * max size of the header to be inserted */ @@ -215,6 +216,11 @@ #define IPA_MAX_IPPT_NUM_PORT_FLT 5 +/** + * Max number of DSCP entries in uc + */ +#define IPA_UC_MAX_DSCP_VAL 64 + /** * New feature flag for CV2X config. */ @@ -1522,6 +1528,7 @@ enum ipa_hdr_l2_type { * IPA_HDR_PROC_SET_DSCP: * IPA_HDR_PROC_EoGRE_HEADER_ADD: Add IPV[46] and GRE header * IPA_HDR_PROC_EoGRE_HEADER_REMOVE: Remove IPV[46] and GRE header + * IPA_HDR_PROC_WWAN_TO_ETHII_EX: To update PCP value for E2E traffic. */ enum ipa_hdr_proc_type { IPA_HDR_PROC_NONE, @@ -1537,8 +1544,9 @@ enum ipa_hdr_proc_type { IPA_HDR_PROC_SET_DSCP, IPA_HDR_PROC_EoGRE_HEADER_ADD, IPA_HDR_PROC_EoGRE_HEADER_REMOVE, + IPA_HDR_PROC_WWAN_TO_ETHII_EX, }; -#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_EoGRE_HEADER_REMOVE + 1) +#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_WWAN_TO_ETHII_EX + 1) /** * struct ipa_rt_rule - attributes of a routing rule @@ -1863,12 +1871,34 @@ struct ipa_eogre_hdr_proc_ctx_params { * (in bytes) from the start of the input IP hdr * @output_ethhdr_negative_offset: Specifies where the ethernet hdr offset is * (in bytes) from the end of the template hdr + * @output_dscp_pcp_update: Specifies if VLAN PCP needs to be updated based on + * DSCP<->PCP mapping table. * @reserved: for future use */ struct ipa_eth_II_to_eth_II_ex_procparams { uint32_t input_ethhdr_negative_offset : 8; uint32_t output_ethhdr_negative_offset : 8; - uint32_t reserved : 16; + uint32_t output_dscp_pcp_update : 1; + uint32_t reserved : 15; +}; + +/** + * struct ipa_wwan_to_eth_II_ex_procparams - + * @input_ethhdr_negative_offset: Specifies where the ethernet hdr offset is + * (in bytes) from the start of the input IP hdr + * @output_ethhdr_negative_offset: Specifies where the ethernet hdr offset is + * (in bytes) from the end of the template hdr + * @output_dscp_pcp_update: Specifies if VLAN PCP needs to be updated based on + * DSCP<->PCP mapping table. + * @input_ethhdr_valid: Specifies whether input ethernet header is valid or not. + * @reserved: for future use + */ +struct ipa_wwan_to_eth_II_ex_procparams { + uint32_t input_ethhdr_negative_offset : 8; + uint32_t output_ethhdr_negative_offset : 8; + uint32_t output_dscp_pcp_update : 1; + uint32_t input_ethhdr_valid : 1; + uint32_t reserved : 14; }; #define L2TP_USER_SPACE_SPECIFY_DST_PIPE @@ -1881,6 +1911,7 @@ struct ipa_eth_II_to_eth_II_ex_procparams { * @l2tp_params: l2tp parameters * @eogre_params: eogre parameters * @generic_params: generic proc_ctx params + * @generic_params_v2: generic proc_ctx params for bridging * @proc_ctx_hdl: out parameter, handle to proc_ctx, valid when status is 0 * @status: out parameter, status of header add operation, * 0 for success, @@ -1894,6 +1925,7 @@ struct ipa_hdr_proc_ctx_add { struct ipa_l2tp_hdr_proc_ctx_params l2tp_params; struct ipa_eogre_hdr_proc_ctx_params eogre_params; struct ipa_eth_II_to_eth_II_ex_procparams generic_params; + struct ipa_wwan_to_eth_II_ex_procparams generic_params_v2; }; #define IPA_L2TP_HDR_PROC_SUPPORT @@ -3654,6 +3686,18 @@ struct ipa_ioc_ext_router_info { uint32_t idu_client_prefix[IPA_PREFIX_MAPPING_MAX][4]; }; +/** + * struct ipa_ioc_dscp_pcp_map_info - provide dscp pcp mapping info to add/delete + * @add: Boolean to indicate add or delete the mapping + * @dscp_pcp_map: DSCP <6 bits> and PCP <3 bits>. + * Only 3 bits are valid(0-7) for PCP. + * DSCP is used as index (0-63). + */ +struct ipa_ioc_dscp_pcp_map_info { + uint32_t add; + uint8_t dscp_pcp_map[IPA_UC_MAX_DSCP_VAL]; +}; + /** * actual IOCTLs supported by IPA driver */ @@ -3975,6 +4019,9 @@ struct ipa_ioc_ext_router_info { IPA_IOCTL_SET_EXT_ROUTER_MODE, \ struct ipa_ioc_ext_router_info) +#define IPA_IOC_ADD_DEL_DSCP_PCP_MAPPING _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ADD_DEL_DSCP_PCP_MAPPING, \ + struct ipa_ioc_dscp_pcp_map_info) /* * unique magic number of the Tethering bridge ioctls From cf0602ada58b1834ac430bef478657880c0a12b1 Mon Sep 17 00:00:00 2001 From: Sarannya S Date: Wed, 28 Dec 2022 17:28:53 +0530 Subject: [PATCH 15/36] net: qrtr: haven: Add bounds check on tx path Add bounds check on values read from shared memory in the tx path. In cases where the VM is misbehaving, the qrtr haven transport should exit and print a warning when bogus values may cause out of bounds to be read. Change-Id: Ic1177ced6f41de66459970eff4537d82de4f614e Signed-off-by: Sarannya S --- net/qrtr/haven.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/qrtr/haven.c b/net/qrtr/haven.c index b37e779c7e7f..02719209782f 100644 --- a/net/qrtr/haven.c +++ b/net/qrtr/haven.c @@ -188,6 +188,9 @@ static size_t haven_tx_avail(struct haven_pipe *pipe) else avail -= FIFO_FULL_RESERVE; + if (WARN_ON_ONCE(avail > pipe->length)) + avail = 0; + return avail; } @@ -198,6 +201,8 @@ static void haven_tx_write(struct haven_pipe *pipe, u32 head; head = le32_to_cpu(*pipe->head); + if (WARN_ON_ONCE(head > pipe->length)) + return; len = min_t(size_t, count, pipe->length - head); if (len) From 230e96df6a659249584e8cc0f203b4c58bf3d219 Mon Sep 17 00:00:00 2001 From: Naman Padhiar Date: Thu, 24 Nov 2022 14:58:44 +0800 Subject: [PATCH 16/36] cnss2: Unregister host driver during PCI remove CNSS2 registers as both platform and PCI driver. PCI device can be removed via sysfs exposed by kernel during PCI device creation. When PCI device gets removed, CNSS PCI remove ops gets called. In cnss_pci_remove, unregister host driver and shutdown WLAN chip to cleanly remove PCI device. Change-Id: Ia60e8b69bda2b3bdd5990cb83f47c082d6667283 Signed-off-by: Naman Padhiar Signed-off-by: Yu Ouyang --- drivers/net/wireless/cnss2/pci.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 1428c2493d56..0ef5a462e437 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -3039,8 +3039,12 @@ int cnss_pci_register_driver_hdlr(struct cnss_pci_data *pci_priv, int cnss_pci_unregister_driver_hdlr(struct cnss_pci_data *pci_priv) { - struct cnss_plat_data *plat_priv = pci_priv->plat_priv; + struct cnss_plat_data *plat_priv; + if (!pci_priv) + return -EINVAL; + + plat_priv = pci_priv->plat_priv; set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); cnss_pci_dev_shutdown(pci_priv); pci_priv->driver_ops = NULL; @@ -5739,7 +5743,9 @@ static void cnss_pci_unregister_mhi(struct cnss_pci_data *pci_priv) mhi_unregister_mhi_controller(mhi_ctrl); cnss_pci_mhi_ipc_logging_deinit(pci_priv); kfree(mhi_ctrl->irq); + mhi_ctrl->irq = NULL; mhi_free_controller(mhi_ctrl); + pci_priv->mhi_ctrl = NULL; } static void cnss_pci_config_regs(struct cnss_pci_data *pci_priv) @@ -6118,6 +6124,7 @@ static void cnss_pci_remove(struct pci_dev *pci_dev) struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(&pci_dev->dev); + cnss_pci_unregister_driver_hdlr(pci_priv); cnss_pci_free_m3_mem(pci_priv); cnss_pci_free_fw_mem(pci_priv); cnss_pci_free_qdss_mem(pci_priv); From b4c9cf2eeddb70934c5d61b81ba8c2861bcccc38 Mon Sep 17 00:00:00 2001 From: Jyothi Kumar Seerapu Date: Thu, 29 Dec 2022 20:30:46 +0530 Subject: [PATCH 17/36] mhi: core: Add the basic sanity to check the irq registration As part of MHI Power On sequence, registering the mhi irq through request_threaded_irq function. In case of failure in mhi irq registration, we simply return without printing the error message. So, added the error message with printing mhi irq number and return value in failure case of irq registration. Change-Id: I5d2e1bc6d66abc8b42ca60fbc53b7664d3468db0 Signed-off-by: Jyothi Kumar Seerapu --- drivers/bus/mhi/core/mhi_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/mhi_init.c b/drivers/bus/mhi/core/mhi_init.c index 60ae6c51143c..00f1f44b6a7d 100644 --- a/drivers/bus/mhi/core/mhi_init.c +++ b/drivers/bus/mhi/core/mhi_init.c @@ -435,8 +435,11 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl) mhi_intvec_threaded_handlr, IRQF_ONESHOT | IRQF_NO_SUSPEND, "mhi", mhi_cntrl); - if (ret) + if (ret) { + MHI_CNTRL_ERR("Error in requesting threaded irq:%d, ret=%d\n", + mhi_cntrl->irq[0], ret); return ret; + } for (i = 0; i < mhi_cntrl->total_ev_rings; i++, mhi_event++) { if (!mhi_event->request_irq) From 523d6aec82afe08f1bb7744c458709c0b7cf68d9 Mon Sep 17 00:00:00 2001 From: Alan Chen Date: Wed, 21 Dec 2022 17:52:30 -0800 Subject: [PATCH 18/36] icnss2: Add data length validation in cnss_wlfw_qdss_data_send_sync() Add a data length validation check in fw response message in qdss_data_send_sync(). Change-Id: I750f46549bc914698baaf4e24f1710536ca8e356 CRs-Fixed: 3366343 Signed-off-by: Alan Chen --- drivers/soc/qcom/icnss2/qmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/icnss2/qmi.c b/drivers/soc/qcom/icnss2/qmi.c index 26bbacaa6621..5290daccb276 100644 --- a/drivers/soc/qcom/icnss2/qmi.c +++ b/drivers/soc/qcom/icnss2/qmi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #define pr_fmt(fmt) "icnss2_qmi: " fmt @@ -1198,7 +1199,8 @@ int icnss_wlfw_qdss_data_send_sync(struct icnss_priv *priv, char *file_name, resp->total_size == total_size) && (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) && (resp->data_valid == 1 && - resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01)) { + resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) && + resp->data_len <= remaining) { memcpy(p_qdss_trace_data_temp, resp->data, resp->data_len); } else { From 0905a386188fe3c2d400983fcefe321ff90ae3fe Mon Sep 17 00:00:00 2001 From: Alan Chen Date: Tue, 20 Dec 2022 11:30:47 -0800 Subject: [PATCH 19/36] cnss2: Add data length validation in cnss_wlfw_qdss_data_send_sync() Add a data length validation check in fw response message in qdss_data_send_sync(). Change-Id: I197b8d52c06e35f5fcf0f8fee94429fdcf500fcb CRs-Fixed: 3359589 Signed-off-by: Alan Chen --- drivers/net/wireless/cnss2/qmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 157c90506d30..7fdda4a58eff 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -930,7 +930,8 @@ int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_n resp->total_size == total_size) && (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) && (resp->data_valid == 1 && - resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01)) { + resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) && + resp->data_len <= remaining) { memcpy(p_qdss_trace_data_temp, resp->data, resp->data_len); } else { From ae5cef9b7e0b7edfb6e3b163b7eb0fa35a99efaa Mon Sep 17 00:00:00 2001 From: Krupali Dhanvijay Date: Mon, 16 Jan 2023 20:39:50 +0530 Subject: [PATCH 20/36] cnss2: Add API to send WFC mode to WLAN FW Add and export API to host driver to send WFC(WiFi Calling) mode to WLAN FW. Change-Id: I92d3d0baad9afc6fdf66f66b847a4e8a90a54341 CRs-Fixed: 3346550 Signed-off-by: Krupali Dhanvijay --- drivers/net/wireless/cnss2/main.c | 21 ++++++++++ drivers/net/wireless/cnss2/qmi.c | 68 ++++++++++++++++++++++++++++++- drivers/net/wireless/cnss2/qmi.h | 8 ++++ include/net/cnss2.h | 10 +++++ 4 files changed, 106 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 10c25a806f05..f10b55aa7d28 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -3134,6 +3134,27 @@ cnss_is_converged_dt(struct cnss_plat_data *plat_priv) return of_property_read_bool(plat_priv->plat_dev->dev.of_node, "qcom,converged-dt"); } + +int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + int ret = 0; + + if (!plat_priv) + return -ENODEV; + + /* If IMS server is connected, return success without QMI send */ + if (test_bit(CNSS_IMS_CONNECTED, &plat_priv->driver_state)) { + cnss_pr_dbg("Ignore host request as IMS server is connected"); + return ret; + } + + ret = cnss_wlfw_send_host_wfc_call_status(plat_priv, cfg); + + return ret; +} +EXPORT_SYMBOL(cnss_set_wfc_mode); + static int cnss_probe(struct platform_device *plat_dev) { int ret = 0; diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 7fdda4a58eff..6fa987c08c12 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -1957,6 +1957,72 @@ out: return ret; } +int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv, + struct cnss_wfc_cfg cfg) +{ + struct wlfw_wfc_call_status_req_msg_v01 *req; + struct wlfw_wfc_call_status_resp_msg_v01 *resp; + struct qmi_txn txn; + int ret = 0; + + if (!test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { + cnss_pr_err("Drop host WFC indication as FW not initialized\n"); + return -EINVAL; + } + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) { + kfree(req); + return -ENOMEM; + } + + req->wfc_call_active_valid = 1; + req->wfc_call_active = cfg.mode; + cnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n", + plat_priv->driver_state); + ret = qmi_txn_init(&plat_priv->qmi_wlfw, &txn, + wlfw_wfc_call_status_resp_msg_v01_ei, resp); + if (ret < 0) { + cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n", + ret); + goto out; + } + + cnss_pr_dbg("Send WFC Mode: %d\n", cfg.mode); + ret = qmi_send_request(&plat_priv->qmi_wlfw, NULL, &txn, + QMI_WLFW_WFC_CALL_STATUS_REQ_V01, + WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN, + wlfw_wfc_call_status_req_msg_v01_ei, req); + if (ret < 0) { + qmi_txn_cancel(&txn); + cnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n", + ret); + goto out; + } + + ret = qmi_txn_wait(&txn, QMI_WLFW_TIMEOUT_JF); + if (ret < 0) { + cnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n", + ret); + goto out; + } + + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { + cnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n", + resp->resp.result, resp->resp.error); + ret = -EINVAL; + goto out; + } + ret = 0; +out: + kfree(req); + kfree(resp); + return ret; +} + static int cnss_wlfw_wfc_call_status_send_sync (struct cnss_plat_data *plat_priv, const struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg) diff --git a/drivers/net/wireless/cnss2/qmi.h b/drivers/net/wireless/cnss2/qmi.h index 53368ac6303e..88ff44d0e7c4 100644 --- a/drivers/net/wireless/cnss2/qmi.h +++ b/drivers/net/wireless/cnss2/qmi.h @@ -82,6 +82,8 @@ int cnss_wlfw_qdss_data_send_sync(struct cnss_plat_data *plat_priv, char *file_n u32 total_size); int wlfw_qdss_trace_send_start(struct cnss_plat_data *plat_priv); int wlfw_qdss_trace_send_stop(struct cnss_plat_data *plat_priv, unsigned long long option); +int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv, + struct cnss_wfc_cfg cfg); #else #define QMI_WLFW_TIMEOUT_MS 10000 @@ -285,6 +287,12 @@ int wlfw_qdss_trace_send_stop(struct cnss_plat_data *plat_priv, unsigned long lo { return 0; } + +int cnss_wlfw_send_host_wfc_call_status(struct cnss_plat_data *plat_priv, + struct cnss_wfc_cfg cfg) +{ + return 0; +} #endif /* CONFIG_CNSS2_QMI */ #ifdef CONFIG_CNSS2_DEBUG diff --git a/include/net/cnss2.h b/include/net/cnss2.h index dbb0ea5978fb..92a78971710b 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -92,6 +92,15 @@ enum cnss_bus_event_type { BUS_EVENT_INVALID = 0xFFFF, }; +enum cnss_wfc_mode { + CNSS_WFC_MODE_OFF, + CNSS_WFC_MODE_ON, +}; + +struct cnss_wfc_cfg { + enum cnss_wfc_mode mode; +}; + struct cnss_hang_event { void *hang_event_data; u16 hang_event_data_len; @@ -281,4 +290,5 @@ extern int cnss_get_mem_segment_info(enum cnss_remote_mem_type type, extern int cnss_send_buffer_to_afcmem(struct device *dev, char *afcdb, uint32_t len, uint8_t slotid); extern int cnss_reset_afcmem(struct device *dev, uint8_t slotid); +extern int cnss_set_wfc_mode(struct device *dev, struct cnss_wfc_cfg cfg); #endif /* _NET_CNSS2_H */ From b4bb607067bcfe6ed7168825f6642d165bc687cf Mon Sep 17 00:00:00 2001 From: Mohana Basava Tejesh Reddy Mareddy Date: Thu, 12 Jan 2023 14:09:54 -0800 Subject: [PATCH 21/36] msm: ep_pcie: Add support for MSI disable Adding support for MSI disable feature in the implementation Change-Id: I3da0cbf06eec6686f7f2730f196214c539d0a5a1 Signed-off-by: Mohana Basava Tejesh Reddy Mareddy --- drivers/platform/msm/ep_pcie/ep_pcie_core.c | 40 ++++++++------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index 2c45fc9d7ab3..d20bc0b18239 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -3021,7 +3021,7 @@ int ep_pcie_core_config_outbound_iatu(struct ep_pcie_iatu entries[], int ep_pcie_core_get_msi_config(struct ep_pcie_msi_config *cfg) { - u32 cap, lower, upper, data, ctrl_reg; + u32 cap, lower, upper, data; static u32 changes; if (ep_pcie_dev.link_status == EP_PCIE_LINK_DISABLED) { @@ -3035,24 +3035,15 @@ int ep_pcie_core_get_msi_config(struct ep_pcie_msi_config *cfg) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: MSI CAP:0x%x\n", ep_pcie_dev.rev, cap); - if (!(cap & BIT(16))) { - EP_PCIE_ERR(&ep_pcie_dev, - "PCIe V%d: MSI is not enabled yet\n", - ep_pcie_dev.rev); - return EP_PCIE_ERROR; - } + if (cap & BIT(16)) { + lower = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_LOWER); + upper = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_UPPER); + data = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_DATA); - lower = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_LOWER); - upper = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_UPPER); - data = readl_relaxed(ep_pcie_dev.dm_core + PCIE20_MSI_DATA); - ctrl_reg = readl_relaxed(ep_pcie_dev.dm_core + - PCIE20_MSI_CAP_ID_NEXT_CTRL); + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: MSI info: lower:0x%x; upper:0x%x; data:0x%x\n", + ep_pcie_dev.rev, lower, upper, data); - EP_PCIE_DBG(&ep_pcie_dev, - "PCIe V%d: MSI info: lower:0x%x; upper:0x%x; data:0x%x\n", - ep_pcie_dev.rev, lower, upper, data); - - if (ctrl_reg & BIT(16)) { struct resource *msi = ep_pcie_dev.res[EP_PCIE_RES_MSI].resource; if (ep_pcie_dev.active_config) @@ -3115,10 +3106,10 @@ int ep_pcie_core_get_msi_config(struct ep_pcie_msi_config *cfg) return 0; } - EP_PCIE_ERR(&ep_pcie_dev, - "PCIe V%d: Wrong MSI info found when MSI is enabled: lower:0x%x; data:0x%x\n", - ep_pcie_dev.rev, lower, data); - return EP_PCIE_ERROR; + EP_PCIE_INFO(&ep_pcie_dev, + "PCIe V%d: MSI is not enabled yet or not supported\n", + ep_pcie_dev.rev); + return -EOPNOTSUPP; } int ep_pcie_core_trigger_msi(u32 idx) @@ -3185,10 +3176,9 @@ int ep_pcie_core_trigger_msi(u32 idx) return 0; } - EP_PCIE_ERR(&ep_pcie_dev, - "PCIe V%d: MSI is not enabled yet. MSI addr:0x%x; data:0x%x; index from client:%d\n", - ep_pcie_dev.rev, addr, data, idx); - return EP_PCIE_ERROR; + EP_PCIE_INFO(&ep_pcie_dev, "MSI is disabled or not supported\n", + ep_pcie_dev.rev); + return -EOPNOTSUPP; } static void ep_pcie_core_issue_inband_pme(void) From a5e6953336fdd86d7e50d3d97a0214bfc8683946 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 24 Nov 2022 14:27:37 +0530 Subject: [PATCH 22/36] mfd: qcom-spmi-pmic: Add remove API Add remove API for unloading spmi-pmic module, as the SPMI framework right now requires drivers under it to have a remove API defined when removing them. Change-Id: Iaf5b9f602fb9389c75a68702eaceb847abcf2876 Signed-off-by: Jishnu Prakash --- drivers/mfd/qcom-spmi-pmic.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index 11b711ca62b4..906a18ac6517 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2014-2015, 2017-2019, The Linux Foundation. * All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -146,8 +147,11 @@ static int pmic_spmi_probe(struct spmi_device *sdev) MODULE_DEVICE_TABLE(of, pmic_spmi_id_table); +static void pmic_spmi_remove(struct spmi_device *sdev) {} + static struct spmi_driver pmic_spmi_driver = { .probe = pmic_spmi_probe, + .remove = pmic_spmi_remove, .driver = { .name = "pmic-spmi", .of_match_table = pmic_spmi_id_table, From d8d32ae605bfa72c4a7f3ebd91f67285e0d9d490 Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Tue, 10 Jan 2023 16:23:31 +0530 Subject: [PATCH 23/36] msm: mhi-net-dev: Don't over-write skb length Once the read operation is done, mhi-net driver adds the read data to the buffer by invoking skb_put() which takes care of updating the length of skb. In the existing logic, mhi-net driver is updating skb length thus skb length is getting incremented twice causing extra (unwanted) data then read to the client. Fixing the same by removing the redundant length update logic. Also move skb_put() ahead of eth_type_trans() as skb length is being used in eth_type_trans(). Change-Id: I11c420a68f2ad69e8a58f29c620917382ff172f7 Signed-off-by: Veerabhadrarao Badiganti Signed-off-by: Sai Chaitanya Kaveti --- drivers/platform/msm/mhi_dev/mhi_dev_net.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index d05bbe5f1f4f..d7f187a9df7e 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -238,14 +238,13 @@ static void mhi_dev_net_read_completion_cb(void *req) struct sk_buff *skb = mreq->context; unsigned long flags; - skb->len = mreq->transfer_len; + skb_put(skb, mreq->transfer_len); if (net_handle->eth_iface) skb->protocol = eth_type_trans(skb, net_handle->dev); else skb->protocol = mhi_dev_net_eth_type_trans(skb); - skb_put(skb, mreq->transfer_len); net_handle->dev->stats.rx_packets++; skb->dev = net_handle->dev; netif_rx(skb); From 3ed6f3203b2a18b009db6ce8645cdd617d7a964d Mon Sep 17 00:00:00 2001 From: Veerabhadrarao Badiganti Date: Fri, 6 Jan 2023 22:43:05 +0530 Subject: [PATCH 24/36] msm: mhi-net-dev: Set MIN and MAX MTU size for Ethernet packet Set MIN and MAX MTU for ethernet packets, so the user can configure MTU size. The default MTU size for the ethernet packet is 1500 bytes. With this change, the user/client can update the max MTU size up to 8192 (MHI_NET_DEFAULT_MTU) bytes. Change-Id: I7da6d11599bde1a6d3a9ac9b238a4ee57a7bbbba Signed-off-by: Veerabhadrarao Badiganti Signed-off-by: Sai Chaitanya Kaveti --- drivers/platform/msm/mhi_dev/mhi_dev_net.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/msm/mhi_dev/mhi_dev_net.c b/drivers/platform/msm/mhi_dev/mhi_dev_net.c index d7f187a9df7e..940e601973ad 100644 --- a/drivers/platform/msm/mhi_dev/mhi_dev_net.c +++ b/drivers/platform/msm/mhi_dev/mhi_dev_net.c @@ -449,6 +449,8 @@ static void mhi_dev_net_ether_setup(struct net_device *dev) { dev->netdev_ops = &mhi_dev_net_ops_ip; ether_setup(dev); + dev->min_mtu = ETH_MIN_MTU; + dev->max_mtu = ETH_MAX_MTU; mhi_dev_net_log(MHI_INFO, "mhi_dev_net Ethernet setup\n"); } From bf7fb6ca053183d3dfe795c32aba9824f8d662da Mon Sep 17 00:00:00 2001 From: Vinayaka B M Date: Wed, 18 Jan 2023 23:01:03 +0530 Subject: [PATCH 25/36] msm: ipa: Rmnet CV2X header file changes Modify code to support additional rmnet_cv2x teth interface. Original 2779101. Change-Id: I5cd9b07036c5c4d1e1df9e6d996b358057c58635 Signed-off-by: Vinayaka B M --- include/linux/ipa_usb.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/ipa_usb.h b/include/linux/ipa_usb.h index 3fad1a392896..3cbce0445513 100644 --- a/include/linux/ipa_usb.h +++ b/include/linux/ipa_usb.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _IPA_USB_H_ @@ -159,6 +160,7 @@ struct ipa_usb_xdci_chan_params { u64 data_buff_base_addr_iova; struct sg_table *sgt_xfer_rings; struct sg_table *sgt_data_buff; + bool is_sw_path; }; /** From 5139e8a7dfa9c4e76bfc80d760b131b212a1464c Mon Sep 17 00:00:00 2001 From: Kaushal Hooda Date: Tue, 20 Jul 2021 17:31:18 +0530 Subject: [PATCH 26/36] net: qrtr: Prevent wakeups using service id based filter Filter data from adsp by using service id so that it will not have wake up capable packets. Service id can be read from DT file and wakeup could be avoided for corresponding packets. Change-Id: Ibbb5f74bb153cdd333f8037b498c366d4f2ac5f8 Signed-off-by: Sarannya S Signed-off-by: Kaushal Hooda --- net/qrtr/haven.c | 2 +- net/qrtr/mhi.c | 2 +- net/qrtr/mhi_dev.c | 2 +- net/qrtr/qrtr.c | 27 ++++++++++++++++++++++++--- net/qrtr/qrtr.h | 4 +++- net/qrtr/smd.c | 16 ++++++++++++++-- 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/net/qrtr/haven.c b/net/qrtr/haven.c index 1358bba65a27..ecd4bf48ee32 100644 --- a/net/qrtr/haven.c +++ b/net/qrtr/haven.c @@ -612,7 +612,7 @@ static int qrtr_haven_probe(struct platform_device *pdev) INIT_WORK(&qdev->work, qrtr_haven_retry_work); qdev->ep.xmit = qrtr_haven_send; - ret = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NET_ID_AUTO, false); + ret = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NET_ID_AUTO, false, NULL); if (ret) goto register_fail; diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index 519bd2186d85..c9377d28d890 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -176,7 +176,7 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, dev_set_drvdata(&mhi_dev->dev, qdev); - rc = qrtr_endpoint_register(&qdev->ep, net_id, rt); + rc = qrtr_endpoint_register(&qdev->ep, net_id, rt, NULL); if (rc) return rc; diff --git a/net/qrtr/mhi_dev.c b/net/qrtr/mhi_dev.c index f93600092745..5710c4454731 100644 --- a/net/qrtr/mhi_dev.c +++ b/net/qrtr/mhi_dev.c @@ -182,7 +182,7 @@ static void qrtr_mhi_dev_state_cb(struct mhi_dev_client_cb_data *cb_data) return; } - rc = qrtr_endpoint_register(&qep->ep, qep->net_id, qep->rt); + rc = qrtr_endpoint_register(&qep->ep, qep->net_id, qep->rt, NULL); if (rc) { dev_err(qep->dev, "register failed %d\n", rc); qrtr_mhi_dev_close_channels(qep); diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c index 79072ab6c44f..569e95262be1 100644 --- a/net/qrtr/qrtr.c +++ b/net/qrtr/qrtr.c @@ -142,6 +142,7 @@ static DEFINE_SPINLOCK(qrtr_port_lock); #define QRTR_BACKUP_HI_SIZE SZ_16K #define QRTR_BACKUP_LO_NUM 20 #define QRTR_BACKUP_LO_SIZE SZ_1K + static struct sk_buff_head qrtr_backup_lo; static struct sk_buff_head qrtr_backup_hi; static struct work_struct qrtr_backup_work; @@ -190,6 +191,8 @@ struct qrtr_node { struct wakeup_source *ws; void *ilc; + + u32 nonwake_svc[MAX_NON_WAKE_SVC_LEN]; }; struct qrtr_tx_flow_waiter { @@ -838,7 +841,9 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) size_t size; unsigned int ver; size_t hdrlen; - int errcode; + int errcode, i; + bool wake = true; + int svc_id; if (len == 0 || len & 3) return -EINVAL; @@ -938,9 +943,22 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) goto err; /* Force wakeup for all packets except for sensors */ - if (node->nid != 9) + if (node->nid != 9 && node->nid != 5) pm_wakeup_ws_event(node->ws, qrtr_wakeup_ms, true); + if (node->nid == 5) { + svc_id = qrtr_get_service_id(cb->src_node, cb->src_port); + if (svc_id > 0) { + for (i = 0; i < MAX_NON_WAKE_SVC_LEN; i++) { + if (svc_id == node->nonwake_svc[i]) { + wake = false; + break; + } + } + } + if (wake) + pm_wakeup_ws_event(node->ws, qrtr_wakeup_ms, true); + } qrtr_port_put(ipc); } @@ -1149,7 +1167,7 @@ static void qrtr_hello_work(struct kthread_work *work) * The specified endpoint must have the xmit function pointer set on call. */ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, - bool rt) + bool rt, u32 *svc_arr) { struct qrtr_node *node; struct sched_param param = {.sched_priority = 1}; @@ -1180,6 +1198,9 @@ int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, if (rt) sched_setscheduler(node->task, SCHED_FIFO, ¶m); + if (svc_arr) + memcpy(node->nonwake_svc, svc_arr, MAX_NON_WAKE_SVC_LEN * sizeof(int)); + mutex_init(&node->qrtr_tx_lock); INIT_RADIX_TREE(&node->qrtr_tx_flow, GFP_KERNEL); init_waitqueue_head(&node->resume_tx); diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h index 8784f5eecb34..449028c2ec93 100644 --- a/net/qrtr/qrtr.h +++ b/net/qrtr/qrtr.h @@ -12,6 +12,8 @@ struct sk_buff; #define QRTR_DEL_PROC_MAGIC 0xe111 +#define MAX_NON_WAKE_SVC_LEN 5 + /** * struct qrtr_endpoint - endpoint handle * @xmit: Callback for outgoing packets @@ -27,7 +29,7 @@ struct qrtr_endpoint { }; int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int net_id, - bool rt); + bool rt, u32 *svc_arr); void qrtr_endpoint_unregister(struct qrtr_endpoint *ep); diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c index 632717cc9996..45626f99dad6 100644 --- a/net/qrtr/smd.c +++ b/net/qrtr/smd.c @@ -64,7 +64,8 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev) struct qrtr_smd_dev *qdev; u32 net_id; bool rt; - int rc; + int rc, size; + u32 *svc_arr = NULL; pr_info("%s:Entered\n", __func__); qdev = devm_kzalloc(&rpdev->dev, sizeof(*qdev), GFP_KERNEL); @@ -81,7 +82,18 @@ static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev) rt = of_property_read_bool(rpdev->dev.of_node, "qcom,low-latency"); - rc = qrtr_endpoint_register(&qdev->ep, net_id, rt); + size = of_property_count_u32_elems(rpdev->dev.of_node, "qcom,non-wake-svc"); + + if (size > 0) { + if (size > MAX_NON_WAKE_SVC_LEN) + size = MAX_NON_WAKE_SVC_LEN; + svc_arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL); + + of_property_read_u32_array(rpdev->dev.of_node, "qcom,non-wake-svc", + svc_arr, size); + } + rc = qrtr_endpoint_register(&qdev->ep, net_id, rt, svc_arr); + if (rc) return rc; From bf9c71bd30a6bc2056100249e919b2b3a466ec0c Mon Sep 17 00:00:00 2001 From: Srinivasarao Pathipati Date: Thu, 26 Jan 2023 23:57:22 +0530 Subject: [PATCH 27/36] Revert "wait: Fix __wait_event_hrtimeout for RT/DL tasks" This reverts commit bd80dd86f9bfc6c86ac7dfda912b6706953c4b59. Change-Id: Ic4a1805e6dcdd0a0581acff9cc488676a69402a8 Signed-off-by: Srinivasarao Pathipati --- include/linux/wait.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/linux/wait.h b/include/linux/wait.h index 7d04c1b588c7..5903b1d17c92 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -529,11 +529,10 @@ do { \ \ hrtimer_init_sleeper_on_stack(&__t, CLOCK_MONOTONIC, \ HRTIMER_MODE_REL); \ - if ((timeout) != KTIME_MAX) { \ - hrtimer_set_expires_range_ns(&__t.timer, timeout, \ - current->timer_slack_ns); \ - hrtimer_sleeper_start_expires(&__t, HRTIMER_MODE_REL); \ - } \ + if ((timeout) != KTIME_MAX) \ + hrtimer_start_range_ns(&__t.timer, timeout, \ + current->timer_slack_ns, \ + HRTIMER_MODE_REL); \ \ __ret = ___wait_event(wq_head, condition, state, 0, 0, \ if (!__t.task) { \ From 70db347c246d9b59a450c44a074e79f3d47b6962 Mon Sep 17 00:00:00 2001 From: Sai Chaitanya Kaveti Date: Wed, 28 Dec 2022 12:17:12 +0530 Subject: [PATCH 28/36] msm: ep_pcie: Enable BME Deassert IRQ Enable BUS_MASTER_EN_DEASSERT IRQ as part of aggregated IRQ and Print error log when BME is deasserted to help in debugging. Use the device tree flag to distinguish if the device supports BME deassert IRQ or not and enable it only on supported devices. Change-Id: I810619b995255dab02eaabf05a6bc5c6e7639419 Signed-off-by: Sai Chaitanya Kaveti --- drivers/platform/msm/ep_pcie/ep_pcie_com.h | 5 +++ drivers/platform/msm/ep_pcie/ep_pcie_core.c | 45 ++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index 40202988c989..34b7a56b2217 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -43,6 +43,9 @@ #define PCIE20_PARF_INT_ALL_STATUS 0x224 #define PCIE20_PARF_INT_ALL_CLEAR 0x228 #define PCIE20_PARF_INT_ALL_MASK 0x22C +#define PCIE20_PARF_INT_ALL_2_STATUS 0x500 +#define PCIE20_PARF_INT_ALL_2_CLEAR 0x504 +#define PCIE20_PARF_INT_ALL_2_MASK 0x508 #define PCIE20_PARF_CLKREQ_OVERRIDE 0x2B0 #define PCIE20_PARF_CLKREQ_IN_OVERRIDE_STS BIT(5) @@ -175,6 +178,7 @@ #define MSI_EXIT_L1SS_WAIT_MAX_COUNT 100 #define XMLH_LINK_UP 0x400 #define PARF_XMLH_LINK_UP 0x40000000 +#define CFG_BUS_MASTER_EN_DEASSERT BIT(24) #define MAX_PROP_SIZE 32 #define MAX_MSG_LEN 80 @@ -363,6 +367,7 @@ struct ep_pcie_dev_t { bool aoss_rst_clear; bool avoid_reboot_in_d3hot; bool pme_in_wake_from_d3cold; + bool bme_deassert_irq; u32 dbi_base_reg; u32 slv_space_reg; u32 phy_status_reg; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index d20bc0b18239..7e81a80905b9 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -874,8 +874,16 @@ static void ep_pcie_core_init(struct ep_pcie_dev_t *dev, bool configured) ep_pcie_write_mask(dev->parf + PCIE20_PARF_INT_ALL_MASK, 0, BIT(EP_PCIE_INT_EVT_L1SUB_TIMEOUT)); + if (dev->bme_deassert_irq) { + ep_pcie_write_reg(dev->parf, PCIE20_PARF_INT_ALL_2_MASK, 0); + ep_pcie_write_mask(dev->parf + PCIE20_PARF_INT_ALL_2_MASK, 0, + CFG_BUS_MASTER_EN_DEASSERT); + EP_PCIE_INFO(dev, + "PCIe V%d: PCIE20_PARF_INT_ALL_2_MASK:0x%x\n", dev->rev, + readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_2_MASK)); + } - EP_PCIE_DBG(dev, "PCIe V%d: PCIE20_PARF_INT_ALL_MASK:0x%x\n", + EP_PCIE_INFO(dev, "PCIe V%d: PCIE20_PARF_INT_ALL_MASK:0x%x\n", dev->rev, readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_MASK)); } @@ -2606,6 +2614,30 @@ static irqreturn_t ep_pcie_handle_clkreq_irq(int irq, void *data) return IRQ_HANDLED; } +/** + * ep_pcie_handle_bme_deassert_irq - Check the second status register of PCIe's + * interrupts and print error log for BME deassert IRQ. + * @dev: PCIe endpoint device structure. + * @status2: Second status register of PCIe's interrupts. + */ +static void ep_pcie_handle_bme_deassert_irq(struct ep_pcie_dev_t *dev, u32 status2) +{ + bool bme; + u32 mask2 = readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_2_MASK); + + ep_pcie_write_mask(dev->parf + PCIE20_PARF_INT_ALL_2_CLEAR, 0, status2); + + EP_PCIE_DUMP(dev, + "PCIe V%d: Global IRQ received; status2:0x%x; mask2:0x%x\n", + dev->rev, status2, mask2); + + if (status2 & CFG_BUS_MASTER_EN_DEASSERT) { + bme = readl_relaxed(dev->dm_core + PCIE20_COMMAND_STATUS) & BIT(2); + EP_PCIE_ERR(dev, "PCIe V%d: BME deassert IRQ received, BME = %d\n", + dev->rev, bme); + } +} + static irqreturn_t ep_pcie_handle_global_irq(int irq, void *data) { struct ep_pcie_dev_t *dev = data; @@ -2675,6 +2707,12 @@ static irqreturn_t ep_pcie_handle_global_irq(int irq, void *data) } } + if (dev->bme_deassert_irq) { + status = readl_relaxed(dev->parf + PCIE20_PARF_INT_ALL_2_STATUS); + if (status) + ep_pcie_handle_bme_deassert_irq(dev, status); + } + return IRQ_HANDLED; } @@ -3496,6 +3534,11 @@ static int ep_pcie_probe(struct platform_device *pdev) "PCIe V%d: PME is%s sent during wake from d3cold\n", ep_pcie_dev.rev, ep_pcie_dev.pme_in_wake_from_d3cold ? "" : " not"); + ep_pcie_dev.bme_deassert_irq = of_property_read_bool((&pdev->dev)->of_node, + "qcom,pcie-bme-deassert-irq"); + EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: BME deassert irq is%s enabled\n", + ep_pcie_dev.rev, ep_pcie_dev.bme_deassert_irq ? "" : " not"); + ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,mhi-soc-reset-offset", &ep_pcie_dev.mhi_soc_reset_offset); From 56677b44e466b7204008e3fbc1ef13e273bbf70c Mon Sep 17 00:00:00 2001 From: Chaitanya Pratapa Date: Thu, 12 Jan 2023 15:05:46 -0800 Subject: [PATCH 29/36] msm: ipa: Add disable_msi flag In certain use cases, host doesn't expect MSI interrupts from device. Provide configuration support to disable MSI in case host doesn't support it. Change-Id: Ia629054024ad0090e5b7039dda99dbe4abe40745 Signed-off-by: Chaitanya Pratapa --- include/linux/ipa_mhi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/ipa_mhi.h b/include/linux/ipa_mhi.h index dbb1cace27f2..b21b2f8e5d86 100644 --- a/include/linux/ipa_mhi.h +++ b/include/linux/ipa_mhi.h @@ -62,6 +62,7 @@ struct ipa_mhi_msi_info { * @notify: client callback * @priv: client private data to be provided in client callback * @test_mode: flag to indicate if IPA MHI is in unit test mode + * @disable_msi: flag to indicate if MSI is disabled. */ struct ipa_mhi_init_params { struct ipa_mhi_msi_info msi; @@ -72,6 +73,7 @@ struct ipa_mhi_init_params { mhi_client_cb notify; void *priv; bool test_mode; + bool disable_msi; }; /** From 97ab5c1ac6744ad307bfb3d10aa63f2773846d24 Mon Sep 17 00:00:00 2001 From: Manisha Podhuturi Date: Tue, 29 Nov 2022 12:09:57 +0530 Subject: [PATCH 30/36] spi: spi-msm-geni: Handle IRQ enable and disable Handle irq enable and disable based on irq status flag, to avoid unbalanced irq errors. Enable irq only if irq status is disabled. Disable irq only if irq status is enabled. Change-Id: Ie01f89d10b0e2413bc8ba9a442ef99d358ce7f50 Signed-off-by: Manisha Podhuturi --- drivers/spi/spi-msm-geni.c | 44 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-msm-geni.c b/drivers/spi/spi-msm-geni.c index ecbe17055e56..200955a3a6db 100644 --- a/drivers/spi/spi-msm-geni.c +++ b/drivers/spi/spi-msm-geni.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -162,6 +163,7 @@ struct spi_geni_master { int num_tx_eot; int num_rx_eot; int num_xfers; + atomic_t is_irq_enable; void *ipc; bool gsi_mode; /* GSI Mode */ bool shared_ee; /* Dual EE use case */ @@ -181,6 +183,7 @@ struct spi_geni_master { }; static void spi_slv_setup(struct spi_geni_master *mas); +static void spi_geni_irq_enable(struct spi_geni_master *mas, bool irq_flag); static ssize_t spi_slave_state_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2087,6 +2090,8 @@ static int spi_geni_probe(struct platform_device *pdev) } } + atomic_set(&geni_mas->is_irq_enable, 0); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (ret) { ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); @@ -2230,12 +2235,12 @@ static int spi_geni_runtime_suspend(struct device *dev) struct spi_master *spi = get_spi_master(dev); struct spi_geni_master *geni_mas = spi_master_get_devdata(spi); - disable_irq(geni_mas->irq); if (geni_mas->is_le_vm) { spi_geni_unlock_bus(spi); return 0; } + spi_geni_irq_enable(geni_mas, false); GENI_SE_DBG(geni_mas->ipc, false, NULL, "%s:\n", __func__); /* Do not unconfigure the GPIOs for a shared_se usecase */ if (geni_mas->shared_ee && !geni_mas->shared_se) @@ -2295,7 +2300,7 @@ static int spi_geni_runtime_resume(struct device *dev) exit_rt_resume: ret = se_geni_resources_on(&geni_mas->spi_rsc); - enable_irq(geni_mas->irq); + spi_geni_irq_enable(geni_mas, true); return ret; } @@ -2342,6 +2347,41 @@ static int spi_geni_suspend(struct device *dev) } #endif +/** + * spi_geni_irq_enable() - Enable or Disable irq. + * @mas: Pointer to spi_geni_master structure. + * @irq_flag: irq flag which indicates irq enable + * or disable + * irq_flag - false - irq disable + * irq_flag - true - irq enable. + * + * This function is used to enable or disable irq. + * Based on irq_flag the enabling or disabling of + * irq will be done. Enable if irq_flag is true, + * disable if irq_flag is false. + * Return: None. + */ +static void spi_geni_irq_enable(struct spi_geni_master *mas, bool irq_flag) +{ + if (irq_flag) { + if (!(atomic_read(&mas->is_irq_enable))) { + enable_irq(mas->irq); + atomic_set(&mas->is_irq_enable, 1); + } else { + GENI_SE_DBG(mas->ipc, true, mas->dev, + "%s: irq already enabled\n", __func__); + } + } else { + if (atomic_read(&mas->is_irq_enable)) { + disable_irq(mas->irq); + atomic_set(&mas->is_irq_enable, 0); + } else { + GENI_SE_DBG(mas->ipc, true, mas->dev, + "%s: irq already disabled\n", __func__); + } + } +} + static const struct dev_pm_ops spi_geni_pm_ops = { SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend, spi_geni_runtime_resume, NULL) From ed328e7bfcf972776efa60e0f9252c8cf3646c9a Mon Sep 17 00:00:00 2001 From: Mohana Basava Tejesh Reddy Mareddy Date: Tue, 20 Dec 2022 20:43:32 -0800 Subject: [PATCH 31/36] msm: mhi_dev: Add support for MSI disable PCIe endpoint device informs PCIe root complex/host about completion or availability of new work using MSI. In some cases like UEFI, MSI functionality is not supported by used PCIe root complex/host, and can work in polling mode only. In MSI not supported case, endpoint is not allowed to raise MSI. This change queries MSI functionality support with root complex/host, and handle case where MSI functionality is not supported by polling MHI state, and not invoking MSIs towards host. Change-Id: Ie9c78f40fe7e9735d3e0104f845e29ac82d76778 Signed-off-by: Mohana Basava Tejesh Reddy Mareddy --- drivers/platform/msm/mhi_dev/mhi.c | 72 ++++++++++++++++++++++++--- drivers/platform/msm/mhi_dev/mhi.h | 1 + drivers/platform/msm/mhi_dev/mhi_sm.c | 2 +- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 1b6259bdcaba..d00c3e6b0ac9 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -281,7 +281,11 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq) int rc; rc = ep_pcie_get_msi_config(mhi->phandle, &cfg); - if (rc) { + if (rc == -EOPNOTSUPP) { + mhi_log(MHI_MSG_VERBOSE, "MSI is disabled\n"); + mhi_ctx->msi_disable = true; + return 0; + } else if (rc) { mhi_log(MHI_MSG_ERROR, "Error retrieving pcie msi logic\n"); return rc; } @@ -335,6 +339,24 @@ static void mhi_dev_event_rd_offset_completion_cb(void *req) if (ereq->event_rd_dma) dma_unmap_single(&mhi_ctx->pdev->dev, ereq->event_rd_dma, sizeof(uint64_t), DMA_TO_DEVICE); + + /* + * The mhi_dev_cmd_event_msi_cb and mhi_dev_event_msi_cb APIs does + * add back the flushed events space to the event buffer and returns + * the event req back to the list. These are registered in the API + * mhi_dev_schedule_msi_ipa and get invoked when MSI triggering is + * complete. + * In the case of MSI being disabled by the host, these callbacks will + * not get invoked as triggering MSI is suppressed from device side. + * Hence, invoking these callbacks as part of this API to ensure we do + * not run out on ereq buffer space in this scenario. + */ + if (mhi_ctx->msi_disable) { + if (ereq->is_cmd_cpl) + mhi_dev_cmd_event_msi_cb(ereq); + else + mhi_dev_event_msi_cb(ereq); + } } static void mhi_dev_cmd_event_msi_cb(void *req) @@ -415,7 +437,11 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx) if (!mhi_ctx->msi_lower) { rc = ep_pcie_get_msi_config(mhi_ctx->phandle, &cfg); - if (rc) { + if (rc == -EOPNOTSUPP) { + mhi_log(MHI_MSG_VERBOSE, "MSI is disabled\n"); + mhi_ctx->msi_disable = true; + return 0; + } else if (rc) { mhi_log(MHI_MSG_ERROR, "Error retrieving pcie msi logic\n"); return rc; @@ -1425,7 +1451,10 @@ static int mhi_hwc_init(struct mhi_dev *mhi) /* Call IPA HW_ACC Init with MSI Address and db routing info */ rc = ep_pcie_get_msi_config(mhi_ctx->phandle, &cfg); - if (rc) { + if (rc == -EOPNOTSUPP) { + mhi_log(MHI_MSG_VERBOSE, "MSI is disabled\n"); + mhi_ctx->msi_disable = true; + } else if (rc) { mhi_log(MHI_MSG_ERROR, "Error retrieving pcie msi logic\n"); return rc; @@ -1450,6 +1479,7 @@ static int mhi_hwc_init(struct mhi_dev *mhi) ipa_init_params.msi.mask = ((1 << cfg.msg_num) - 1); ipa_init_params.first_er_idx = erdb_cfg.base; ipa_init_params.first_ch_idx = HW_CHANNEL_BASE; + ipa_init_params.disable_msi = mhi_ctx->msi_disable; if (mhi_ctx->config_iatu) ipa_init_params.mmio_addr = @@ -1642,7 +1672,10 @@ int mhi_dev_send_event(struct mhi_dev *mhi, int evnt_ring, struct mhi_addr transfer_addr; rc = ep_pcie_get_msi_config(mhi->phandle, &cfg); - if (rc) { + if (rc == -EOPNOTSUPP) { + mhi_log(MHI_MSG_VERBOSE, "MSI is disabled\n"); + mhi_ctx->msi_disable = true; + } else if (rc) { mhi_log(MHI_MSG_ERROR, "Error retrieving pcie msi logic\n"); return rc; } @@ -3759,16 +3792,19 @@ static int mhi_dev_recover(struct mhi_dev *mhi) mhi_log(MHI_MSG_VERBOSE, "mhi_state = 0x%X, reset = %d\n", state, mhi_reset); + if (mhi_ctx->msi_disable) + goto poll_for_reset; + rc = mhi_dev_mmio_read(mhi, BHI_INTVEC, &bhi_intvec); if (rc) return rc; while (bhi_intvec == 0xffffffff && - bhi_max_cnt < MHI_BHI_INTVEC_MAX_CNT) { + bhi_max_cnt < MHI_BHI_INTVEC_MAX_CNT) { /* Wait for Host to set the bhi_intvec */ msleep(MHI_BHI_INTVEC_WAIT_MS); mhi_log(MHI_MSG_VERBOSE, - "Wait for Host to set BHI_INTVEC\n"); + "Wait for Host to set BHI_INTVEC\n"); rc = mhi_dev_mmio_read(mhi, BHI_INTVEC, &bhi_intvec); if (rc) { mhi_log(MHI_MSG_ERROR, @@ -3780,12 +3816,12 @@ static int mhi_dev_recover(struct mhi_dev *mhi) if (bhi_max_cnt == MHI_BHI_INTVEC_MAX_CNT) { mhi_log(MHI_MSG_ERROR, - "Host failed to set BHI_INTVEC\n"); + "Host failed to set BHI_INTVEC\n"); return -EINVAL; } if (bhi_intvec != 0xffffffff) { - /* Indicate the host that the device is ready */ + /* Indicate the host that device is ready */ rc = ep_pcie_trigger_msi(mhi->phandle, bhi_intvec); if (rc) { mhi_log(MHI_MSG_ERROR, "error sending msi\n"); @@ -3793,6 +3829,7 @@ static int mhi_dev_recover(struct mhi_dev *mhi) } } +poll_for_reset: /* Poll for the host to set the reset bit */ rc = mhi_dev_mmio_get_mhi_state(mhi, &state, &mhi_reset); if (rc) { @@ -4313,6 +4350,7 @@ static void mhi_dev_reinit(struct work_struct *work) static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx) { struct platform_device *pdev; + struct ep_pcie_msi_config cfg; int rc = 0; /* @@ -4360,6 +4398,24 @@ static int mhi_dev_resume_mmio_mhi_init(struct mhi_dev *mhi_ctx) return -EINVAL; } + /* + * Fetching MSI config to read the MSI capability and setting the + * msi_disable flag based on it. + */ + rc = ep_pcie_get_msi_config(mhi_ctx->phandle, &cfg); + if (rc == -EOPNOTSUPP) { + mhi_log(MHI_MSG_VERBOSE, "MSI is disabled\n"); + mhi_ctx->msi_disable = true; + } else if (!rc) { + mhi_ctx->msi_disable = false; + } else { + mhi_log(MHI_MSG_ERROR, + "Error retrieving pcie msi logic\n"); + return rc; + } + + mhi_log(MHI_MSG_VERBOSE, "msi_disable = %d\n", mhi_ctx->msi_disable); + rc = mhi_dev_recover(mhi_ctx); if (rc) { mhi_log(MHI_MSG_ERROR, "get mhi state failed\n"); diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 16e0c1f7ed0a..253274b5d9e6 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -527,6 +527,7 @@ struct mhi_dev { uint32_t *mmio_backup; struct mhi_config cfg; + bool msi_disable; u32 msi_data; u32 msi_lower; spinlock_t msi_lock; diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 0d015e7a9127..5669fcfbd16a 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -479,7 +479,7 @@ static int mhi_sm_prepare_resume(void) case MHI_DEV_READY_STATE: res = ep_pcie_get_msi_config(mhi_sm_ctx->mhi_dev->phandle, &cfg); - if (res) { + if (res && res != -EOPNOTSUPP) { MHI_SM_ERR("Error retrieving pcie msi logic\n"); goto exit; } From 319cb600be943010ea8ec167cc6f117d03392252 Mon Sep 17 00:00:00 2001 From: Juri Lelli Date: Mon, 27 Jun 2022 11:50:51 +0200 Subject: [PATCH 32/36] wait: Fix __wait_event_hrtimeout for RT/DL tasks [ Upstream commit cceeeb6a6d02e7b9a74ddd27a3225013b34174aa ] Changes to hrtimer mode (potentially made by __hrtimer_init_sleeper on PREEMPT_RT) are not visible to hrtimer_start_range_ns, thus not accounted for by hrtimer_start_expires call paths. In particular, __wait_event_hrtimeout suffers from this problem as we have, for example: fs/aio.c::read_events wait_event_interruptible_hrtimeout __wait_event_hrtimeout hrtimer_init_sleeper_on_stack <- this might "mode |= HRTIMER_MODE_HARD" on RT if task runs at RT/DL priority hrtimer_start_range_ns WARN_ON_ONCE(!(mode & HRTIMER_MODE_HARD) ^ !timer->is_hard) fires since the latter doesn't see the change of mode done by init_sleeper Fix it by making __wait_event_hrtimeout call hrtimer_sleeper_start_expires, which is aware of the special RT/DL case, instead of hrtimer_start_range_ns. Change-Id: I0fa428c0a9a8fb43bca19bb999b822c5111b6284 Reported-by: Bruno Goncalves Signed-off-by: Juri Lelli Signed-off-by: Thomas Gleixner Reviewed-by: Daniel Bristot de Oliveira Reviewed-by: Valentin Schneider Link: https://lore.kernel.org/r/20220627095051.42470-1-juri.lelli@redhat.com Signed-off-by: Sasha Levin Git-commit: bd80dd86f9bfc6c86ac7dfda912b6706953c4b59 Git-repo: https://android.googlesource.com/kernel/common/ Signed-off-by: Srinivasarao Pathipati --- include/linux/wait.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/linux/wait.h b/include/linux/wait.h index 5ee4869d6df5..6af553e35c85 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -530,10 +530,11 @@ do { \ \ hrtimer_init_sleeper_on_stack(&__t, CLOCK_MONOTONIC, \ HRTIMER_MODE_REL); \ - if ((timeout) != KTIME_MAX) \ - hrtimer_start_range_ns(&__t.timer, timeout, \ - current->timer_slack_ns, \ - HRTIMER_MODE_REL); \ + if ((timeout) != KTIME_MAX) { \ + hrtimer_set_expires_range_ns(&__t.timer, timeout, \ + current->timer_slack_ns); \ + hrtimer_sleeper_start_expires(&__t, HRTIMER_MODE_REL); \ + } \ \ __ret = ___wait_event(wq_head, condition, state, 0, 0, \ if (!__t.task) { \ From 0331251e022e3a0152fbca1ce0ee0b9e7da5dc21 Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Sat, 21 Jan 2023 20:54:05 +0530 Subject: [PATCH 33/36] soc: qcom: qsee_ipc_irq_bridge: Remove redundant cleanup qiib_cleanup in qiib_driver_data_deinit is redundant since this cleanup is already done in driver remove. Remove qiib_cleanup in deinit and add required NULL check to avoid any use-after-free scenario. Change-Id: I95fa3cf91b5ca6cbaeb66d304a0572ba1d294a69 Signed-off-by: Arun Prakash --- drivers/soc/qcom/qsee_ipc_irq_bridge.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/qsee_ipc_irq_bridge.c b/drivers/soc/qcom/qsee_ipc_irq_bridge.c index c07140879d3b..591aa7eefac3 100644 --- a/drivers/soc/qcom/qsee_ipc_irq_bridge.c +++ b/drivers/soc/qcom/qsee_ipc_irq_bridge.c @@ -125,7 +125,6 @@ static int qiib_driver_data_init(void) */ static void qiib_driver_data_deinit(void) { - qiib_cleanup(); if (!qiib_info->log_ctx) ipc_log_context_destroy(qiib_info->log_ctx); kfree(qiib_info); @@ -433,8 +432,10 @@ static void qiib_cleanup(void) } mutex_unlock(&qiib_info->list_lock); - if (!IS_ERR_OR_NULL(qiib_info->classp)) + if (!IS_ERR_OR_NULL(qiib_info->classp)) { class_destroy(qiib_info->classp); + qiib_info->classp = NULL; + } unregister_chrdev_region(MAJOR(qiib_info->dev_num), qiib_info->nports); } From 61c87a0b9670489b87cc187e946a8cf870883bd4 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Mon, 13 Feb 2023 20:53:47 -0800 Subject: [PATCH 34/36] msm: ipa3: Update MPLS DL Vlan tag array to use 16 bits MPLS GRE supports 12 bits up to 4094 vlans. 16 bits can support this max value while 8 bits will support only 254 values. Without this fix, vlans 255-4094 are not usable. Change-Id: I582f0186b2d1042e394b75762793b6234b0f097e Signed-off-by: Michael Adisumarta --- include/uapi/linux/msm_ipa.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 9b6786c29b21..163618b37735 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. * - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _UAPI_MSM_IPA_H_ @@ -1747,8 +1747,8 @@ struct IpaDscpVlanPcpMap_t { uint8_t pad3; /* for alignment */ uint8_t num_mpls_val_sorted; /* num of elements in mpls_val_sorted */ uint32_t mpls_val_sorted[IPA_EoGRE_MAX_VLAN * IPA_GRE_MAX_S_VLAN]; - uint8_t vlan_c[IPA_EoGRE_MAX_VLAN * IPA_GRE_MAX_S_VLAN]; - uint8_t vlan_s[IPA_EoGRE_MAX_VLAN * IPA_GRE_MAX_S_VLAN]; + uint16_t vlan_c[IPA_EoGRE_MAX_VLAN * IPA_GRE_MAX_S_VLAN]; + uint16_t vlan_s[IPA_EoGRE_MAX_VLAN * IPA_GRE_MAX_S_VLAN]; } __packed; /** From 7ddf19e97350f3d640acb2084eb052415a4030fa Mon Sep 17 00:00:00 2001 From: Puranam V G Tejaswi Date: Tue, 14 Feb 2023 16:09:02 +0530 Subject: [PATCH 35/36] msm: kgsl: Use dma_buf_get() to get dma_buf structure Currently we don't ensure if vma->vm_file is associated with dma_buf. This can cause issues later when private_data from a non dma_buf file is used as dma_buf structure. Hence get the fd that is associated with vma->vm_file and use dma_buf_get() to get pointer to dma_buf structure. dma_buf_get() ensures that the file from the input fd is associated with dma_buf. Change-Id: Ib78aef8b16bedca5ca86d3a132278ff9f07dce73 Signed-off-by: Puranam V G Tejaswi --- drivers/gpu/msm/kgsl.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index de5c52d3a54b..0a311a79bfb9 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2583,6 +2583,15 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable, } #ifdef CONFIG_DMA_SHARED_BUFFER +static int match_file(const void *p, struct file *file, unsigned int fd) +{ + /* + * We must return fd + 1 because iterate_fd stops searching on + * non-zero return, but 0 is a valid fd. + */ + return (p == file) ? (fd + 1) : 0; +} + static void _setup_cache_mode(struct kgsl_mem_entry *entry, struct vm_area_struct *vma) { @@ -2619,6 +2628,8 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device, vma = find_vma(current->mm, hostptr); if (vma && vma->vm_file) { + int fd; + ret = check_vma_flags(vma, entry->memdesc.flags); if (ret) { up_read(¤t->mm->mmap_sem); @@ -2634,10 +2645,27 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device, return -EFAULT; } - /* Take a refcount because dma_buf_put() decrements the refcount */ - get_file(vma->vm_file); - - dmabuf = vma->vm_file->private_data; + /* Look for the fd that matches this vma file */ + fd = iterate_fd(current->files, 0, match_file, vma->vm_file); + if (fd) { + dmabuf = dma_buf_get(fd - 1); + if (IS_ERR(dmabuf)) { + up_read(¤t->mm->mmap_sem); + return PTR_ERR(dmabuf); + } + /* + * It is possible that the fd obtained from iterate_fd + * was closed before passing the fd to dma_buf_get(). + * Hence dmabuf returned by dma_buf_get() could be + * different from vma->vm_file->private_data. Return + * failure if this happens. + */ + if (dmabuf != vma->vm_file->private_data) { + dma_buf_put(dmabuf); + up_read(¤t->mm->mmap_sem); + return -EBADF; + } + } } if (!dmabuf) { From 1a1dccc448f488762fe086df1028f54f148ac1c7 Mon Sep 17 00:00:00 2001 From: Krishna Nagaraja Date: Mon, 2 Jan 2023 23:37:36 +0530 Subject: [PATCH 36/36] msm: ipa: add support for PMIPv6 Make changes to add new proc ctx and uCP commands to support Proxy Mobile IPv6. Change-Id: I4c0995ffe6969c3183e6b16dd6dbd1203d7bec43 Signed-off-by: Krishna Nagaraja --- include/uapi/linux/msm_ipa.h | 53 +++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 163618b37735..d596fc155224 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -1529,6 +1529,8 @@ enum ipa_hdr_l2_type { * IPA_HDR_PROC_EoGRE_HEADER_ADD: Add IPV[46] and GRE header * IPA_HDR_PROC_EoGRE_HEADER_REMOVE: Remove IPV[46] and GRE header * IPA_HDR_PROC_WWAN_TO_ETHII_EX: To update PCP value for E2E traffic. + * IPA_HDR_PROC_GRE_HEADER_ADD, Add IPV[46] and IP-GRE header + * IPA_HDR_PROC_GRE_HEADER_REMOVE, Remove IPV[46] and IP-GRE header */ enum ipa_hdr_proc_type { IPA_HDR_PROC_NONE, @@ -1545,8 +1547,10 @@ enum ipa_hdr_proc_type { IPA_HDR_PROC_EoGRE_HEADER_ADD, IPA_HDR_PROC_EoGRE_HEADER_REMOVE, IPA_HDR_PROC_WWAN_TO_ETHII_EX, + IPA_HDR_PROC_GRE_HEADER_ADD, + IPA_HDR_PROC_GRE_HEADER_REMOVE }; -#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_WWAN_TO_ETHII_EX + 1) +#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_GRE_HEADER_REMOVE + 1) /** * struct ipa_rt_rule - attributes of a routing rule @@ -1865,6 +1869,52 @@ struct ipa_eogre_hdr_proc_ctx_params { struct ipa_eogre_header_remove_procparams hdr_remove_param; }; + +/** + * struct ipa_gre_header_add_procparams - + * @eth_hdr_retained: Specifies if Ethernet header is retained or not + * @input_ip_version: Specifies if Input header is IPV4(0) or IPV6(1) + * @output_ip_version: Specifies if template header's outer IP is IPV4(0) or IPV6(1) + * @second_pass: Specifies if the data should be processed again. + * @is_mpls: Specifies if ucp cmd is for legacy EoGRE(0) or MPLSoGRE(1) + * @tag_remove_len: Specifies amount to be removed for the tags + */ +struct ipa_gre_header_add_procparams { + uint32_t eth_hdr_retained :1; + uint32_t input_ip_version :1; + uint32_t output_ip_version :1; + uint32_t second_pass :1; + uint32_t is_mpls :1; + uint32_t tag_remove_len :4; + uint32_t reserved :23; +}; + +/** + * struct ipa_gre_header_remove_procparams - + * @hdr_len_remove: Specifies how much (in bytes) of the header needs + * to be removed + * @outer_ip_version: Specifies if template header's outer IP is IPV4(0) or IPV6(1) + * @is_mpls: Specifies if ucp cmd is for legacy EoGRE(0) or MPLSoGRE(1) + * @tag_add_len: Specifies amount to be added for the tags + */ +struct ipa_gre_header_remove_procparams { + uint32_t hdr_len_remove :8; /* 44 bytes for IPV6, 24 for IPV4 */ + uint32_t outer_ip_version :1; + uint32_t is_mpls :1; + uint32_t tag_add_len :4; + uint32_t reserved :18; +}; + +/** + * struct ipa_gre_hdr_proc_ctx_params - + * @hdr_add_param: parameters for header add + * @hdr_remove_param: parameters for header remove + */ +struct ipa_gre_hdr_proc_ctx_params { + struct ipa_gre_header_add_procparams hdr_add_param; + struct ipa_gre_header_remove_procparams hdr_remove_param; +}; + /** * struct ipa_eth_II_to_eth_II_ex_procparams - * @input_ethhdr_negative_offset: Specifies where the ethernet hdr offset is @@ -1926,6 +1976,7 @@ struct ipa_hdr_proc_ctx_add { struct ipa_eogre_hdr_proc_ctx_params eogre_params; struct ipa_eth_II_to_eth_II_ex_procparams generic_params; struct ipa_wwan_to_eth_II_ex_procparams generic_params_v2; + struct ipa_gre_hdr_proc_ctx_params gre_params; }; #define IPA_L2TP_HDR_PROC_SUPPORT