| From 7beb290caa2adb0a399e735a1e175db9aae0523a Mon Sep 17 00:00:00 2001 |
| From: Juergen Gross <jgross@suse.com> |
| Date: Sun, 13 Sep 2020 14:23:02 +0200 |
| Subject: xen/events: use a common cpu hotplug hook for event channels |
| |
| From: Juergen Gross <jgross@suse.com> |
| |
| commit 7beb290caa2adb0a399e735a1e175db9aae0523a upstream. |
| |
| Today only fifo event channels have a cpu hotplug callback. In order |
| to prepare for more percpu (de)init work move that callback into |
| events_base.c and add percpu_init() and percpu_deinit() hooks to |
| struct evtchn_ops. |
| |
| This is part of XSA-332. |
| |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Juergen Gross <jgross@suse.com> |
| Reviewed-by: Jan Beulich <jbeulich@suse.com> |
| Reviewed-by: Wei Liu <wl@xen.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/xen/events/events_base.c | 25 +++++++++++++++++++++ |
| drivers/xen/events/events_fifo.c | 40 ++++++++++++++++------------------- |
| drivers/xen/events/events_internal.h | 3 ++ |
| 3 files changed, 47 insertions(+), 21 deletions(-) |
| |
| --- a/drivers/xen/events/events_base.c |
| +++ b/drivers/xen/events/events_base.c |
| @@ -34,6 +34,7 @@ |
| #include <linux/irqnr.h> |
| #include <linux/pci.h> |
| #include <linux/spinlock.h> |
| +#include <linux/cpuhotplug.h> |
| |
| #ifdef CONFIG_X86 |
| #include <asm/desc.h> |
| @@ -1830,6 +1831,26 @@ static inline void xen_alloc_callback_ve |
| static bool fifo_events = true; |
| module_param(fifo_events, bool, 0); |
| |
| +static int xen_evtchn_cpu_prepare(unsigned int cpu) |
| +{ |
| + int ret = 0; |
| + |
| + if (evtchn_ops->percpu_init) |
| + ret = evtchn_ops->percpu_init(cpu); |
| + |
| + return ret; |
| +} |
| + |
| +static int xen_evtchn_cpu_dead(unsigned int cpu) |
| +{ |
| + int ret = 0; |
| + |
| + if (evtchn_ops->percpu_deinit) |
| + ret = evtchn_ops->percpu_deinit(cpu); |
| + |
| + return ret; |
| +} |
| + |
| void __init xen_init_IRQ(void) |
| { |
| int ret = -EINVAL; |
| @@ -1840,6 +1861,10 @@ void __init xen_init_IRQ(void) |
| if (ret < 0) |
| xen_evtchn_2l_init(); |
| |
| + cpuhp_setup_state_nocalls(CPUHP_XEN_EVTCHN_PREPARE, |
| + "xen/evtchn:prepare", |
| + xen_evtchn_cpu_prepare, xen_evtchn_cpu_dead); |
| + |
| evtchn_to_irq = kcalloc(EVTCHN_ROW(xen_evtchn_max_channels()), |
| sizeof(*evtchn_to_irq), GFP_KERNEL); |
| BUG_ON(!evtchn_to_irq); |
| --- a/drivers/xen/events/events_fifo.c |
| +++ b/drivers/xen/events/events_fifo.c |
| @@ -385,21 +385,6 @@ static void evtchn_fifo_resume(void) |
| event_array_pages = 0; |
| } |
| |
| -static const struct evtchn_ops evtchn_ops_fifo = { |
| - .max_channels = evtchn_fifo_max_channels, |
| - .nr_channels = evtchn_fifo_nr_channels, |
| - .setup = evtchn_fifo_setup, |
| - .bind_to_cpu = evtchn_fifo_bind_to_cpu, |
| - .clear_pending = evtchn_fifo_clear_pending, |
| - .set_pending = evtchn_fifo_set_pending, |
| - .is_pending = evtchn_fifo_is_pending, |
| - .test_and_set_mask = evtchn_fifo_test_and_set_mask, |
| - .mask = evtchn_fifo_mask, |
| - .unmask = evtchn_fifo_unmask, |
| - .handle_events = evtchn_fifo_handle_events, |
| - .resume = evtchn_fifo_resume, |
| -}; |
| - |
| static int evtchn_fifo_alloc_control_block(unsigned cpu) |
| { |
| void *control_block = NULL; |
| @@ -422,19 +407,36 @@ static int evtchn_fifo_alloc_control_blo |
| return ret; |
| } |
| |
| -static int xen_evtchn_cpu_prepare(unsigned int cpu) |
| +static int evtchn_fifo_percpu_init(unsigned int cpu) |
| { |
| if (!per_cpu(cpu_control_block, cpu)) |
| return evtchn_fifo_alloc_control_block(cpu); |
| return 0; |
| } |
| |
| -static int xen_evtchn_cpu_dead(unsigned int cpu) |
| +static int evtchn_fifo_percpu_deinit(unsigned int cpu) |
| { |
| __evtchn_fifo_handle_events(cpu, true); |
| return 0; |
| } |
| |
| +static const struct evtchn_ops evtchn_ops_fifo = { |
| + .max_channels = evtchn_fifo_max_channels, |
| + .nr_channels = evtchn_fifo_nr_channels, |
| + .setup = evtchn_fifo_setup, |
| + .bind_to_cpu = evtchn_fifo_bind_to_cpu, |
| + .clear_pending = evtchn_fifo_clear_pending, |
| + .set_pending = evtchn_fifo_set_pending, |
| + .is_pending = evtchn_fifo_is_pending, |
| + .test_and_set_mask = evtchn_fifo_test_and_set_mask, |
| + .mask = evtchn_fifo_mask, |
| + .unmask = evtchn_fifo_unmask, |
| + .handle_events = evtchn_fifo_handle_events, |
| + .resume = evtchn_fifo_resume, |
| + .percpu_init = evtchn_fifo_percpu_init, |
| + .percpu_deinit = evtchn_fifo_percpu_deinit, |
| +}; |
| + |
| int __init xen_evtchn_fifo_init(void) |
| { |
| int cpu = smp_processor_id(); |
| @@ -448,9 +450,5 @@ int __init xen_evtchn_fifo_init(void) |
| |
| evtchn_ops = &evtchn_ops_fifo; |
| |
| - cpuhp_setup_state_nocalls(CPUHP_XEN_EVTCHN_PREPARE, |
| - "xen/evtchn:prepare", |
| - xen_evtchn_cpu_prepare, xen_evtchn_cpu_dead); |
| - |
| return ret; |
| } |
| --- a/drivers/xen/events/events_internal.h |
| +++ b/drivers/xen/events/events_internal.h |
| @@ -69,6 +69,9 @@ struct evtchn_ops { |
| |
| void (*handle_events)(unsigned cpu); |
| void (*resume)(void); |
| + |
| + int (*percpu_init)(unsigned int cpu); |
| + int (*percpu_deinit)(unsigned int cpu); |
| }; |
| |
| extern const struct evtchn_ops *evtchn_ops; |