mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Fix unmask_evtchn() when the port is bound to a different
VCPU. Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
d6f8e9a68e
commit
3e61615263
5 files changed
+99
-35
No files matched your search
@@ -639,6 +639,44 @@ void notify_remote_via_irq(int irq)
|
||||
}
|
||||
EXPORT_SYMBOL(notify_remote_via_irq);
|
||||
|
||||
void mask_evtchn(int port)
|
||||
{
|
||||
shared_info_t *s = HYPERVISOR_shared_info;
|
||||
synch_set_bit(port, &s->evtchn_mask[0]);
|
||||
}
|
||||
EXPORT_SYMBOL(mask_evtchn);
|
||||
|
||||
void unmask_evtchn(int port)
|
||||
{
|
||||
shared_info_t *s = HYPERVISOR_shared_info;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
|
||||
|
||||
/* Slow path (hypercall) if this is a non-local port. */
|
||||
if (unlikely(cpu != cpu_from_evtchn(port))) {
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_unmask,
|
||||
.u.unmask.port = port };
|
||||
(void)HYPERVISOR_event_channel_op(&op);
|
||||
return;
|
||||
}
|
||||
|
||||
synch_clear_bit(port, &s->evtchn_mask[0]);
|
||||
|
||||
/*
|
||||
* The following is basically the equivalent of 'hw_resend_irq'. Just
|
||||
* like a real IO-APIC we 'lose the interrupt edge' if the channel is
|
||||
* masked.
|
||||
*/
|
||||
if (synch_test_bit(port, &s->evtchn_pending[0]) &&
|
||||
!synch_test_and_set_bit(port / BITS_PER_LONG,
|
||||
&vcpu_info->evtchn_pending_sel)) {
|
||||
vcpu_info->evtchn_upcall_pending = 1;
|
||||
if (!vcpu_info->evtchn_upcall_mask)
|
||||
force_evtchn_callback();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(unmask_evtchn);
|
||||
|
||||
void irq_resume(void)
|
||||
{
|
||||
evtchn_op_t op;
|
||||
|
||||
@@ -79,46 +79,16 @@ extern int bind_ipi_to_irqhandler(
|
||||
*/
|
||||
extern void unbind_from_irqhandler(unsigned int irq, void *dev_id);
|
||||
|
||||
/*
|
||||
* Unlike notify_remote_via_evtchn(), this is safe to use across
|
||||
* save/restore. Notifications on a broken connection are silently dropped.
|
||||
*/
|
||||
void notify_remote_via_irq(int irq);
|
||||
|
||||
extern void irq_resume(void);
|
||||
|
||||
/* Entry point for notifications into Linux subsystems. */
|
||||
asmlinkage void evtchn_do_upcall(struct pt_regs *regs);
|
||||
|
||||
/* Entry point for notifications into the userland character device. */
|
||||
void evtchn_device_upcall(int port);
|
||||
extern void evtchn_device_upcall(int port);
|
||||
|
||||
static inline void mask_evtchn(int port)
|
||||
{
|
||||
shared_info_t *s = HYPERVISOR_shared_info;
|
||||
synch_set_bit(port, &s->evtchn_mask[0]);
|
||||
}
|
||||
|
||||
static inline void unmask_evtchn(int port)
|
||||
{
|
||||
shared_info_t *s = HYPERVISOR_shared_info;
|
||||
vcpu_info_t *vcpu_info = &s->vcpu_info[smp_processor_id()];
|
||||
|
||||
synch_clear_bit(port, &s->evtchn_mask[0]);
|
||||
|
||||
/*
|
||||
* The following is basically the equivalent of 'hw_resend_irq'. Just
|
||||
* like a real IO-APIC we 'lose the interrupt edge' if the channel is
|
||||
* masked.
|
||||
*/
|
||||
if (synch_test_bit(port, &s->evtchn_pending[0]) &&
|
||||
!synch_test_and_set_bit(port / BITS_PER_LONG,
|
||||
&vcpu_info->evtchn_pending_sel)) {
|
||||
vcpu_info->evtchn_upcall_pending = 1;
|
||||
if (!vcpu_info->evtchn_upcall_mask)
|
||||
force_evtchn_callback();
|
||||
}
|
||||
}
|
||||
extern void mask_evtchn(int port);
|
||||
extern void unmask_evtchn(int port);
|
||||
|
||||
static inline void clear_evtchn(int port)
|
||||
{
|
||||
@@ -134,6 +104,12 @@ static inline void notify_remote_via_evtchn(int port)
|
||||
(void)HYPERVISOR_event_channel_op(&op);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlike notify_remote_via_evtchn(), this is safe to use across
|
||||
* save/restore. Notifications on a broken connection are silently dropped.
|
||||
*/
|
||||
extern void notify_remote_via_irq(int irq);
|
||||
|
||||
#endif /* __ASM_EVTCHN_H__ */
|
||||
|
||||
/*
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Event notifications from VIRQs, PIRQs, and other domains.
|
||||
*
|
||||
* Copyright (c) 2003-2004, K A Fraser.
|
||||
* Copyright (c) 2003-2005, K A Fraser.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -541,6 +541,41 @@ static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long evtchn_unmask(evtchn_unmask_t *unmask)
|
||||
{
|
||||
struct domain *d = current->domain;
|
||||
shared_info_t *s = d->shared_info;
|
||||
int port = unmask->port;
|
||||
struct vcpu *v;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
|
||||
if ( unlikely(!port_is_valid(d, port)) )
|
||||
{
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id];
|
||||
|
||||
/*
|
||||
* These operations must happen in strict order. Based on
|
||||
* include/xen/event.h:evtchn_set_pending().
|
||||
*/
|
||||
if ( test_and_clear_bit(port, &s->evtchn_mask[0]) &&
|
||||
test_bit (port, &s->evtchn_pending[0]) &&
|
||||
!test_and_set_bit (port / BITS_PER_LONG,
|
||||
&v->vcpu_info->evtchn_pending_sel) &&
|
||||
!test_and_set_bit (0, &v->vcpu_info->evtchn_upcall_pending) )
|
||||
{
|
||||
evtchn_notify(v);
|
||||
}
|
||||
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long do_event_channel_op(evtchn_op_t *uop)
|
||||
{
|
||||
long rc;
|
||||
@@ -602,6 +637,10 @@ long do_event_channel_op(evtchn_op_t *uop)
|
||||
rc = evtchn_bind_vcpu(&op.u.bind_vcpu);
|
||||
break;
|
||||
|
||||
case EVTCHNOP_unmask:
|
||||
rc = evtchn_unmask(&op.u.unmask);
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = -ENOSYS;
|
||||
break;
|
||||
|
||||
@@ -164,6 +164,16 @@ typedef struct evtchn_bind_vcpu {
|
||||
uint32_t vcpu;
|
||||
} evtchn_bind_vcpu_t;
|
||||
|
||||
/*
|
||||
* EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
|
||||
* a notification to the appropriate VCPU if an event is pending.
|
||||
*/
|
||||
#define EVTCHNOP_unmask 9
|
||||
typedef struct evtchn_unmask {
|
||||
/* IN parameters. */
|
||||
evtchn_port_t port;
|
||||
} evtchn_unmask_t;
|
||||
|
||||
typedef struct evtchn_op {
|
||||
uint32_t cmd; /* EVTCHNOP_* */
|
||||
union {
|
||||
@@ -176,6 +186,7 @@ typedef struct evtchn_op {
|
||||
evtchn_send_t send;
|
||||
evtchn_status_t status;
|
||||
evtchn_bind_vcpu_t bind_vcpu;
|
||||
evtchn_unmask_t unmask;
|
||||
} u;
|
||||
} evtchn_op_t;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* A nice interface for passing asynchronous events to guest OSes.
|
||||
*
|
||||
* Copyright (c) 2002, K A Fraser
|
||||
* Copyright (c) 2002-2005, K A Fraser
|
||||
*/
|
||||
|
||||
#ifndef __XEN_EVENT_H__
|
||||
|
||||