Skip to content

Commit 54c9de8

Browse files
committed
xen/events: add a new "late EOI" evtchn framework
In order to avoid tight event channel related IRQ loops add a new framework of "late EOI" handling: the IRQ the event channel is bound to will be masked until the event has been handled and the related driver is capable to handle another event. The driver is responsible for unmasking the event channel via the new function xen_irq_lateeoi(). This is similar to binding an event channel to a threaded IRQ, but without having to structure the driver accordingly. In order to support a future special handling in case a rogue guest is sending lots of unsolicited events, add a flag to xen_irq_lateeoi() which can be set by the caller to indicate the event was a spurious one. This is part of XSA-332. Cc: [email protected] Reported-by: Julien Grall <[email protected]> Signed-off-by: Juergen Gross <[email protected]> Reviewed-by: Jan Beulich <[email protected]> Reviewed-by: Stefano Stabellini <[email protected]> Reviewed-by: Wei Liu <[email protected]>
1 parent f013371 commit 54c9de8

File tree

2 files changed

+155
-17
lines changed

2 files changed

+155
-17
lines changed

drivers/xen/events/events_base.c

Lines changed: 134 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ static bool (*pirq_needs_eoi)(unsigned irq);
113113
static struct irq_info *legacy_info_ptrs[NR_IRQS_LEGACY];
114114

115115
static struct irq_chip xen_dynamic_chip;
116+
static struct irq_chip xen_lateeoi_chip;
116117
static struct irq_chip xen_percpu_chip;
117118
static struct irq_chip xen_pirq_chip;
118119
static void enable_dynirq(struct irq_data *data);
@@ -397,6 +398,33 @@ void notify_remote_via_irq(int irq)
397398
}
398399
EXPORT_SYMBOL_GPL(notify_remote_via_irq);
399400

401+
static void xen_irq_lateeoi_locked(struct irq_info *info)
402+
{
403+
evtchn_port_t evtchn;
404+
405+
evtchn = info->evtchn;
406+
if (!VALID_EVTCHN(evtchn))
407+
return;
408+
409+
unmask_evtchn(evtchn);
410+
}
411+
412+
void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags)
413+
{
414+
struct irq_info *info;
415+
unsigned long flags;
416+
417+
read_lock_irqsave(&evtchn_rwlock, flags);
418+
419+
info = info_for_irq(irq);
420+
421+
if (info)
422+
xen_irq_lateeoi_locked(info);
423+
424+
read_unlock_irqrestore(&evtchn_rwlock, flags);
425+
}
426+
EXPORT_SYMBOL_GPL(xen_irq_lateeoi);
427+
400428
static void xen_irq_init(unsigned irq)
401429
{
402430
struct irq_info *info;
@@ -868,7 +896,7 @@ int xen_pirq_from_irq(unsigned irq)
868896
}
869897
EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
870898

871-
int bind_evtchn_to_irq(evtchn_port_t evtchn)
899+
static int bind_evtchn_to_irq_chip(evtchn_port_t evtchn, struct irq_chip *chip)
872900
{
873901
int irq;
874902
int ret;
@@ -885,7 +913,7 @@ int bind_evtchn_to_irq(evtchn_port_t evtchn)
885913
if (irq < 0)
886914
goto out;
887915

888-
irq_set_chip_and_handler_name(irq, &xen_dynamic_chip,
916+
irq_set_chip_and_handler_name(irq, chip,
889917
handle_edge_irq, "event");
890918

891919
ret = xen_irq_info_evtchn_setup(irq, evtchn);
@@ -906,8 +934,19 @@ int bind_evtchn_to_irq(evtchn_port_t evtchn)
906934

907935
return irq;
908936
}
937+
938+
int bind_evtchn_to_irq(evtchn_port_t evtchn)
939+
{
940+
return bind_evtchn_to_irq_chip(evtchn, &xen_dynamic_chip);
941+
}
909942
EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
910943

944+
int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn)
945+
{
946+
return bind_evtchn_to_irq_chip(evtchn, &xen_lateeoi_chip);
947+
}
948+
EXPORT_SYMBOL_GPL(bind_evtchn_to_irq_lateeoi);
949+
911950
static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
912951
{
913952
struct evtchn_bind_ipi bind_ipi;
@@ -949,8 +988,9 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
949988
return irq;
950989
}
951990

952-
int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
953-
evtchn_port_t remote_port)
991+
static int bind_interdomain_evtchn_to_irq_chip(unsigned int remote_domain,
992+
evtchn_port_t remote_port,
993+
struct irq_chip *chip)
954994
{
955995
struct evtchn_bind_interdomain bind_interdomain;
956996
int err;
@@ -961,10 +1001,26 @@ int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
9611001
err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
9621002
&bind_interdomain);
9631003

964-
return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
1004+
return err ? : bind_evtchn_to_irq_chip(bind_interdomain.local_port,
1005+
chip);
1006+
}
1007+
1008+
int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
1009+
evtchn_port_t remote_port)
1010+
{
1011+
return bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
1012+
&xen_dynamic_chip);
9651013
}
9661014
EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq);
9671015

1016+
int bind_interdomain_evtchn_to_irq_lateeoi(unsigned int remote_domain,
1017+
evtchn_port_t remote_port)
1018+
{
1019+
return bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
1020+
&xen_lateeoi_chip);
1021+
}
1022+
EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irq_lateeoi);
1023+
9681024
static int find_virq(unsigned int virq, unsigned int cpu, evtchn_port_t *evtchn)
9691025
{
9701026
struct evtchn_status status;
@@ -1061,14 +1117,15 @@ static void unbind_from_irq(unsigned int irq)
10611117
mutex_unlock(&irq_mapping_update_lock);
10621118
}
10631119

1064-
int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
1065-
irq_handler_t handler,
1066-
unsigned long irqflags,
1067-
const char *devname, void *dev_id)
1120+
static int bind_evtchn_to_irqhandler_chip(evtchn_port_t evtchn,
1121+
irq_handler_t handler,
1122+
unsigned long irqflags,
1123+
const char *devname, void *dev_id,
1124+
struct irq_chip *chip)
10681125
{
10691126
int irq, retval;
10701127

1071-
irq = bind_evtchn_to_irq(evtchn);
1128+
irq = bind_evtchn_to_irq_chip(evtchn, chip);
10721129
if (irq < 0)
10731130
return irq;
10741131
retval = request_irq(irq, handler, irqflags, devname, dev_id);
@@ -1079,18 +1136,38 @@ int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
10791136

10801137
return irq;
10811138
}
1139+
1140+
int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
1141+
irq_handler_t handler,
1142+
unsigned long irqflags,
1143+
const char *devname, void *dev_id)
1144+
{
1145+
return bind_evtchn_to_irqhandler_chip(evtchn, handler, irqflags,
1146+
devname, dev_id,
1147+
&xen_dynamic_chip);
1148+
}
10821149
EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
10831150

1084-
int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
1085-
evtchn_port_t remote_port,
1086-
irq_handler_t handler,
1087-
unsigned long irqflags,
1088-
const char *devname,
1089-
void *dev_id)
1151+
int bind_evtchn_to_irqhandler_lateeoi(evtchn_port_t evtchn,
1152+
irq_handler_t handler,
1153+
unsigned long irqflags,
1154+
const char *devname, void *dev_id)
1155+
{
1156+
return bind_evtchn_to_irqhandler_chip(evtchn, handler, irqflags,
1157+
devname, dev_id,
1158+
&xen_lateeoi_chip);
1159+
}
1160+
EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler_lateeoi);
1161+
1162+
static int bind_interdomain_evtchn_to_irqhandler_chip(
1163+
unsigned int remote_domain, evtchn_port_t remote_port,
1164+
irq_handler_t handler, unsigned long irqflags,
1165+
const char *devname, void *dev_id, struct irq_chip *chip)
10901166
{
10911167
int irq, retval;
10921168

1093-
irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
1169+
irq = bind_interdomain_evtchn_to_irq_chip(remote_domain, remote_port,
1170+
chip);
10941171
if (irq < 0)
10951172
return irq;
10961173

@@ -1102,8 +1179,33 @@ int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
11021179

11031180
return irq;
11041181
}
1182+
1183+
int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
1184+
evtchn_port_t remote_port,
1185+
irq_handler_t handler,
1186+
unsigned long irqflags,
1187+
const char *devname,
1188+
void *dev_id)
1189+
{
1190+
return bind_interdomain_evtchn_to_irqhandler_chip(remote_domain,
1191+
remote_port, handler, irqflags, devname,
1192+
dev_id, &xen_dynamic_chip);
1193+
}
11051194
EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
11061195

1196+
int bind_interdomain_evtchn_to_irqhandler_lateeoi(unsigned int remote_domain,
1197+
evtchn_port_t remote_port,
1198+
irq_handler_t handler,
1199+
unsigned long irqflags,
1200+
const char *devname,
1201+
void *dev_id)
1202+
{
1203+
return bind_interdomain_evtchn_to_irqhandler_chip(remote_domain,
1204+
remote_port, handler, irqflags, devname,
1205+
dev_id, &xen_lateeoi_chip);
1206+
}
1207+
EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler_lateeoi);
1208+
11071209
int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
11081210
irq_handler_t handler,
11091211
unsigned long irqflags, const char *devname, void *dev_id)
@@ -1637,6 +1739,21 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
16371739
.irq_retrigger = retrigger_dynirq,
16381740
};
16391741

1742+
static struct irq_chip xen_lateeoi_chip __read_mostly = {
1743+
/* The chip name needs to contain "xen-dyn" for irqbalance to work. */
1744+
.name = "xen-dyn-lateeoi",
1745+
1746+
.irq_disable = disable_dynirq,
1747+
.irq_mask = disable_dynirq,
1748+
.irq_unmask = enable_dynirq,
1749+
1750+
.irq_ack = mask_ack_dynirq,
1751+
.irq_mask_ack = mask_ack_dynirq,
1752+
1753+
.irq_set_affinity = set_affinity_irq,
1754+
.irq_retrigger = retrigger_dynirq,
1755+
};
1756+
16401757
static struct irq_chip xen_pirq_chip __read_mostly = {
16411758
.name = "xen-pirq",
16421759

include/xen/events.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@
1515
unsigned xen_evtchn_nr_channels(void);
1616

1717
int bind_evtchn_to_irq(evtchn_port_t evtchn);
18+
int bind_evtchn_to_irq_lateeoi(evtchn_port_t evtchn);
1819
int bind_evtchn_to_irqhandler(evtchn_port_t evtchn,
1920
irq_handler_t handler,
2021
unsigned long irqflags, const char *devname,
2122
void *dev_id);
23+
int bind_evtchn_to_irqhandler_lateeoi(evtchn_port_t evtchn,
24+
irq_handler_t handler,
25+
unsigned long irqflags, const char *devname,
26+
void *dev_id);
2227
int bind_virq_to_irq(unsigned int virq, unsigned int cpu, bool percpu);
2328
int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
2429
irq_handler_t handler,
@@ -32,12 +37,20 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi,
3237
void *dev_id);
3338
int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
3439
evtchn_port_t remote_port);
40+
int bind_interdomain_evtchn_to_irq_lateeoi(unsigned int remote_domain,
41+
evtchn_port_t remote_port);
3542
int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
3643
evtchn_port_t remote_port,
3744
irq_handler_t handler,
3845
unsigned long irqflags,
3946
const char *devname,
4047
void *dev_id);
48+
int bind_interdomain_evtchn_to_irqhandler_lateeoi(unsigned int remote_domain,
49+
evtchn_port_t remote_port,
50+
irq_handler_t handler,
51+
unsigned long irqflags,
52+
const char *devname,
53+
void *dev_id);
4154

4255
/*
4356
* Common unbind function for all event sources. Takes IRQ to unbind from.
@@ -46,6 +59,14 @@ int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
4659
*/
4760
void unbind_from_irqhandler(unsigned int irq, void *dev_id);
4861

62+
/*
63+
* Send late EOI for an IRQ bound to an event channel via one of the *_lateeoi
64+
* functions above.
65+
*/
66+
void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags);
67+
/* Signal an event was spurious, i.e. there was no action resulting from it. */
68+
#define XEN_EOI_FLAG_SPURIOUS 0x00000001
69+
4970
#define XEN_IRQ_PRIORITY_MAX EVTCHN_FIFO_PRIORITY_MAX
5071
#define XEN_IRQ_PRIORITY_DEFAULT EVTCHN_FIFO_PRIORITY_DEFAULT
5172
#define XEN_IRQ_PRIORITY_MIN EVTCHN_FIFO_PRIORITY_MIN

0 commit comments

Comments
 (0)