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:
kaf24@firebug.cl.cam.ac.uk committed 2005-12-13 19:20:29 +01:00
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;
+9 -33
View File
@@ -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__ */
/*
+40 -1
View File
@@ -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;
+11
View File
@@ -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;
+1 -1
View File
@@ -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__
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.