diff options
-rw-r--r-- | drivers/xen/events.c | 74 | ||||
-rw-r--r-- | drivers/xen/evtchn.c | 2 | ||||
-rw-r--r-- | include/xen/events.h | 7 |
3 files changed, 81 insertions, 2 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 6e075cdd0c6b..a3bcd6175f4a 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -87,6 +87,7 @@ enum xen_irq_type { | |||
87 | */ | 87 | */ |
88 | struct irq_info { | 88 | struct 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 | } |
1066 | EXPORT_SYMBOL_GPL(unbind_from_irqhandler); | 1078 | EXPORT_SYMBOL_GPL(unbind_from_irqhandler); |
1067 | 1079 | ||
1080 | int 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 | } | ||
1099 | EXPORT_SYMBOL_GPL(evtchn_make_refcounted); | ||
1100 | |||
1101 | int 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 | } | ||
1129 | EXPORT_SYMBOL_GPL(evtchn_get); | ||
1130 | |||
1131 | void 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 | } | ||
1138 | EXPORT_SYMBOL_GPL(evtchn_put); | ||
1139 | |||
1068 | void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector) | 1140 | void 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 dbc13e94b612..b1f60a0c0bea 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 d287997d3eab..0f773708e02c 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 | */ |
38 | void unbind_from_irqhandler(unsigned int irq, void *dev_id); | 38 | void 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 | */ | ||
43 | int evtchn_make_refcounted(unsigned int evtchn); | ||
44 | int evtchn_get(unsigned int evtchn); | ||
45 | void evtchn_put(unsigned int evtchn); | ||
46 | |||
40 | void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector); | 47 | void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector); |
41 | int resend_irq_on_evtchn(unsigned int irq); | 48 | int resend_irq_on_evtchn(unsigned int irq); |
42 | void rebind_evtchn_irq(int evtchn, int irq); | 49 | void rebind_evtchn_irq(int evtchn, int irq); |