From c71ae0f6830e692c98fbae7238ab91e90a8211b0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 7 May 2021 14:52:50 +0200 Subject: [PATCH] 5.11-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-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 ++++ ...values-from-remote-device-before-use.patch | 209 ++++++++++++++++++ ...em_reclaim-flag-from-state-workqueue.patch | 64 ++++++ 5 files changed, 408 insertions(+) create mode 100644 queue-5.11/bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch create mode 100644 queue-5.11/bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch create mode 100644 queue-5.11/bus-mhi-core-fix-check-for-syserr-at-power_up.patch create mode 100644 queue-5.11/bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch create mode 100644 queue-5.11/bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch diff --git a/queue-5.11/bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch b/queue-5.11/bus-mhi-core-add-missing-checks-for-mmio-register-entries.patch new file mode 100644 index 00000000000..47ccfdea634 --- /dev/null +++ b/queue-5.11/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 +@@ -871,12 +871,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.11/bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch b/queue-5.11/bus-mhi-core-clear-configuration-from-channel-context-during-reset.patch new file mode 100644 index 00000000000..c8d41cc68fe --- /dev/null +++ b/queue-5.11/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 +@@ -547,6 +547,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; +@@ -560,7 +561,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.11/bus-mhi-core-fix-check-for-syserr-at-power_up.patch b/queue-5.11/bus-mhi-core-fix-check-for-syserr-at-power_up.patch new file mode 100644 index 00000000000..e267975f976 --- /dev/null +++ b/queue-5.11/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.11/bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch b/queue-5.11/bus-mhi-core-sanity-check-values-from-remote-device-before-use.patch new file mode 100644 index 00000000000..0462850ce9d --- /dev/null +++ b/queue-5.11/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 +@@ -222,6 +222,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; +@@ -351,7 +356,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) +@@ -504,6 +518,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); + +@@ -663,6 +682,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); +@@ -687,6 +712,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 +@@ -696,7 +722,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) { +@@ -802,6 +834,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--; + } +@@ -813,7 +847,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++; + } + +@@ -836,11 +878,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) { +@@ -854,7 +903,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)) { +@@ -868,7 +918,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); +@@ -1407,6 +1465,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); + +@@ -1414,7 +1473,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.11/bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch b/queue-5.11/bus-mhi-pci_generic-remove-wq_mem_reclaim-flag-from-state-workqueue.patch new file mode 100644 index 00000000000..5fe3ef9680c --- /dev/null +++ b/queue-5.11/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 +@@ -896,8 +896,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