[irqchip: irq/irqchip-next] irqchip/gic-v3-its: Unconditionally save/restore the ITS state on suspend

2020-11-23 Thread irqchip-bot for Xu Qiang
The following commit has been merged into the irq/irqchip-next branch of 
irqchip:

Commit-ID: 74cde1a53368aed4f2b4b54bf7030437f64a534b
Gitweb:
https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms/74cde1a53368aed4f2b4b54bf7030437f64a534b
Author:Xu Qiang 
AuthorDate:Sat, 07 Nov 2020 10:42:26 
Committer: Marc Zyngier 
CommitterDate: Sun, 22 Nov 2020 12:58:35 

irqchip/gic-v3-its: Unconditionally save/restore the ITS state on suspend

On systems without HW-based collections (i.e. anything except GIC-500),
we rely on firmware to perform the ITS save/restore. This doesn't
really work, as although FW can properly save everything, it cannot
fully restore the state of the command queue (the read-side is reset
to the head of the queue). This results in the ITS consuming previously
processed commands, potentially corrupting the state.

Instead, let's always save the ITS state on suspend, disabling it in the
process, and restore the full state on resume. This saves us from broken
FW as long as it doesn't enable the ITS by itself (for which we can't do
anything).

This amounts to simply dropping the ITS_FLAGS_SAVE_SUSPEND_STATE.

Signed-off-by: Xu Qiang 
[maz: added warning on resume, rewrote commit message]
Signed-off-by: Marc Zyngier 
Link: https://lore.kernel.org/r/20201107104226.14282-1-xuqian...@huawei.com
---
 drivers/irqchip/irq-gic-v3-its.c | 16 +++-
 1 file changed, 3 insertions(+), 13 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 0418071..0598c5c 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -42,7 +42,6 @@
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING  (1ULL << 0)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375  (1ULL << 1)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144  (1ULL << 2)
-#define ITS_FLAGS_SAVE_SUSPEND_STATE   (1ULL << 3)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING(1 << 0)
 #define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
@@ -4741,9 +4740,6 @@ static int its_save_disable(void)
list_for_each_entry(its, _nodes, entry) {
void __iomem *base;
 
-   if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-   continue;
-
base = its->base;
its->ctlr_save = readl_relaxed(base + GITS_CTLR);
err = its_force_quiescent(base);
@@ -4762,9 +4758,6 @@ err:
list_for_each_entry_continue_reverse(its, _nodes, entry) {
void __iomem *base;
 
-   if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-   continue;
-
base = its->base;
writel_relaxed(its->ctlr_save, base + GITS_CTLR);
}
@@ -4784,9 +4777,6 @@ static void its_restore_enable(void)
void __iomem *base;
int i;
 
-   if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-   continue;
-
base = its->base;
 
/*
@@ -4794,7 +4784,10 @@ static void its_restore_enable(void)
 * don't restore it since writing to CBASER or BASER
 * registers is undefined according to the GIC v3 ITS
 * Specification.
+*
+* Firmware resuming with the ITS enabled is terminally broken.
 */
+   WARN_ON(readl_relaxed(base + GITS_CTLR) & GITS_CTLR_ENABLE);
ret = its_force_quiescent(base);
if (ret) {
pr_err("ITS@%pa: failed to quiesce on resume: %d\n",
@@ -5074,9 +5067,6 @@ static int __init its_probe_one(struct resource *res,
ctlr |= GITS_CTLR_ImDe;
writel_relaxed(ctlr, its->base + GITS_CTLR);
 
-   if (GITS_TYPER_HCC(typer))
-   its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
-
err = its_init_domain(handle, its);
if (err)
goto out_free_tables;


[PATCH -next] panic: complete the flush of the hard deadlock log messages to the serial port

2020-11-23 Thread Xu Qiang
when hardlockup_all_cpu_backtrace is on, and there are
a large number of cores in the system, it takes
a long time to output the hard deadlock logs of all cores
to the serial port. When the console_flush_on_panic function
in panic is executed, console_locked is still held.
As a result, garbled characters are displayed in the serial port log.

To solve this problem, wait for a maximum of 10s for the serial port
to be released before console_flush_on_panic.

Signed-off-by: Xu Qiang 
---
 kernel/panic.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/kernel/panic.c b/kernel/panic.c
index 332736a72a58..0014788e8141 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -301,6 +301,14 @@ void panic(const char *fmt, ...)
 * panic() is not being callled from OOPS.
 */
debug_locks_off();
+
+   /* Wait for all CPUs to complete console_unlock */
+   for (i = 0; i < 10 * 1000; i++) {
+   if (console_trylock())
+   break;
+   mdelay(1);
+   }
+
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
 
panic_print_sys_info();
-- 
2.25.0



[PATCH -next] irq-chip/gic-v3-its: Fixed an issue where the ITS executes the residual commands in the queue again when the ITS wakes up from sleep mode.

2020-11-07 Thread Xu Qiang
On my platform, ITS_FLAGS_SAVE_SUSPEND_STATE is not set,thus do nothing
in its suspend and resuse function.On the other hand,firmware stores
GITS_CTRL,GITS_CBASER,GITS_CWRITER and GITS_BASER in the suspend,
and restores these registers in the resume. As a result, the ITS executes
the residual commands in the queue.

Memory corruption may occur in the following scenarios:

The kernel sends three commands in the following sequence:
1.mapd(deviceA, ITT_addr1, valid:1)
2.mapti(deviceA):ITS write ITT_addr1 memory;
3.mapd(deviceA, ITT_addr1, valid:0) and kfree(ITT_addr1);
4.mapd(deviceA, ITT_addr2, valid:1);
5.mapti(deviceA):ITS write ITT_addr2 memory;

To solve this problem,dropping the checks for ITS_FLAGS_SAVE_SUSPEND_STATE.

Signed-off-by: Xu Qiang 
---
 drivers/irqchip/irq-gic-v3-its.c | 13 -
 1 file changed, 13 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 0fec31931e11..06f2c1c252b9 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -42,7 +42,6 @@
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING  (1ULL << 0)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_22375  (1ULL << 1)
 #define ITS_FLAGS_WORKAROUND_CAVIUM_23144  (1ULL << 2)
-#define ITS_FLAGS_SAVE_SUSPEND_STATE   (1ULL << 3)
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING(1 << 0)
 #define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1)
@@ -4741,9 +4740,6 @@ static int its_save_disable(void)
list_for_each_entry(its, _nodes, entry) {
void __iomem *base;
 
-   if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-   continue;
-
base = its->base;
its->ctlr_save = readl_relaxed(base + GITS_CTLR);
err = its_force_quiescent(base);
@@ -4762,9 +4758,6 @@ static int its_save_disable(void)
list_for_each_entry_continue_reverse(its, _nodes, entry) {
void __iomem *base;
 
-   if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-   continue;
-
base = its->base;
writel_relaxed(its->ctlr_save, base + GITS_CTLR);
}
@@ -4784,9 +4777,6 @@ static void its_restore_enable(void)
void __iomem *base;
int i;
 
-   if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
-   continue;
-
base = its->base;
 
/*
@@ -5074,9 +5064,6 @@ static int __init its_probe_one(struct resource *res,
ctlr |= GITS_CTLR_ImDe;
writel_relaxed(ctlr, its->base + GITS_CTLR);
 
-   if (GITS_TYPER_HCC(typer))
-   its->flags |= ITS_FLAGS_SAVE_SUSPEND_STATE;
-
err = its_init_domain(handle, its);
if (err)
goto out_free_tables;
-- 
2.25.0



[PATCH -next] irq-chip/gic-v3-its: Fixed an issue where the ITS executes the residual commands in the queue again when the ITS wakes up from sleep mode.

2020-11-03 Thread Xu Qiang
During wakeup, the ATF restore interface restores the values of
the cbaser and cwriter registers. As a result, the ITS executes
the residual commands in the queue, which may cause memory corruption.

To solve this problem, clear all data in the command queue
in the suspend interface of the ITS driver.

Signed-off-by: Xu Qiang 
---
 drivers/irqchip/irq-gic-v3-its.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 0fec31931e11..b8487f78ac21 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -4741,6 +4741,14 @@ static int its_save_disable(void)
list_for_each_entry(its, _nodes, entry) {
void __iomem *base;
 
+   /*
+* Clear the command queue so that the ITS will not re-execute
+* the remaining commands in the command queue when
+* the cwriter and cbaser registers are restored
+* in the restore interface of the firmware.
+*/
+   memset(its->cmd_base, 0, ITS_CMD_QUEUE_SZ);
+
if (!(its->flags & ITS_FLAGS_SAVE_SUSPEND_STATE))
continue;
 
-- 
2.25.0



[PATCH -next] kernel/watchdog_hld.c: Complete the flush of the hard deadlock log messages to the serial port

2020-11-01 Thread Xu Qiang
when hardlockup_all_cpu_backtrace is on, and there are
a large number of cores in the system, it takes
a long time to output the hard deadlock logs of all cores
to the serial port. When the console_flush_on_panic function
in panic is executed, console_locked is still held.
As a result, garbled characters are displayed in the serial port log.

To solve this problem, wait for a maximum of 10s for the serial port
to be released before entering the panic mode.

Signed-off-by: Xu Qiang 
---
 kernel/watchdog_hld.c | 13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/kernel/watchdog_hld.c b/kernel/watchdog_hld.c
index a546bc54f6ff..d3410b9fd3c3 100644
--- a/kernel/watchdog_hld.c
+++ b/kernel/watchdog_hld.c
@@ -13,8 +13,10 @@
 #define pr_fmt(fmt) "NMI watchdog: " fmt
 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -129,6 +131,7 @@ static void watchdog_overflow_callback(struct perf_event 
*event,
 * then this is a good indication the cpu is stuck
 */
if (is_hardlockup()) {
+   int i;
int this_cpu = smp_processor_id();
 
/* only print hardlockups once */
@@ -151,9 +154,15 @@ static void watchdog_overflow_callback(struct perf_event 
*event,
if (sysctl_hardlockup_all_cpu_backtrace &&
!test_and_set_bit(0, _allcpu_dumped))
trigger_allbutself_cpu_backtrace();
-
-   if (hardlockup_panic)
+   if (hardlockup_panic) {
+   /* Wait for all CPUs to complete 
wake_up_klogd_work_func */
+   for (i = 0; i < 10 * 1000; i++) {
+   if (console_trylock())
+   break;
+   mdelay(1);
+   }
nmi_panic(regs, "Hard LOCKUP");
+   }
atomic_inc(_detected);
 
__this_cpu_write(hard_watchdog_warn, true);
-- 
2.25.0



[PATCH] drm/vkms: Fix soft lockup.

2020-07-28 Thread Xu Qiang
asm/irq_stack.h:48 [inline]
 do_softirq_own_stack+0x5a/0x70 arch/x86/kernel/irq_64.c:77
 invoke_softirq kernel/softirq.c:387 [inline]
 __irq_exit_rcu kernel/softirq.c:417 [inline]
 irq_exit_rcu+0xb1/0xd0 kernel/softirq.c:429
 sysvec_apic_timer_interrupt+0x42/0xd0 arch/x86/kernel/apic/apic.c:1091
 asm_sysvec_apic_timer_interrupt+0x12/0x20 arch/x86/include/asm/idtentry.h:596
[ cut here ]
WARNING: CPU: 5 PID: 8121 at drivers/gpu/drm/vkms/vkms_crtc.c:21 
vkms_vblank_simulate+0x19a/0x1b0 drivers/gpu/drm/vkms/vkms_crtc.c:21
Modules linked in:
CPU: 5 PID: 8121 Comm: syslog-ng Tainted: GW 5.8.0-rc2-csan #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 
Ubuntu-1.8.2-1ubuntu1 04/01/2014
RIP: 0010:vkms_vblank_simulate+0x19a/0x1b0 drivers/gpu/drm/vkms/vkms_crtc.c:21
RSP: 0018:c9184ee8 EFLAGS: 00010046
RAX: 88822864a080 RBX: 88822ecb8fb0 RCX: 826cd2b0
RDX: 8001 RSI: 826cd40a RDI: 0007
RBP: 001f058d R08: 88822864a080 R09: 7fff
R10:  R11:  R12: 88822ecb8630
R13:  R14: 017998a35917 R15: 888237d5ed80
FS:  7f8dcbde0700() GS:888237d4() knlGS:
CS:  0010 DS:  ES:  CR0: 80050033
CR2: ff600400 CR3: 00022575f002 CR4: 000626e0
Call Trace:
 
 __run_hrtimer kernel/time/hrtimer.c:1520 [inline]
 __hrtimer_run_queues+0x14c/0x410 kernel/time/hrtimer.c:1584
 hrtimer_interrupt+0x141/0x2c0 kernel/time/hrtimer.c:1646
 local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1080 [inline]
 __sysvec_apic_timer_interrupt+0x6e/0x170 arch/x86/kernel/apic/apic.c:1097
 asm_call_on_stack+0xf/0x20 arch/x86/entry/entry_64.S:711
 
 __run_on_irqstack arch/x86/include/asm/irq_stack.h:22 [inline]
 run_on_irqstack_cond arch/x86/include/asm/irq_stack.h:48 [inline]
 sysvec_apic_timer_interrupt+0xa9/0xd0 arch/x86/kernel/apic/apic.c:1091
 asm_sysvec_apic_timer_interrupt+0x12/0x20 arch/x86/include/asm/idtentry.h:596
RIP: 0010:con_should_update drivers/tty/vt/vt.c:291 [inline]
RIP: 0010:do_con_write.part.0+0xad6/0xfa0 drivers/tty/vt/vt.c:2790
---[ end trace d6a6c6a9ecb73597 ]---
NMI backtrace for cpu 5 skipped: idling at native_halt+0xd/0x10 
arch/x86/include/asm/irqflags.h:66

Cc: sta...@vger.kernel.org
Reported-by: Hulk Robot 
Signed-off-by: Xu Qiang 
---
 drivers/gpu/drm/vkms/vkms_crtc.c | 5 -
 drivers/gpu/drm/vkms/vkms_drv.h  | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index ac85e17428f8..655294f11bb8 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -49,7 +49,7 @@ static enum hrtimer_restart vkms_vblank_simulate(struct 
hrtimer *timer)
DRM_DEBUG_DRIVER("Composer worker already queued\n");
}
 
-   return HRTIMER_RESTART;
+   return output->hrtimer_exit ? HRTIMER_NORESTART : HRTIMER_RESTART;
 }
 
 static int vkms_enable_vblank(struct drm_crtc *crtc)
@@ -66,6 +66,8 @@ static int vkms_enable_vblank(struct drm_crtc *crtc)
out->period_ns = ktime_set(0, vblank->framedur_ns);
hrtimer_start(>vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL);
 
+   out->hrtimer_exit = false;
+
return 0;
 }
 
@@ -73,6 +75,7 @@ static void vkms_disable_vblank(struct drm_crtc *crtc)
 {
struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
 
+   out->hrtimer_exit = true;
hrtimer_cancel(>vblank_hrtimer);
 }
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index f4036bb0b9a8..4d4323dc2cfd 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -65,6 +65,7 @@ struct vkms_output {
struct drm_connector connector;
struct hrtimer vblank_hrtimer;
ktime_t period_ns;
+   boolhrtimer_exit;
struct drm_pending_vblank_event *event;
/* ordered wq for composer_work */
struct workqueue_struct *composer_workq;
-- 
2.25.0



[PATCH -next] gpu: drm: Fix spinlock vblank_time_lock use error.

2020-07-21 Thread Xu Qiang
The drm_handle_vblank function is in the interrupt context.
Therefore, the spin lock vblank_time_lock is obtained
from the interrupt context.

Cc: 
Signed-off-by: Xu Qiang 
---
 drivers/gpu/drm/drm_vblank.c | 17 ++---
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c
index f402c75b9d34..4ca63ff33a43 100644
--- a/drivers/gpu/drm/drm_vblank.c
+++ b/drivers/gpu/drm/drm_vblank.c
@@ -229,10 +229,11 @@ static void drm_reset_vblank_timestamp(struct drm_device 
*dev, unsigned int pipe
 {
u32 cur_vblank;
bool rc;
+   unsigned long irqflags;
ktime_t t_vblank;
int count = DRM_TIMESTAMP_MAXRETRIES;
 
-   spin_lock(>vblank_time_lock);
+   spin_lock_irqsave(>vblank_time_lock, irqflags);
 
/*
 * sample the current counter to avoid random jumps
@@ -257,7 +258,7 @@ static void drm_reset_vblank_timestamp(struct drm_device 
*dev, unsigned int pipe
 */
store_vblank(dev, pipe, 1, t_vblank, cur_vblank);
 
-   spin_unlock(>vblank_time_lock);
+   spin_unlock_irqrestore(>vblank_time_lock, irqflags);
 }
 
 /*
@@ -1106,11 +1107,12 @@ static int __enable_vblank(struct drm_device *dev, 
unsigned int pipe)
 static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe)
 {
struct drm_vblank_crtc *vblank = >vblank[pipe];
+   unsigned long irqflags;
int ret = 0;
 
assert_spin_locked(>vbl_lock);
 
-   spin_lock(>vblank_time_lock);
+   spin_lock_irqsave(>vblank_time_lock, irqflags);
 
if (!vblank->enabled) {
/*
@@ -1136,7 +1138,7 @@ static int drm_vblank_enable(struct drm_device *dev, 
unsigned int pipe)
}
}
 
-   spin_unlock(>vblank_time_lock);
+   spin_unlock_irqrestore(>vblank_time_lock, irqflags);
 
return ret;
 }
@@ -1917,6 +1919,7 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned 
int pipe)
 {
struct drm_vblank_crtc *vblank = >vblank[pipe];
unsigned long irqflags;
+   unsigned long irqflags_vblank;
bool disable_irq;
 
if (drm_WARN_ON_ONCE(dev, !drm_dev_has_vblank(dev)))
@@ -1931,18 +1934,18 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned 
int pipe)
 * vblank enable/disable, as this would cause inconsistent
 * or corrupted timestamps and vblank counts.
 */
-   spin_lock(>vblank_time_lock);
+   spin_lock_irqsave(>vblank_time_lock, irqflags_vblank);
 
/* Vblank irq handling disabled. Nothing to do. */
if (!vblank->enabled) {
-   spin_unlock(>vblank_time_lock);
+   spin_unlock_irqrestore(>vblank_time_lock, irqflags_vblank);
spin_unlock_irqrestore(>event_lock, irqflags);
return false;
}
 
drm_update_vblank_count(dev, pipe, true);
 
-   spin_unlock(>vblank_time_lock);
+   spin_unlock_irqrestore(>vblank_time_lock, irqflags_vblank);
 
wake_up(>queue);
 
-- 
2.25.0