Skip to content

Commit 25da461

Browse files
jgross1bostrovs
authored andcommitted
xen/events: don't unmask an event channel when an eoi is pending
An event channel should be kept masked when an eoi is pending for it. When being migrated to another cpu it might be unmasked, though. In order to avoid this keep three different flags for each event channel to be able to distinguish "normal" masking/unmasking from eoi related masking/unmasking and temporary masking. The event channel should only be able to generate an interrupt if all flags are cleared. Cc: [email protected] Fixes: 54c9de8 ("xen/events: add a new "late EOI" evtchn framework") Reported-by: Julien Grall <[email protected]> Signed-off-by: Juergen Gross <[email protected]> Reviewed-by: Julien Grall <[email protected]> Reviewed-by: Boris Ostrovsky <[email protected]> Tested-by: Ross Lagerwall <[email protected]> Link: https://lore.kernel.org/r/[email protected] [boris -- corrected Fixed tag format] Signed-off-by: Boris Ostrovsky <[email protected]>
1 parent 9e77d96 commit 25da461

File tree

4 files changed

+80
-41
lines changed

4 files changed

+80
-41
lines changed

drivers/xen/events/events_2l.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,6 @@ static bool evtchn_2l_is_pending(evtchn_port_t port)
7777
return sync_test_bit(port, BM(&s->evtchn_pending[0]));
7878
}
7979

80-
static bool evtchn_2l_test_and_set_mask(evtchn_port_t port)
81-
{
82-
struct shared_info *s = HYPERVISOR_shared_info;
83-
return sync_test_and_set_bit(port, BM(&s->evtchn_mask[0]));
84-
}
85-
8680
static void evtchn_2l_mask(evtchn_port_t port)
8781
{
8882
struct shared_info *s = HYPERVISOR_shared_info;
@@ -376,7 +370,6 @@ static const struct evtchn_ops evtchn_ops_2l = {
376370
.clear_pending = evtchn_2l_clear_pending,
377371
.set_pending = evtchn_2l_set_pending,
378372
.is_pending = evtchn_2l_is_pending,
379-
.test_and_set_mask = evtchn_2l_test_and_set_mask,
380373
.mask = evtchn_2l_mask,
381374
.unmask = evtchn_2l_unmask,
382375
.handle_events = evtchn_2l_handle_events,

drivers/xen/events/events_base.c

Lines changed: 80 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,18 @@ struct irq_info {
9898
short refcnt;
9999
u8 spurious_cnt;
100100
u8 is_accounted;
101-
enum xen_irq_type type; /* type */
101+
short type; /* type: IRQT_* */
102+
u8 mask_reason; /* Why is event channel masked */
103+
#define EVT_MASK_REASON_EXPLICIT 0x01
104+
#define EVT_MASK_REASON_TEMPORARY 0x02
105+
#define EVT_MASK_REASON_EOI_PENDING 0x04
102106
unsigned irq;
103107
evtchn_port_t evtchn; /* event channel */
104108
unsigned short cpu; /* cpu bound */
105109
unsigned short eoi_cpu; /* EOI must happen on this cpu-1 */
106110
unsigned int irq_epoch; /* If eoi_cpu valid: irq_epoch of event */
107111
u64 eoi_time; /* Time in jiffies when to EOI. */
112+
spinlock_t lock;
108113

109114
union {
110115
unsigned short virq;
@@ -154,6 +159,7 @@ static DEFINE_RWLOCK(evtchn_rwlock);
154159
* evtchn_rwlock
155160
* IRQ-desc lock
156161
* percpu eoi_list_lock
162+
* irq_info->lock
157163
*/
158164

159165
static LIST_HEAD(xen_irq_list_head);
@@ -304,6 +310,8 @@ static int xen_irq_info_common_setup(struct irq_info *info,
304310
info->irq = irq;
305311
info->evtchn = evtchn;
306312
info->cpu = cpu;
313+
info->mask_reason = EVT_MASK_REASON_EXPLICIT;
314+
spin_lock_init(&info->lock);
307315

308316
ret = set_evtchn_to_irq(evtchn, irq);
309317
if (ret < 0)
@@ -459,6 +467,34 @@ unsigned int cpu_from_evtchn(evtchn_port_t evtchn)
459467
return ret;
460468
}
461469

470+
static void do_mask(struct irq_info *info, u8 reason)
471+
{
472+
unsigned long flags;
473+
474+
spin_lock_irqsave(&info->lock, flags);
475+
476+
if (!info->mask_reason)
477+
mask_evtchn(info->evtchn);
478+
479+
info->mask_reason |= reason;
480+
481+
spin_unlock_irqrestore(&info->lock, flags);
482+
}
483+
484+
static void do_unmask(struct irq_info *info, u8 reason)
485+
{
486+
unsigned long flags;
487+
488+
spin_lock_irqsave(&info->lock, flags);
489+
490+
info->mask_reason &= ~reason;
491+
492+
if (!info->mask_reason)
493+
unmask_evtchn(info->evtchn);
494+
495+
spin_unlock_irqrestore(&info->lock, flags);
496+
}
497+
462498
#ifdef CONFIG_X86
463499
static bool pirq_check_eoi_map(unsigned irq)
464500
{
@@ -605,7 +641,7 @@ static void xen_irq_lateeoi_locked(struct irq_info *info, bool spurious)
605641
}
606642

607643
info->eoi_time = 0;
608-
unmask_evtchn(evtchn);
644+
do_unmask(info, EVT_MASK_REASON_EOI_PENDING);
609645
}
610646

611647
static void xen_irq_lateeoi_worker(struct work_struct *work)
@@ -850,7 +886,8 @@ static unsigned int __startup_pirq(unsigned int irq)
850886
goto err;
851887

852888
out:
853-
unmask_evtchn(evtchn);
889+
do_unmask(info, EVT_MASK_REASON_EXPLICIT);
890+
854891
eoi_pirq(irq_get_irq_data(irq));
855892

856893
return 0;
@@ -877,7 +914,7 @@ static void shutdown_pirq(struct irq_data *data)
877914
if (!VALID_EVTCHN(evtchn))
878915
return;
879916

880-
mask_evtchn(evtchn);
917+
do_mask(info, EVT_MASK_REASON_EXPLICIT);
881918
xen_evtchn_close(evtchn);
882919
xen_irq_info_cleanup(info);
883920
}
@@ -1721,10 +1758,10 @@ void rebind_evtchn_irq(evtchn_port_t evtchn, int irq)
17211758
}
17221759

17231760
/* Rebind an evtchn so that it gets delivered to a specific cpu */
1724-
static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
1761+
static int xen_rebind_evtchn_to_cpu(struct irq_info *info, unsigned int tcpu)
17251762
{
17261763
struct evtchn_bind_vcpu bind_vcpu;
1727-
int masked;
1764+
evtchn_port_t evtchn = info ? info->evtchn : 0;
17281765

17291766
if (!VALID_EVTCHN(evtchn))
17301767
return -1;
@@ -1740,7 +1777,7 @@ static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
17401777
* Mask the event while changing the VCPU binding to prevent
17411778
* it being delivered on an unexpected VCPU.
17421779
*/
1743-
masked = test_and_set_mask(evtchn);
1780+
do_mask(info, EVT_MASK_REASON_TEMPORARY);
17441781

17451782
/*
17461783
* If this fails, it usually just indicates that we're dealing with a
@@ -1750,8 +1787,7 @@ static int xen_rebind_evtchn_to_cpu(evtchn_port_t evtchn, unsigned int tcpu)
17501787
if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
17511788
bind_evtchn_to_cpu(evtchn, tcpu, false);
17521789

1753-
if (!masked)
1754-
unmask_evtchn(evtchn);
1790+
do_unmask(info, EVT_MASK_REASON_TEMPORARY);
17551791

17561792
return 0;
17571793
}
@@ -1790,7 +1826,7 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
17901826
unsigned int tcpu = select_target_cpu(dest);
17911827
int ret;
17921828

1793-
ret = xen_rebind_evtchn_to_cpu(evtchn_from_irq(data->irq), tcpu);
1829+
ret = xen_rebind_evtchn_to_cpu(info_for_irq(data->irq), tcpu);
17941830
if (!ret)
17951831
irq_data_update_effective_affinity(data, cpumask_of(tcpu));
17961832

@@ -1799,18 +1835,20 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest,
17991835

18001836
static void enable_dynirq(struct irq_data *data)
18011837
{
1802-
evtchn_port_t evtchn = evtchn_from_irq(data->irq);
1838+
struct irq_info *info = info_for_irq(data->irq);
1839+
evtchn_port_t evtchn = info ? info->evtchn : 0;
18031840

18041841
if (VALID_EVTCHN(evtchn))
1805-
unmask_evtchn(evtchn);
1842+
do_unmask(info, EVT_MASK_REASON_EXPLICIT);
18061843
}
18071844

18081845
static void disable_dynirq(struct irq_data *data)
18091846
{
1810-
evtchn_port_t evtchn = evtchn_from_irq(data->irq);
1847+
struct irq_info *info = info_for_irq(data->irq);
1848+
evtchn_port_t evtchn = info ? info->evtchn : 0;
18111849

18121850
if (VALID_EVTCHN(evtchn))
1813-
mask_evtchn(evtchn);
1851+
do_mask(info, EVT_MASK_REASON_EXPLICIT);
18141852
}
18151853

18161854
static void ack_dynirq(struct irq_data *data)
@@ -1829,18 +1867,39 @@ static void mask_ack_dynirq(struct irq_data *data)
18291867
ack_dynirq(data);
18301868
}
18311869

1870+
static void lateeoi_ack_dynirq(struct irq_data *data)
1871+
{
1872+
struct irq_info *info = info_for_irq(data->irq);
1873+
evtchn_port_t evtchn = info ? info->evtchn : 0;
1874+
1875+
if (VALID_EVTCHN(evtchn)) {
1876+
do_mask(info, EVT_MASK_REASON_EOI_PENDING);
1877+
clear_evtchn(evtchn);
1878+
}
1879+
}
1880+
1881+
static void lateeoi_mask_ack_dynirq(struct irq_data *data)
1882+
{
1883+
struct irq_info *info = info_for_irq(data->irq);
1884+
evtchn_port_t evtchn = info ? info->evtchn : 0;
1885+
1886+
if (VALID_EVTCHN(evtchn)) {
1887+
do_mask(info, EVT_MASK_REASON_EXPLICIT);
1888+
clear_evtchn(evtchn);
1889+
}
1890+
}
1891+
18321892
static int retrigger_dynirq(struct irq_data *data)
18331893
{
1834-
evtchn_port_t evtchn = evtchn_from_irq(data->irq);
1835-
int masked;
1894+
struct irq_info *info = info_for_irq(data->irq);
1895+
evtchn_port_t evtchn = info ? info->evtchn : 0;
18361896

18371897
if (!VALID_EVTCHN(evtchn))
18381898
return 0;
18391899

1840-
masked = test_and_set_mask(evtchn);
1900+
do_mask(info, EVT_MASK_REASON_TEMPORARY);
18411901
set_evtchn(evtchn);
1842-
if (!masked)
1843-
unmask_evtchn(evtchn);
1902+
do_unmask(info, EVT_MASK_REASON_TEMPORARY);
18441903

18451904
return 1;
18461905
}
@@ -2054,8 +2113,8 @@ static struct irq_chip xen_lateeoi_chip __read_mostly = {
20542113
.irq_mask = disable_dynirq,
20552114
.irq_unmask = enable_dynirq,
20562115

2057-
.irq_ack = mask_ack_dynirq,
2058-
.irq_mask_ack = mask_ack_dynirq,
2116+
.irq_ack = lateeoi_ack_dynirq,
2117+
.irq_mask_ack = lateeoi_mask_ack_dynirq,
20592118

20602119
.irq_set_affinity = set_affinity_irq,
20612120
.irq_retrigger = retrigger_dynirq,

drivers/xen/events/events_fifo.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -209,12 +209,6 @@ static bool evtchn_fifo_is_pending(evtchn_port_t port)
209209
return sync_test_bit(EVTCHN_FIFO_BIT(PENDING, word), BM(word));
210210
}
211211

212-
static bool evtchn_fifo_test_and_set_mask(evtchn_port_t port)
213-
{
214-
event_word_t *word = event_word_from_port(port);
215-
return sync_test_and_set_bit(EVTCHN_FIFO_BIT(MASKED, word), BM(word));
216-
}
217-
218212
static void evtchn_fifo_mask(evtchn_port_t port)
219213
{
220214
event_word_t *word = event_word_from_port(port);
@@ -423,7 +417,6 @@ static const struct evtchn_ops evtchn_ops_fifo = {
423417
.clear_pending = evtchn_fifo_clear_pending,
424418
.set_pending = evtchn_fifo_set_pending,
425419
.is_pending = evtchn_fifo_is_pending,
426-
.test_and_set_mask = evtchn_fifo_test_and_set_mask,
427420
.mask = evtchn_fifo_mask,
428421
.unmask = evtchn_fifo_unmask,
429422
.handle_events = evtchn_fifo_handle_events,

drivers/xen/events/events_internal.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ struct evtchn_ops {
2121
void (*clear_pending)(evtchn_port_t port);
2222
void (*set_pending)(evtchn_port_t port);
2323
bool (*is_pending)(evtchn_port_t port);
24-
bool (*test_and_set_mask)(evtchn_port_t port);
2524
void (*mask)(evtchn_port_t port);
2625
void (*unmask)(evtchn_port_t port);
2726

@@ -84,11 +83,6 @@ static inline bool test_evtchn(evtchn_port_t port)
8483
return evtchn_ops->is_pending(port);
8584
}
8685

87-
static inline bool test_and_set_mask(evtchn_port_t port)
88-
{
89-
return evtchn_ops->test_and_set_mask(port);
90-
}
91-
9286
static inline void mask_evtchn(evtchn_port_t port)
9387
{
9488
return evtchn_ops->mask(port);

0 commit comments

Comments
 (0)