Hi all,
We found the following issue with Linux v6.12-rc7 on KunPeng920
platform. A very low frequency problem of pc value mismatch occurs when
using perf hardware breakpoints to trigger a signal handler and
comparing pc from u_context with its desired value.
Attached please find the reproducer for this issue. It applies perf
events to set a hardware breakpoint to an address while binding a signal
to the perf event fd. When stepping into the breakpoint address, the
signal handler compares pc value copied from signal ucontext with the
real breakpoint address and see if there is a mismatch.
While looking into the flow of execution:
// normal flow of exe:
a.out-19844 [038] d... 8763.348609:
hw_breakpoint_control: perf user addr: 400c6c, bp addr: 400c6c, ops: 0
// breakpoint exception:
a.out-19844 [038] d... 8763.348611: do_debug_exception:
ec: 0, pc: 400c6c, pstate: 20001000
a.out-19844 [038] d... 8763.348611: breakpoint_handler:
perf bp read: 400c6c
// send signal:
a.out-19844 [038] d.h. 8763.348613: send_sigio_to_task
<-send_sigio
a.out-19844 [038] d.h. 8763.348614: <stack trace>
=> send_sigio_to_task
=> send_sigio
=> kill_fasync_rcu
=> kill_fasync
=> perf_event_wakeup
=> perf_pending_event
=> irq_work_single
=> irq_work_run_list
=> irq_work_run
=> do_handle_IPI
=> ipi_handler
=> handle_percpu_devid_fasteoi_ipi
=> __handle_domain_irq
=> gic_handle_irq
=> el0_irq_naked
a.out-19844 [038] d.h. 8763.348614: send_sigio_to_task:
step in with signum 38
a.out-19844 [038] d.h. 8763.348615: send_sigio_to_task:
will do_send_sig_info 38
// kernel signal handling:
a.out-19844 [038] .... 8763.348616: do_notify_resume:
thread_flags 2097665, _TIF_SIGPENDING 1, _TIF_NOTIFY_SIGNAL40
a.out-19844 [038] .... 8763.348617: setup_sigframe:
restore sig: 400c6c
// single step exception:
a.out-19844 [038] d... 8763.348619: do_debug_exception:
ec: 1, pc: 400988, pstate: 20001000
a.out-19844 [038] d... 8763.348621:
hw_breakpoint_control: perf user addr: 400c6c, bp addr: 400c6c, ops: 1
// abnormal flow of exe:
a.out-19844 [084] d... 8763.782103:
hw_breakpoint_control: perf user addr: 400c6c, bp addr: 400c6c, ops: 0
// breakpoint exception:
a.out-19844 [084] d... 8763.782104: do_debug_exception:
ec: 0, pc: 400c6c, pstate: 20001000
// single step exception:
a.out-19844 [084] d... 8763.782105: breakpoint_handler:
perf bp read: 400c6c
a.out-19844 [084] d... 8763.782107: do_debug_exception:
ec: 1, pc: 400c70, pstate: 20001000
// send signal:
a.out-19844 [084] d.h. 8763.782108: send_sigio_to_task
<-send_sigio
a.out-19844 [084] d.h. 8763.782109: <stack trace>
=> send_sigio_to_task
=> send_sigio
=> kill_fasync_rcu
=> kill_fasync
=> perf_event_wakeup
=> perf_pending_event
=> irq_work_single
=> irq_work_run_list
=> irq_work_run
=> do_handle_IPI
=> ipi_handler
=> handle_percpu_devid_fasteoi_ipi
=> __handle_domain_irq
=> gic_handle_irq
=> el0_irq_naked
a.out-19844 [084] d.h. 8763.782110: send_sigio_to_task:
step in with signum 38
a.out-19844 [084] d.h. 8763.782110: send_sigio_to_task:
will do_send_sig_info 38
// kernel signal handling:
a.out-19844 [084] .... 8763.782111: do_notify_resume:
thread_flags 513, _TIF_SIGPENDING 1, _TIF_NOTIFY_SIGNAL40
a.out-19844 [084] .... 8763.782113: setup_sigframe:
restore sig: 400c70
a.out-19844 [084] d... 8763.782115:
hw_breakpoint_control: perf user addr: 400c6c, bp addr: 400c6c, ops: 1
Kernel sends this signal to task through pushing a perf_pending_event
(which sends the signal) in irq_work_queue then triggering an IPI to let
kernel handle this pended task.
seems that when mismatch occurs, the IPI does not preempt the breakpoint
exception it should preempt, causing no pending signals to be handled.
In this way, there is no pending signals in do_notify_resume and kernel
will not set up signal frame with correct pc value.
Thanks,
Chen
In very rare cases after resuming controller from L1 to L0 it reads
registers before the clock UTMI have been enabled and as the result
driver reads incorrect value.
Most of registers are in APB domain clock but some of them (e.g. PORTSC)
are in UTMI domain clock.
After entering to L1 state the UTMI clock can be disabled.
When controller transition from L1 to L0 the port status change event is
reported and in interrupt runtime function driver reads PORTSC.
During this read operation controller synchronize UTMI and APB domain
but UTMI clock is still disabled and in result it reads 0xFFFFFFFF value.
To fix this issue driver increases APB timeout value.
The issue is platform specific and if the default value of APB timeout
is not sufficient then this time should be set Individually for each
platform.
Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
cc: stable(a)vger.kernel.org
Signed-off-by: Pawel Laszczak <pawell(a)cadence.com>
---
Changelog:
v2:
- changed patch description
- made patch as platform specific
drivers/usb/cdns3/cdnsp-gadget.c | 29 +++++++++++++++++++++++++++++
drivers/usb/cdns3/cdnsp-gadget.h | 3 +++
drivers/usb/cdns3/cdnsp-pci.c | 12 ++++++++++--
drivers/usb/cdns3/core.h | 3 +++
4 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c
index 87f310841735..7f5534db2086 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.c
+++ b/drivers/usb/cdns3/cdnsp-gadget.c
@@ -139,6 +139,26 @@ static void cdnsp_clear_port_change_bit(struct cdnsp_device *pdev,
(portsc & PORT_CHANGE_BITS), port_regs);
}
+static void cdnsp_set_apb_timeout_value(struct cdnsp_device *pdev)
+{
+ struct cdns *cdns = dev_get_drvdata(pdev->dev);
+ __le32 __iomem *reg;
+ void __iomem *base;
+ u32 offset = 0;
+ u32 val;
+
+ if (!cdns->override_apb_timeout)
+ return;
+
+ base = &pdev->cap_regs->hc_capbase;
+ offset = cdnsp_find_next_ext_cap(base, offset, D_XEC_PRE_REGS_CAP);
+ reg = base + offset + REG_CHICKEN_BITS_3_OFFSET;
+
+ val = le32_to_cpu(readl(reg));
+ val = CHICKEN_APB_TIMEOUT_SET(val, cdns->override_apb_timeout);
+ writel(cpu_to_le32(val), reg);
+}
+
static void cdnsp_set_chicken_bits_2(struct cdnsp_device *pdev, u32 bit)
{
__le32 __iomem *reg;
@@ -1798,6 +1818,15 @@ static int cdnsp_gen_setup(struct cdnsp_device *pdev)
pdev->hci_version = HC_VERSION(pdev->hcc_params);
pdev->hcc_params = readl(&pdev->cap_regs->hcc_params);
+ /*
+ * Override the APB timeout value to give the controller more time for
+ * enabling UTMI clock and synchronizing APB and UTMI clock domains.
+ * This fix is platform specific and is required to fixes issue with
+ * reading incorrect value from PORTSC register after resuming
+ * from L1 state.
+ */
+ cdnsp_set_apb_timeout_value(pdev);
+
cdnsp_get_rev_cap(pdev);
/* Make sure the Device Controller is halted. */
diff --git a/drivers/usb/cdns3/cdnsp-gadget.h b/drivers/usb/cdns3/cdnsp-gadget.h
index 84887dfea763..87ac0cd113e7 100644
--- a/drivers/usb/cdns3/cdnsp-gadget.h
+++ b/drivers/usb/cdns3/cdnsp-gadget.h
@@ -520,6 +520,9 @@ struct cdnsp_rev_cap {
#define REG_CHICKEN_BITS_2_OFFSET 0x48
#define CHICKEN_XDMA_2_TP_CACHE_DIS BIT(28)
+#define REG_CHICKEN_BITS_3_OFFSET 0x4C
+#define CHICKEN_APB_TIMEOUT_SET(p, val) (((p) & ~GENMASK(21, 0)) | (val))
+
/* XBUF Extended Capability ID. */
#define XBUF_CAP_ID 0xCB
#define XBUF_RX_TAG_MASK_0_OFFSET 0x1C
diff --git a/drivers/usb/cdns3/cdnsp-pci.c b/drivers/usb/cdns3/cdnsp-pci.c
index a51144504ff3..8c361b8394e9 100644
--- a/drivers/usb/cdns3/cdnsp-pci.c
+++ b/drivers/usb/cdns3/cdnsp-pci.c
@@ -28,6 +28,8 @@
#define PCI_DRIVER_NAME "cdns-pci-usbssp"
#define PLAT_DRIVER_NAME "cdns-usbssp"
+#define CHICKEN_APB_TIMEOUT_VALUE 0x1C20
+
static struct pci_dev *cdnsp_get_second_fun(struct pci_dev *pdev)
{
/*
@@ -139,6 +141,14 @@ static int cdnsp_pci_probe(struct pci_dev *pdev,
cdnsp->otg_irq = pdev->irq;
}
+ /*
+ * Cadence PCI based platform require some longer timeout for APB
+ * to fixes domain clock synchronization issue after resuming
+ * controller from L1 state.
+ */
+ cdnsp->override_apb_timeout = CHICKEN_APB_TIMEOUT_VALUE;
+ pci_set_drvdata(pdev, cdnsp);
+
if (pci_is_enabled(func)) {
cdnsp->dev = dev;
cdnsp->gadget_init = cdnsp_gadget_init;
@@ -148,8 +158,6 @@ static int cdnsp_pci_probe(struct pci_dev *pdev,
goto free_cdnsp;
}
- pci_set_drvdata(pdev, cdnsp);
-
device_wakeup_enable(&pdev->dev);
if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);
diff --git a/drivers/usb/cdns3/core.h b/drivers/usb/cdns3/core.h
index 921cccf1ca9d..801be9e61340 100644
--- a/drivers/usb/cdns3/core.h
+++ b/drivers/usb/cdns3/core.h
@@ -79,6 +79,8 @@ struct cdns3_platform_data {
* @pdata: platform data from glue layer
* @lock: spinlock structure
* @xhci_plat_data: xhci private data structure pointer
+ * @override_apb_timeout: hold value of APB timeout. For value 0 the default
+ * value in CHICKEN_BITS_3 will be preserved.
* @gadget_init: pointer to gadget initialization function
*/
struct cdns {
@@ -117,6 +119,7 @@ struct cdns {
struct cdns3_platform_data *pdata;
spinlock_t lock;
struct xhci_plat_priv *xhci_plat_data;
+ u32 override_apb_timeout;
int (*gadget_init)(struct cdns *cdns);
};
--
2.43.0
The quilt patch titled
Subject: mm/contig_alloc: fix alloc_contig_range when __GFP_COMP and order < MAX_ORDER
has been removed from the -mm tree. Its filename was
mm-contig_alloc-fix-alloc_contig_range-when-__gfp_comp-and-order-max_order.patch
This patch was dropped because an updated version will be issued
------------------------------------------------------
From: Jinjiang Tu <tujinjiang(a)huawei.com>
Subject: mm/contig_alloc: fix alloc_contig_range when __GFP_COMP and order < MAX_ORDER
Date: Wed, 12 Mar 2025 16:47:05 +0800
When calling alloc_contig_range() with __GFP_COMP and the order of
requested pfn range is pageblock_order, less than MAX_ORDER, I triggered
WARNING as follows:
PFN range: requested [2150105088, 2150105600), allocated [2150105088, 2150106112)
WARNING: CPU: 3 PID: 580 at mm/page_alloc.c:6877 alloc_contig_range+0x280/0x340
alloc_contig_range() marks pageblocks of the requested pfn range to be
isolated, migrate these pages if they are in use and will be freed to
MIGRATE_ISOLATED freelist.
Suppose two alloc_contig_range() calls at the same time and the requested
pfn range are [0x80280000, 0x80280200) and [0x80280200, 0x80280400)
respectively. Suppose the two memory range are in use, then
alloc_contig_range() will migrate and free these pages to MIGRATE_ISOLATED
freelist. __free_one_page() will merge MIGRATE_ISOLATE buddy to larger
buddy, resulting in a MAX_ORDER buddy. Finally, find_large_buddy() in
alloc_contig_range() returns a MAX_ORDER buddy and results in WARNING.
To fix it, call free_contig_range() to free the excess pfn range.
Link: https://lkml.kernel.org/r/20250312084705.2938220-1-tujinjiang@huawei.com
Fixes: e98337d11bbd ("mm/contig_alloc: support __GFP_COMP")
Signed-off-by: Jinjiang Tu <tujinjiang(a)huawei.com>
Cc: David Hildenbrand <david(a)redhat.com>
Cc: Kefeng Wang <wangkefeng.wang(a)huawei.com>
Cc: Nanyong Sun <sunnanyong(a)huawei.com>
Cc: Yu Zhao <yuzhao(a)google.com>
Cc: Zi Yan <ziy(a)nvidia.com>
Cc: <stable(a)vger.kernel.org>
Signed-off-by: Andrew Morton <akpm(a)linux-foundation.org>
---
mm/page_alloc.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
--- a/mm/page_alloc.c~mm-contig_alloc-fix-alloc_contig_range-when-__gfp_comp-and-order-max_order
+++ a/mm/page_alloc.c
@@ -6786,7 +6786,8 @@ int alloc_contig_range_noprof(unsigned l
goto done;
}
- if (!(gfp_mask & __GFP_COMP)) {
+ if (!(gfp_mask & __GFP_COMP) ||
+ (is_power_of_2(end - start) && ilog2(end - start) < MAX_PAGE_ORDER)) {
split_free_pages(cc.freepages, gfp_mask);
/* Free head and tail (if any) */
@@ -6794,7 +6795,15 @@ int alloc_contig_range_noprof(unsigned l
free_contig_range(outer_start, start - outer_start);
if (end != outer_end)
free_contig_range(end, outer_end - end);
- } else if (start == outer_start && end == outer_end && is_power_of_2(end - start)) {
+
+ outer_start = start;
+ outer_end = end;
+
+ if (!(gfp_mask & __GFP_COMP))
+ goto done;
+ }
+
+ if (start == outer_start && end == outer_end && is_power_of_2(end - start)) {
struct page *head = pfn_to_page(start);
int order = ilog2(end - start);
_
Patches currently in -mm which might be from tujinjiang(a)huawei.com are
Hello,
On Sun, Apr 20, 2025 at 11:00:53AM -0400, Sasha Levin wrote:
> This is a note to let you know that I've just added the patch titled
>
> wifi: mac80211: Update skb's control block key in ieee80211_tx_dequeue()
>
> to the 6.14-stable tree which can be found at:
> http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=sum…
>
> The filename of the patch is:
> wifi-mac80211-update-skb-s-control-block-key-in-ieee.patch
> and it can be found in the queue-6.14 subdirectory.
>
> If you, or anyone else, feels it should not be added to the stable tree,
> please let <stable(a)vger.kernel.org> know about it.
>
Not sure this patch should go to stable. @Johannes haven't you revert
it in your tree ?
Thanks,
--
Remi
>
>
> commit 9209089b629b7c29ae393cded89e77c169f18dfb
> Author: Remi Pommarel <repk(a)triplefau.lt>
> Date: Mon Mar 24 17:28:20 2025 +0100
>
> wifi: mac80211: Update skb's control block key in ieee80211_tx_dequeue()
>
> [ Upstream commit a104042e2bf6528199adb6ca901efe7b60c2c27f ]
>
> The ieee80211 skb control block key (set when skb was queued) could have
> been removed before ieee80211_tx_dequeue() call. ieee80211_tx_dequeue()
> already called ieee80211_tx_h_select_key() to get the current key, but
> the latter do not update the key in skb control block in case it is
> NULL. Because some drivers actually use this key in their TX callbacks
> (e.g. ath1{1,2}k_mac_op_tx()) this could lead to the use after free
> below:
>
> BUG: KASAN: slab-use-after-free in ath11k_mac_op_tx+0x590/0x61c
> Read of size 4 at addr ffffff803083c248 by task kworker/u16:4/1440
>
> CPU: 3 UID: 0 PID: 1440 Comm: kworker/u16:4 Not tainted 6.13.0-ge128f627f404 #2
> Hardware name: HW (DT)
> Workqueue: bat_events batadv_send_outstanding_bcast_packet
> Call trace:
> show_stack+0x14/0x1c (C)
> dump_stack_lvl+0x58/0x74
> print_report+0x164/0x4c0
> kasan_report+0xac/0xe8
> __asan_report_load4_noabort+0x1c/0x24
> ath11k_mac_op_tx+0x590/0x61c
> ieee80211_handle_wake_tx_queue+0x12c/0x1c8
> ieee80211_queue_skb+0xdcc/0x1b4c
> ieee80211_tx+0x1ec/0x2bc
> ieee80211_xmit+0x224/0x324
> __ieee80211_subif_start_xmit+0x85c/0xcf8
> ieee80211_subif_start_xmit+0xc0/0xec4
> dev_hard_start_xmit+0xf4/0x28c
> __dev_queue_xmit+0x6ac/0x318c
> batadv_send_skb_packet+0x38c/0x4b0
> batadv_send_outstanding_bcast_packet+0x110/0x328
> process_one_work+0x578/0xc10
> worker_thread+0x4bc/0xc7c
> kthread+0x2f8/0x380
> ret_from_fork+0x10/0x20
>
> Allocated by task 1906:
> kasan_save_stack+0x28/0x4c
> kasan_save_track+0x1c/0x40
> kasan_save_alloc_info+0x3c/0x4c
> __kasan_kmalloc+0xac/0xb0
> __kmalloc_noprof+0x1b4/0x380
> ieee80211_key_alloc+0x3c/0xb64
> ieee80211_add_key+0x1b4/0x71c
> nl80211_new_key+0x2b4/0x5d8
> genl_family_rcv_msg_doit+0x198/0x240
> <...>
>
> Freed by task 1494:
> kasan_save_stack+0x28/0x4c
> kasan_save_track+0x1c/0x40
> kasan_save_free_info+0x48/0x94
> __kasan_slab_free+0x48/0x60
> kfree+0xc8/0x31c
> kfree_sensitive+0x70/0x80
> ieee80211_key_free_common+0x10c/0x174
> ieee80211_free_keys+0x188/0x46c
> ieee80211_stop_mesh+0x70/0x2cc
> ieee80211_leave_mesh+0x1c/0x60
> cfg80211_leave_mesh+0xe0/0x280
> cfg80211_leave+0x1e0/0x244
> <...>
>
> Reset SKB control block key before calling ieee80211_tx_h_select_key()
> to avoid that.
>
> Fixes: bb42f2d13ffc ("mac80211: Move reorder-sensitive TX handlers to after TXQ dequeue")
> Signed-off-by: Remi Pommarel <repk(a)triplefau.lt>
> Link: https://patch.msgid.link/06aa507b853ca385ceded81c18b0a6dd0f081bc8.174283338…
> Signed-off-by: Johannes Berg <johannes.berg(a)intel.com>
> Signed-off-by: Sasha Levin <sashal(a)kernel.org>
>
> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
> index a24636bda6793..0c6214f12ea39 100644
> --- a/net/mac80211/tx.c
> +++ b/net/mac80211/tx.c
> @@ -3893,6 +3893,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
> * The key can be removed while the packet was queued, so need to call
> * this here to get the current key.
> */
> + info->control.hw_key = NULL;
> r = ieee80211_tx_h_select_key(&tx);
> if (r != TX_CONTINUE) {
> ieee80211_free_txskb(&local->hw, skb);
According to the AD9832 datasheet (Table 10, D12 description), setting
the RESET bit forces the phase accumulator to zero, which corresponds to
a full-scale DC output, rather than disabling the output signal.
The correct way to disable the output and enter a low-power state is to
set the AD9832_SLEEP bit (Table 10, D13 description), which powers down
the internal DAC current sources and disables internal clocks.
Fixes: ea707584bac1 ("Staging: IIO: DDS: AD9832 / AD9835 driver")
Cc: stable(a)vger.kernel.org
Signed-off-by: Gabriel Shahrouzi <gshahrouzi(a)gmail.com>
---
drivers/staging/iio/frequency/ad9832.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index db42810c7664b..0872ff4ec4896 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -232,7 +232,7 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr,
st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP |
AD9832_CLR);
else
- st->ctrl_src |= AD9832_RESET;
+ st->ctrl_src |= AD9832_SLEEP;
st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
st->ctrl_src);
--
2.43.0
According to the AD9832 datasheet (Table 10, D12 description), setting
the RESET bit forces the phase accumulator to zero, which corresponds to
a full-scale DC output, rather than disabling the output signal.
The correct way to disable the output and enter a low-power state is to
set the AD9832_SLEEP bit (Table 10, D13 description), which powers down
the internal DAC current sources and disables internal clocks.
Fixes: ea707584bac1 ("Staging: IIO: DDS: AD9832 / AD9835 driver")
Cc: stable(a)vger.kernel.org
Signed-off-by: Gabriel Shahrouzi <gshahrouzi(a)gmail.com>
---
drivers/staging/iio/frequency/ad9832.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index db42810c7664b..0872ff4ec4896 100644
--- a/drivers/staging/iio/frequency/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -232,7 +232,7 @@ static ssize_t ad9832_write(struct device *dev, struct device_attribute *attr,
st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP |
AD9832_CLR);
else
- st->ctrl_src |= AD9832_RESET;
+ st->ctrl_src |= AD9832_SLEEP;
st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) |
st->ctrl_src);
--
2.43.0