From ef6064d1c2e78d53bd42c16384631f342b72cc8c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 7 May 2021 14:53:11 +0200 Subject: [PATCH] 5.12-stable patches added patches: bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch bus-mhi-core-fix-check-for-syserr-at-power_up.patch bus-mhi-core-fix-invalid-error-returning-in-mhi_queue.patch bus-mhi-core-fix-mhi-runtime_pm-behavior.patch bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch --- ...ing-checks-for-mmio-register-entries.patch | 43 ++++ ...on-from-channel-context-during-reset.patch | 55 +++++ ...ore-fix-check-for-syserr-at-power_up.patch | 37 ++++ ...invalid-error-returning-in-mhi_queue.patch | 52 +++++ ...mhi-core-fix-mhi-runtime_pm-behavior.patch | 78 +++++++ ...values-from-remote-device-before-use.patch | 209 ++++++++++++++++++ ...em_reclaim-flag-from-state-workqueue.patch | 64 ++++++ 7 files changed, 538 insertions(+) create mode 100644 queue-5.12/bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch create mode 100644 queue-5.12/bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch create mode 100644 queue-5.12/bus-mhi-core-fix-check-for-syserr-at-power_up.patch create mode 100644 queue-5.12/bus-mhi-core-fix-invalid-error-returning-in-mhi_queue.patch create mode 100644 queue-5.12/bus-mhi-core-fix-mhi-runtime_pm-behavior.patch create mode 100644 queue-5.12/bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch create mode 100644 queue-5.12/bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch diff --git a/queue-5.12/bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch b/queue-5.12/bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch new file mode 100644 index 00000000000..73728e52347 --- /dev/null +++ b/queue-5.12/bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch @@ -0,0 +1,43 @@ +From 8de5ad99414347ad08e6ebc2260be1d2e009cb9a Mon Sep 17 00:00:00 2001 +From: Bhaumik Bhatt +Date: Tue, 9 Mar 2021 10:44:50 -0800 +Subject: bus: mhi: core: Add missing checks for MMIO register entries + +From: Bhaumik Bhatt + +commit 8de5ad99414347ad08e6ebc2260be1d2e009cb9a upstream. + +As per documentation, fields marked as (required) in an MHI +controller structure need to be populated by the controller driver +before calling mhi_register_controller(). Ensure all required +pointers and non-zero fields are present in the controller before +proceeding with the registration. + +Signed-off-by: Bhaumik Bhatt +Reviewed-by: Jeffrey Hugo +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1615315490-36017-1-git-send-email-bbhatt@codeaurora.org +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/core/init.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- a/drivers/bus/mhi/core/init.c ++++ b/drivers/bus/mhi/core/init.c +@@ -876,12 +876,10 @@ int mhi_register_controller(struct mhi_c + u32 soc_info; + int ret, i; + +- if (!mhi_cntrl) +- return -EINVAL; +- +- if (!mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || ++ if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || ++ !mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || + !mhi_cntrl->status_cb || !mhi_cntrl->read_reg || +- !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs) ++ !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || !mhi_cntrl->irq) + return -EINVAL; + + ret = parse_config(mhi_cntrl, config); diff --git a/queue-5.12/bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch b/queue-5.12/bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch new file mode 100644 index 00000000000..f312ca17531 --- /dev/null +++ b/queue-5.12/bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch @@ -0,0 +1,55 @@ +From 47705c08465931923e2f2b506986ca0bdf80380d Mon Sep 17 00:00:00 2001 +From: Bhaumik Bhatt +Date: Thu, 1 Apr 2021 14:16:15 -0700 +Subject: bus: mhi: core: Clear configuration from channel context during reset + +From: Bhaumik Bhatt + +commit 47705c08465931923e2f2b506986ca0bdf80380d upstream. + +When clearing up the channel context after client drivers are +done using channels, the configuration is currently not being +reset entirely. Ensure this is done to appropriately handle +issues where clients unaware of the context state end up calling +functions which expect a context. + +Signed-off-by: Bhaumik Bhatt +Reviewed-by: Hemant Kumar +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1617311778-1254-7-git-send-email-bbhatt@codeaurora.org +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/core/init.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/drivers/bus/mhi/core/init.c ++++ b/drivers/bus/mhi/core/init.c +@@ -552,6 +552,7 @@ void mhi_deinit_chan_ctxt(struct mhi_con + struct mhi_ring *buf_ring; + struct mhi_ring *tre_ring; + struct mhi_chan_ctxt *chan_ctxt; ++ u32 tmp; + + buf_ring = &mhi_chan->buf_ring; + tre_ring = &mhi_chan->tre_ring; +@@ -565,7 +566,19 @@ void mhi_deinit_chan_ctxt(struct mhi_con + vfree(buf_ring->base); + + buf_ring->base = tre_ring->base = NULL; ++ tre_ring->ctxt_wp = NULL; + chan_ctxt->rbase = 0; ++ chan_ctxt->rlen = 0; ++ chan_ctxt->rp = 0; ++ chan_ctxt->wp = 0; ++ ++ tmp = chan_ctxt->chcfg; ++ tmp &= ~CHAN_CTX_CHSTATE_MASK; ++ tmp |= (MHI_CH_STATE_DISABLED << CHAN_CTX_CHSTATE_SHIFT); ++ chan_ctxt->chcfg = tmp; ++ ++ /* Update to all cores */ ++ smp_wmb(); + } + + int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, diff --git a/queue-5.12/bus-mhi-core-fix-check-for-syserr-at-power_up.patch b/queue-5.12/bus-mhi-core-fix-check-for-syserr-at-power_up.patch new file mode 100644 index 00000000000..e267975f976 --- /dev/null +++ b/queue-5.12/bus-mhi-core-fix-check-for-syserr-at-power_up.patch @@ -0,0 +1,37 @@ +From 6403298c58d4858d93648f553abf0bcbd2dfaca2 Mon Sep 17 00:00:00 2001 +From: Jeffrey Hugo +Date: Fri, 12 Feb 2021 14:27:23 -0700 +Subject: bus: mhi: core: Fix check for syserr at power_up + +From: Jeffrey Hugo + +commit 6403298c58d4858d93648f553abf0bcbd2dfaca2 upstream. + +The check to see if we have reset the device after detecting syserr at +power_up is inverted. wait_for_event_timeout() returns 0 on failure, +and a positive value on success. The check is looking for non-zero +as a failure, which is likely to incorrectly cause a device init failure +if syserr was detected at power_up. Fix this. + +Fixes: e18d4e9fa79b ("bus: mhi: core: Handle syserr during power_up") +Signed-off-by: Jeffrey Hugo +Reviewed-by: Loic Poulain +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1613165243-23359-1-git-send-email-jhugo@codeaurora.org +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/core/pm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/bus/mhi/core/pm.c ++++ b/drivers/bus/mhi/core/pm.c +@@ -1092,7 +1092,7 @@ int mhi_async_power_up(struct mhi_contro + &val) || + !val, + msecs_to_jiffies(mhi_cntrl->timeout_ms)); +- if (ret) { ++ if (!ret) { + ret = -EIO; + dev_info(dev, "Failed to reset MHI due to syserr state\n"); + goto error_bhi_offset; diff --git a/queue-5.12/bus-mhi-core-fix-invalid-error-returning-in-mhi_queue.patch b/queue-5.12/bus-mhi-core-fix-invalid-error-returning-in-mhi_queue.patch new file mode 100644 index 00000000000..6da98483b8e --- /dev/null +++ b/queue-5.12/bus-mhi-core-fix-invalid-error-returning-in-mhi_queue.patch @@ -0,0 +1,52 @@ +From 0ecc1c70dcd32c0f081b173a1a5d89952686f271 Mon Sep 17 00:00:00 2001 +From: Loic Poulain +Date: Fri, 26 Feb 2021 11:53:02 +0100 +Subject: bus: mhi: core: Fix invalid error returning in mhi_queue + +From: Loic Poulain + +commit 0ecc1c70dcd32c0f081b173a1a5d89952686f271 upstream. + +mhi_queue returns an error when the doorbell is not accessible in +the current state. This can happen when the device is in non M0 +state, like M3, and needs to be waken-up prior ringing the DB. This +case is managed earlier by triggering an asynchronous M3 exit via +controller resume/suspend callbacks, that in turn will cause M0 +transition and DB update. + +So, since it's not an error but just delaying of doorbell update, there +is no reason to return an error. + +This also fixes a use after free error for skb case, indeed a caller +queuing skb will try to free the skb if the queueing fails, but in +that case queueing has been done. + +Fixes: a8f75cb348fd ("mhi: core: Factorize mhi queuing") +Signed-off-by: Loic Poulain +Reviewed-by: Jeffrey Hugo +Reviewed-by: Bhaumik Bhatt +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1614336782-5809-1-git-send-email-loic.poulain@linaro.org +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/core/main.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/drivers/bus/mhi/core/main.c ++++ b/drivers/bus/mhi/core/main.c +@@ -1077,12 +1077,8 @@ static int mhi_queue(struct mhi_device * + if (mhi_chan->dir == DMA_TO_DEVICE) + atomic_inc(&mhi_cntrl->pending_pkts); + +- if (unlikely(!MHI_DB_ACCESS_VALID(mhi_cntrl))) { +- ret = -EIO; +- goto exit_unlock; +- } +- +- mhi_ring_chan_db(mhi_cntrl, mhi_chan); ++ if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) ++ mhi_ring_chan_db(mhi_cntrl, mhi_chan); + + if (dir == DMA_FROM_DEVICE) + mhi_cntrl->runtime_put(mhi_cntrl); diff --git a/queue-5.12/bus-mhi-core-fix-mhi-runtime_pm-behavior.patch b/queue-5.12/bus-mhi-core-fix-mhi-runtime_pm-behavior.patch new file mode 100644 index 00000000000..86ac1b534f4 --- /dev/null +++ b/queue-5.12/bus-mhi-core-fix-mhi-runtime_pm-behavior.patch @@ -0,0 +1,78 @@ +From 4547a749be997eb12ea7edcf361ec2a5329f7aec Mon Sep 17 00:00:00 2001 +From: Loic Poulain +Date: Tue, 6 Apr 2021 11:11:54 +0200 +Subject: bus: mhi: core: Fix MHI runtime_pm behavior + +From: Loic Poulain + +commit 4547a749be997eb12ea7edcf361ec2a5329f7aec upstream. + +This change ensures that PM reference is always get during packet +queueing and released either after queuing completion (RX) or once +the buffer has been consumed (TX). This guarantees proper update for +underlying MHI controller runtime status (e.g. last_busy timestamp) +and prevents suspend to be triggered while TX packets are flying, +or before we completed update of the RX ring. + +Signed-off-by: Loic Poulain +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1617700315-12492-1-git-send-email-loic.poulain@linaro.org +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/core/main.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +--- a/drivers/bus/mhi/core/main.c ++++ b/drivers/bus/mhi/core/main.c +@@ -589,8 +589,11 @@ static int parse_xfer_event(struct mhi_c + /* notify client */ + mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); + +- if (mhi_chan->dir == DMA_TO_DEVICE) ++ if (mhi_chan->dir == DMA_TO_DEVICE) { + atomic_dec(&mhi_cntrl->pending_pkts); ++ /* Release the reference got from mhi_queue() */ ++ mhi_cntrl->runtime_put(mhi_cntrl); ++ } + + /* + * Recycle the buffer if buffer is pre-allocated, +@@ -1062,9 +1065,11 @@ static int mhi_queue(struct mhi_device * + if (unlikely(ret)) + goto exit_unlock; + +- /* trigger M3 exit if necessary */ +- if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state)) +- mhi_trigger_resume(mhi_cntrl); ++ /* Packet is queued, take a usage ref to exit M3 if necessary ++ * for host->device buffer, balanced put is done on buffer completion ++ * for device->host buffer, balanced put is after ringing the DB ++ */ ++ mhi_cntrl->runtime_get(mhi_cntrl); + + /* Assert dev_wake (to exit/prevent M1/M2)*/ + mhi_cntrl->wake_toggle(mhi_cntrl); +@@ -1079,6 +1084,9 @@ static int mhi_queue(struct mhi_device * + + mhi_ring_chan_db(mhi_cntrl, mhi_chan); + ++ if (dir == DMA_FROM_DEVICE) ++ mhi_cntrl->runtime_put(mhi_cntrl); ++ + exit_unlock: + read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); + +@@ -1470,8 +1478,11 @@ static void mhi_reset_data_chan(struct m + while (tre_ring->rp != tre_ring->wp) { + struct mhi_buf_info *buf_info = buf_ring->rp; + +- if (mhi_chan->dir == DMA_TO_DEVICE) ++ if (mhi_chan->dir == DMA_TO_DEVICE) { + atomic_dec(&mhi_cntrl->pending_pkts); ++ /* Release the reference got from mhi_queue() */ ++ mhi_cntrl->runtime_put(mhi_cntrl); ++ } + + if (!buf_info->pre_mapped) + mhi_cntrl->unmap_single(mhi_cntrl, buf_info); diff --git a/queue-5.12/bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch b/queue-5.12/bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch new file mode 100644 index 00000000000..e797dd00e82 --- /dev/null +++ b/queue-5.12/bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch @@ -0,0 +1,209 @@ +From ec32332df7645e0ba463a08d483fe97665167071 Mon Sep 17 00:00:00 2001 +From: Jeffrey Hugo +Date: Wed, 10 Mar 2021 14:30:55 -0700 +Subject: bus: mhi: core: Sanity check values from remote device before use + +From: Jeffrey Hugo + +commit ec32332df7645e0ba463a08d483fe97665167071 upstream. + +When parsing the structures in the shared memory, there are values which +come from the remote device. For example, a transfer completion event +will have a pointer to the tre in the relevant channel's transfer ring. +As another example, event ring elements may specify a channel in which +the event occurred, however the specified channel value may not be valid +as no channel is defined at that index even though the index may be less +than the maximum allowed index. Such values should be considered to be +untrusted, and validated before use. If we blindly use such values, we +may access invalid data or crash if the values are corrupted. + +If validation fails, drop the relevant event. + +Signed-off-by: Jeffrey Hugo +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Hemant Kumar +Link: https://lore.kernel.org/r/1615411855-15053-1-git-send-email-jhugo@codeaurora.org +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/core/main.c | 81 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 74 insertions(+), 7 deletions(-) + +--- a/drivers/bus/mhi/core/main.c ++++ b/drivers/bus/mhi/core/main.c +@@ -242,6 +242,11 @@ static void mhi_del_ring_element(struct + smp_wmb(); + } + ++static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr) ++{ ++ return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len; ++} ++ + int mhi_destroy_device(struct device *dev, void *data) + { + struct mhi_device *mhi_dev; +@@ -383,7 +388,16 @@ irqreturn_t mhi_irq_handler(int irq_numb + struct mhi_event_ctxt *er_ctxt = + &mhi_cntrl->mhi_ctxt->er_ctxt[mhi_event->er_index]; + struct mhi_ring *ev_ring = &mhi_event->ring; +- void *dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); ++ dma_addr_t ptr = er_ctxt->rp; ++ void *dev_rp; ++ ++ if (!is_valid_ring_ptr(ev_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event ring rp points outside of the event ring\n"); ++ return IRQ_HANDLED; ++ } ++ ++ dev_rp = mhi_to_virtual(ev_ring, ptr); + + /* Only proceed if event ring has pending events */ + if (ev_ring->rp == dev_rp) +@@ -536,6 +550,11 @@ static int parse_xfer_event(struct mhi_c + struct mhi_buf_info *buf_info; + u16 xfer_len; + ++ if (!is_valid_ring_ptr(tre_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event element points outside of the tre ring\n"); ++ break; ++ } + /* Get the TRB this event points to */ + ev_tre = mhi_to_virtual(tre_ring, ptr); + +@@ -695,6 +714,12 @@ static void mhi_process_cmd_completion(s + struct mhi_chan *mhi_chan; + u32 chan; + ++ if (!is_valid_ring_ptr(mhi_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event element points outside of the cmd ring\n"); ++ return; ++ } ++ + cmd_pkt = mhi_to_virtual(mhi_ring, ptr); + + chan = MHI_TRE_GET_CMD_CHID(cmd_pkt); +@@ -719,6 +744,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + u32 chan; + int count = 0; ++ dma_addr_t ptr = er_ctxt->rp; + + /* + * This is a quick check to avoid unnecessary event processing +@@ -728,7 +754,13 @@ int mhi_process_ctrl_ev_ring(struct mhi_ + if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) + return -EIO; + +- dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); ++ if (!is_valid_ring_ptr(ev_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event ring rp points outside of the event ring\n"); ++ return -EIO; ++ } ++ ++ dev_rp = mhi_to_virtual(ev_ring, ptr); + local_rp = ev_ring->rp; + + while (dev_rp != local_rp) { +@@ -834,6 +866,8 @@ int mhi_process_ctrl_ev_ring(struct mhi_ + */ + if (chan < mhi_cntrl->max_chan) { + mhi_chan = &mhi_cntrl->mhi_chan[chan]; ++ if (!mhi_chan->configured) ++ break; + parse_xfer_event(mhi_cntrl, local_rp, mhi_chan); + event_quota--; + } +@@ -845,7 +879,15 @@ int mhi_process_ctrl_ev_ring(struct mhi_ + + mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); + local_rp = ev_ring->rp; +- dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); ++ ++ ptr = er_ctxt->rp; ++ if (!is_valid_ring_ptr(ev_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event ring rp points outside of the event ring\n"); ++ return -EIO; ++ } ++ ++ dev_rp = mhi_to_virtual(ev_ring, ptr); + count++; + } + +@@ -868,11 +910,18 @@ int mhi_process_data_event_ring(struct m + int count = 0; + u32 chan; + struct mhi_chan *mhi_chan; ++ dma_addr_t ptr = er_ctxt->rp; + + if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_cntrl->pm_state))) + return -EIO; + +- dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); ++ if (!is_valid_ring_ptr(ev_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event ring rp points outside of the event ring\n"); ++ return -EIO; ++ } ++ ++ dev_rp = mhi_to_virtual(ev_ring, ptr); + local_rp = ev_ring->rp; + + while (dev_rp != local_rp && event_quota > 0) { +@@ -886,7 +935,8 @@ int mhi_process_data_event_ring(struct m + * Only process the event ring elements whose channel + * ID is within the maximum supported range. + */ +- if (chan < mhi_cntrl->max_chan) { ++ if (chan < mhi_cntrl->max_chan && ++ mhi_cntrl->mhi_chan[chan].configured) { + mhi_chan = &mhi_cntrl->mhi_chan[chan]; + + if (likely(type == MHI_PKT_TYPE_TX_EVENT)) { +@@ -900,7 +950,15 @@ int mhi_process_data_event_ring(struct m + + mhi_recycle_ev_ring_element(mhi_cntrl, ev_ring); + local_rp = ev_ring->rp; +- dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); ++ ++ ptr = er_ctxt->rp; ++ if (!is_valid_ring_ptr(ev_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event ring rp points outside of the event ring\n"); ++ return -EIO; ++ } ++ ++ dev_rp = mhi_to_virtual(ev_ring, ptr); + count++; + } + read_lock_bh(&mhi_cntrl->pm_lock); +@@ -1365,6 +1423,7 @@ static void mhi_mark_stale_events(struct + struct mhi_ring *ev_ring; + struct device *dev = &mhi_cntrl->mhi_dev->dev; + unsigned long flags; ++ dma_addr_t ptr; + + dev_dbg(dev, "Marking all events for chan: %d as stale\n", chan); + +@@ -1372,7 +1431,15 @@ static void mhi_mark_stale_events(struct + + /* mark all stale events related to channel as STALE event */ + spin_lock_irqsave(&mhi_event->lock, flags); +- dev_rp = mhi_to_virtual(ev_ring, er_ctxt->rp); ++ ++ ptr = er_ctxt->rp; ++ if (!is_valid_ring_ptr(ev_ring, ptr)) { ++ dev_err(&mhi_cntrl->mhi_dev->dev, ++ "Event ring rp points outside of the event ring\n"); ++ dev_rp = ev_ring->rp; ++ } else { ++ dev_rp = mhi_to_virtual(ev_ring, ptr); ++ } + + local_rp = ev_ring->rp; + while (dev_rp != local_rp) { diff --git a/queue-5.12/bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch b/queue-5.12/bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch new file mode 100644 index 00000000000..f786e8df1c4 --- /dev/null +++ b/queue-5.12/bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch @@ -0,0 +1,64 @@ +From 0fccbf0a3b690b162f53b13ed8bc442ea33437dc Mon Sep 17 00:00:00 2001 +From: Loic Poulain +Date: Wed, 24 Feb 2021 11:18:50 +0100 +Subject: bus: mhi: pci_generic: Remove WQ_MEM_RECLAIM flag from state workqueue + +From: Loic Poulain + +commit 0fccbf0a3b690b162f53b13ed8bc442ea33437dc upstream. + +A recent change created a dedicated workqueue for the state-change work +with WQ_HIGHPRI (no strong reason for that) and WQ_MEM_RECLAIM flags, +but the state-change work (mhi_pm_st_worker) does not guarantee forward +progress under memory pressure, and will even wait on various memory +allocations when e.g. creating devices, loading firmware, etc... The +work is then not part of a memory reclaim path... + +Moreover, this causes a warning in check_flush_dependency() since we end +up in code that flushes a non-reclaim workqueue: + +[ 40.969601] workqueue: WQ_MEM_RECLAIM mhi_hiprio_wq:mhi_pm_st_worker [mhi] is flushing !WQ_MEM_RECLAIM events_highpri:flush_backlog +[ 40.969612] WARNING: CPU: 4 PID: 158 at kernel/workqueue.c:2607 check_flush_dependency+0x11c/0x140 +[ 40.969733] Call Trace: +[ 40.969740] __flush_work+0x97/0x1d0 +[ 40.969745] ? wake_up_process+0x15/0x20 +[ 40.969749] ? insert_work+0x70/0x80 +[ 40.969750] ? __queue_work+0x14a/0x3e0 +[ 40.969753] flush_work+0x10/0x20 +[ 40.969756] rollback_registered_many+0x1c9/0x510 +[ 40.969759] unregister_netdevice_queue+0x94/0x120 +[ 40.969761] unregister_netdev+0x1d/0x30 +[ 40.969765] mhi_net_remove+0x1a/0x40 [mhi_net] +[ 40.969770] mhi_driver_remove+0x124/0x250 [mhi] +[ 40.969776] device_release_driver_internal+0xf0/0x1d0 +[ 40.969778] device_release_driver+0x12/0x20 +[ 40.969782] bus_remove_device+0xe1/0x150 +[ 40.969786] device_del+0x17b/0x3e0 +[ 40.969791] mhi_destroy_device+0x9a/0x100 [mhi] +[ 40.969796] ? mhi_unmap_single_use_bb+0x50/0x50 [mhi] +[ 40.969799] device_for_each_child+0x5e/0xa0 +[ 40.969804] mhi_pm_st_worker+0x921/0xf50 [mhi] + +Fixes: 8f7039787687 ("bus: mhi: core: Move to using high priority workqueue") +Signed-off-by: Loic Poulain +Reviewed-by: Bhaumik Bhatt +Reviewed-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/1614161930-8513-1-git-send-email-loic.poulain@linaro.org +Signed-off-by: Manivannan Sadhasivam +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/core/init.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/bus/mhi/core/init.c ++++ b/drivers/bus/mhi/core/init.c +@@ -901,8 +901,7 @@ int mhi_register_controller(struct mhi_c + INIT_WORK(&mhi_cntrl->st_worker, mhi_pm_st_worker); + init_waitqueue_head(&mhi_cntrl->state_event); + +- mhi_cntrl->hiprio_wq = alloc_ordered_workqueue +- ("mhi_hiprio_wq", WQ_MEM_RECLAIM | WQ_HIGHPRI); ++ mhi_cntrl->hiprio_wq = alloc_ordered_workqueue("mhi_hiprio_wq", WQ_HIGHPRI); + if (!mhi_cntrl->hiprio_wq) { + dev_err(mhi_cntrl->cntrl_dev, "Failed to allocate workqueue\n"); + ret = -ENOMEM; -- 2.47.3