[lkml]   [2017]   [Jul]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
SubjectProblem with commit bf22ff45bed664aefb5c4e43029057a199b7070c
Commit bf22ff45bed664aefb5c4e43029057a199b7070c ("genirq: Avoid
unnecessary low level irq function calls") breaks Xen guest
save/restore handling.

The main problem are the PV devices using Xen event channels as
interrupt sources which are represented as an "irq chip" in the kernel.
When saving the guest the event channels are masked internally. At
restore time event channels are re-established and unmasked via
irq_startup(). Unfortunately above commit will let the unmask operation
be a nop as the irq handling doesn't know about the masking done before.

I have a patch repairing the issue, but I'm not sure if this way to do
it would be accepted. I have exported mask_irq() and I'm doing the
masking now through this function. Would the attached patch be
acceptable? Or is there a better way to solve the problem?

diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 2e567d8433b3..79e82534a3c3 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -346,9 +346,17 @@ static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
static void xen_evtchn_mask_all(void)
unsigned int evtchn;
+ int irq;
+ struct irq_desc *desc;

- for (evtchn = 0; evtchn < xen_evtchn_nr_channels(); evtchn++)
- mask_evtchn(evtchn);
+ for (evtchn = 0; evtchn < xen_evtchn_nr_channels(); evtchn++) {
+ irq = get_evtchn_to_irq(evtchn);
+ desc = irq_to_desc(irq);
+ if (desc)
+ mask_irq(desc);
+ else
+ mask_evtchn(evtchn);
+ }

diff --git a/include/linux/irq.h b/include/linux/irq.h
index 00db35b61e9e..4b6ab670639a 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -509,6 +509,7 @@ extern int setup_irq(unsigned int irq, struct irqaction *new);
extern void remove_irq(unsigned int irq, struct irqaction *act);
extern int setup_percpu_irq(unsigned int irq, struct irqaction *new);
extern void remove_percpu_irq(unsigned int irq, struct irqaction *act);
+extern void mask_irq(struct irq_desc *desc);

extern void irq_cpu_online(void);
extern void irq_cpu_offline(void);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 2e30d925a40d..7e25a1ad2857 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -408,6 +408,7 @@ void mask_irq(struct irq_desc *desc)

void unmask_irq(struct irq_desc *desc)
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 9da14d125df4..5e2bc4d799af 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -81,7 +81,6 @@ extern void irq_enable(struct irq_desc *desc);
extern void irq_disable(struct irq_desc *desc);
extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
-extern void mask_irq(struct irq_desc *desc);
extern void unmask_irq(struct irq_desc *desc);
extern void unmask_threaded_irq(struct irq_desc *desc);
 \ /
  Last update: 2017-07-07 16:51    [W:0.065 / U:0.984 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site