aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/events.c74
-rw-r--r--drivers/xen/evtchn.c2
-rw-r--r--include/xen/events.h7
3 files changed, 81 insertions, 2 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 6e075cdd0c6..a3bcd6175f4 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -87,6 +87,7 @@ enum xen_irq_type {
87 */ 87 */
88struct irq_info { 88struct irq_info {
89 struct list_head list; 89 struct list_head list;
90 int refcnt;
90 enum xen_irq_type type; /* type */ 91 enum xen_irq_type type; /* type */
91 unsigned irq; 92 unsigned irq;
92 unsigned short evtchn; /* event channel */ 93 unsigned short evtchn; /* event channel */
@@ -406,6 +407,7 @@ static void xen_irq_init(unsigned irq)
406 panic("Unable to allocate metadata for IRQ%d\n", irq); 407 panic("Unable to allocate metadata for IRQ%d\n", irq);
407 408
408 info->type = IRQT_UNBOUND; 409 info->type = IRQT_UNBOUND;
410 info->refcnt = -1;
409 411
410 irq_set_handler_data(irq, info); 412 irq_set_handler_data(irq, info);
411 413
@@ -469,6 +471,8 @@ static void xen_free_irq(unsigned irq)
469 471
470 irq_set_handler_data(irq, NULL); 472 irq_set_handler_data(irq, NULL);
471 473
474 WARN_ON(info->refcnt > 0);
475
472 kfree(info); 476 kfree(info);
473 477
474 /* Legacy IRQ descriptors are managed by the arch. */ 478 /* Legacy IRQ descriptors are managed by the arch. */
@@ -637,7 +641,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
637 if (irq != -1) { 641 if (irq != -1) {
638 printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n", 642 printk(KERN_INFO "xen_map_pirq_gsi: returning irq %d for gsi %u\n",
639 irq, gsi); 643 irq, gsi);
640 goto out; /* XXX need refcount? */ 644 goto out;
641 } 645 }
642 646
643 irq = xen_allocate_irq_gsi(gsi); 647 irq = xen_allocate_irq_gsi(gsi);
@@ -939,9 +943,16 @@ static void unbind_from_irq(unsigned int irq)
939{ 943{
940 struct evtchn_close close; 944 struct evtchn_close close;
941 int evtchn = evtchn_from_irq(irq); 945 int evtchn = evtchn_from_irq(irq);
946 struct irq_info *info = irq_get_handler_data(irq);
942 947
943 mutex_lock(&irq_mapping_update_lock); 948 mutex_lock(&irq_mapping_update_lock);
944 949
950 if (info->refcnt > 0) {
951 info->refcnt--;
952 if (info->refcnt != 0)
953 goto done;
954 }
955
945 if (VALID_EVTCHN(evtchn)) { 956 if (VALID_EVTCHN(evtchn)) {
946 close.port = evtchn; 957 close.port = evtchn;
947 if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0) 958 if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
@@ -970,6 +981,7 @@ static void unbind_from_irq(unsigned int irq)
970 981
971 xen_free_irq(irq); 982 xen_free_irq(irq);
972 983
984 done:
973 mutex_unlock(&irq_mapping_update_lock); 985 mutex_unlock(&irq_mapping_update_lock);
974} 986}
975 987
@@ -1065,6 +1077,66 @@ void unbind_from_irqhandler(unsigned int irq, void *dev_id)
1065} 1077}
1066EXPORT_SYMBOL_GPL(unbind_from_irqhandler); 1078EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
1067 1079
1080int evtchn_make_refcounted(unsigned int evtchn)
1081{
1082 int irq = evtchn_to_irq[evtchn];
1083 struct irq_info *info;
1084
1085 if (irq == -1)
1086 return -ENOENT;
1087
1088 info = irq_get_handler_data(irq);
1089
1090 if (!info)
1091 return -ENOENT;
1092
1093 WARN_ON(info->refcnt != -1);
1094
1095 info->refcnt = 1;
1096
1097 return 0;
1098}
1099EXPORT_SYMBOL_GPL(evtchn_make_refcounted);
1100
1101int evtchn_get(unsigned int evtchn)
1102{
1103 int irq;
1104 struct irq_info *info;
1105 int err = -ENOENT;
1106
1107 mutex_lock(&irq_mapping_update_lock);
1108
1109 irq = evtchn_to_irq[evtchn];
1110 if (irq == -1)
1111 goto done;
1112
1113 info = irq_get_handler_data(irq);
1114
1115 if (!info)
1116 goto done;
1117
1118 err = -EINVAL;
1119 if (info->refcnt <= 0)
1120 goto done;
1121
1122 info->refcnt++;
1123 err = 0;
1124 done:
1125 mutex_unlock(&irq_mapping_update_lock);
1126
1127 return err;
1128}
1129EXPORT_SYMBOL_GPL(evtchn_get);
1130
1131void evtchn_put(unsigned int evtchn)
1132{
1133 int irq = evtchn_to_irq[evtchn];
1134 if (WARN_ON(irq == -1))
1135 return;
1136 unbind_from_irq(irq);
1137}
1138EXPORT_SYMBOL_GPL(evtchn_put);
1139
1068void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector) 1140void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
1069{ 1141{
1070 int irq = per_cpu(ipi_to_irq, cpu)[vector]; 1142 int irq = per_cpu(ipi_to_irq, cpu)[vector];
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index dbc13e94b61..b1f60a0c0be 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -268,7 +268,7 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
268 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED, 268 rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
269 u->name, (void *)(unsigned long)port); 269 u->name, (void *)(unsigned long)port);
270 if (rc >= 0) 270 if (rc >= 0)
271 rc = 0; 271 rc = evtchn_make_refcounted(port);
272 272
273 return rc; 273 return rc;
274} 274}
diff --git a/include/xen/events.h b/include/xen/events.h
index d287997d3ea..0f773708e02 100644
--- a/include/xen/events.h
+++ b/include/xen/events.h
@@ -37,6 +37,13 @@ int bind_interdomain_evtchn_to_irqhandler(unsigned int remote_domain,
37 */ 37 */
38void unbind_from_irqhandler(unsigned int irq, void *dev_id); 38void unbind_from_irqhandler(unsigned int irq, void *dev_id);
39 39
40/*
41 * Allow extra references to event channels exposed to userspace by evtchn
42 */
43int evtchn_make_refcounted(unsigned int evtchn);
44int evtchn_get(unsigned int evtchn);
45void evtchn_put(unsigned int evtchn);
46
40void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector); 47void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
41int resend_irq_on_evtchn(unsigned int irq); 48int resend_irq_on_evtchn(unsigned int irq);
42void rebind_evtchn_irq(int evtchn, int irq); 49void rebind_evtchn_irq(int evtchn, int irq);