From c1a9064dc71e4d551043f4eb1646ea51c0ee572f Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Fri, 8 Jul 2005 14:17:54 +0000 Subject: Clean up Xen's event-channel interface, and semantics for binding to VCPUs. Signed-off-by: Keir Fraser --- .../arch/xen/i386/kernel/smpboot.c | 4 +- linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c | 21 +++++----- .../asm-xen/asm-i386/mach-xen/irq_vectors.h | 4 +- .../asm-xen/asm-x86_64/mach-xen/irq_vectors.h | 4 +- xen/common/event_channel.c | 45 +++++++++++++--------- xen/include/public/dom0_ops.h | 2 +- xen/include/public/event_channel.h | 26 ++++++++----- 7 files changed, 61 insertions(+), 45 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c index 0a79ca6bcd..4798f1d4ec 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1533,13 +1533,13 @@ void __init smp_intr_init(void) int cpu = smp_processor_id(); per_cpu(resched_irq, cpu) = - bind_ipi_on_cpu_to_irq(cpu, RESCHEDULE_VECTOR); + bind_ipi_to_irq(RESCHEDULE_VECTOR); sprintf(resched_name[cpu], "resched%d", cpu); BUG_ON(request_irq(per_cpu(resched_irq, cpu), smp_reschedule_interrupt, SA_INTERRUPT, resched_name[cpu], NULL)); per_cpu(callfunc_irq, cpu) = - bind_ipi_on_cpu_to_irq(cpu, CALL_FUNCTION_VECTOR); + bind_ipi_to_irq(CALL_FUNCTION_VECTOR); sprintf(callfunc_name[cpu], "callfunc%d", cpu); BUG_ON(request_irq(per_cpu(callfunc_irq, cpu), smp_call_function_interrupt, diff --git a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c index dda6c112e4..b293eee001 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c +++ b/linux-2.6.11-xen-sparse/arch/xen/kernel/evtchn.c @@ -236,17 +236,17 @@ void unbind_virq_from_irq(int virq) spin_unlock(&irq_mapping_update_lock); } -int bind_ipi_on_cpu_to_irq(int cpu, int ipi) +int bind_ipi_on_cpu_to_irq(int ipi) { evtchn_op_t op; int evtchn, irq; + int cpu = smp_processor_id(); spin_lock(&irq_mapping_update_lock); if ( (evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]) == 0 ) { - op.cmd = EVTCHNOP_bind_ipi; - op.u.bind_ipi.ipi_vcpu = cpu; + op.cmd = EVTCHNOP_bind_ipi; if ( HYPERVISOR_event_channel_op(&op) != 0 ) panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, cpu); evtchn = op.u.bind_ipi.port; @@ -278,9 +278,9 @@ void rebind_evtchn_from_ipi(int cpu, int newcpu, int ipi) spin_lock(&irq_mapping_update_lock); - op.cmd = EVTCHNOP_rebind; - op.u.rebind.port = evtchn; - op.u.rebind.vcpu = newcpu; + op.cmd = EVTCHNOP_bind_vcpu; + op.u.bind_vcpu.port = evtchn; + op.u.bind_vcpu.vcpu = newcpu; if ( HYPERVISOR_event_channel_op(&op) != 0 ) printk(KERN_INFO "Failed to rebind IPI%d to CPU%d\n",ipi,newcpu); @@ -294,18 +294,19 @@ void rebind_evtchn_from_irq(int cpu, int newcpu, int irq) spin_lock(&irq_mapping_update_lock); - op.cmd = EVTCHNOP_rebind; - op.u.rebind.port = evtchn; - op.u.rebind.vcpu = newcpu; + op.cmd = EVTCHNOP_bind_vcpu; + op.u.bind_vcpu.port = evtchn; + op.u.bind_vcpu.vcpu = newcpu; if ( HYPERVISOR_event_channel_op(&op) != 0 ) printk(KERN_INFO "Failed to rebind IRQ%d to CPU%d\n",irq,newcpu); spin_unlock(&irq_mapping_update_lock); } -void unbind_ipi_on_cpu_from_irq(int cpu, int ipi) +void unbind_ipi_from_irq(int ipi) { evtchn_op_t op; + int cpu = smp_processor_id(); int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]; int irq = irq_to_evtchn[evtchn]; diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h index 88c5faaf84..af4ed763fa 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h @@ -128,8 +128,8 @@ /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */ extern int bind_virq_to_irq(int virq); extern void unbind_virq_from_irq(int virq); -extern int bind_ipi_on_cpu_to_irq(int cpu, int ipi); -extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi); +extern int bind_ipi_to_irq(int ipi); +extern void unbind_ipi_from_irq(int ipi); extern int bind_evtchn_to_irq(int evtchn); extern void unbind_evtchn_from_irq(int evtchn); diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h index 8f19c41675..f72c14da1f 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/irq_vectors.h @@ -126,8 +126,8 @@ /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */ extern int bind_virq_to_irq(int virq); extern void unbind_virq_from_irq(int virq); -extern int bind_ipi_on_cpu_to_irq(int cpu, int ipi); -extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi); +extern int bind_ipi_to_irq(int ipi); +extern void unbind_ipi_from_irq(int ipi); extern int bind_evtchn_to_irq(int evtchn); extern void unbind_evtchn_from_irq(int evtchn); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index 61ad635f5e..13145e114d 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -220,12 +220,10 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) chn1->u.interdomain.remote_dom = d2; chn1->u.interdomain.remote_port = (u16)port2; - chn1->notify_vcpu_id = 0; chn1->state = ECS_INTERDOMAIN; chn2->u.interdomain.remote_dom = d1; chn2->u.interdomain.remote_port = (u16)port1; - chn2->notify_vcpu_id = 0; chn2->state = ECS_INTERDOMAIN; out: @@ -285,10 +283,7 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind) { struct evtchn *chn; struct domain *d = current->domain; - int port, ipi_vcpu = bind->ipi_vcpu; - - if ( (ipi_vcpu >= MAX_VIRT_CPUS) || (d->vcpu[ipi_vcpu] == NULL) ) - return -EINVAL; + int port; spin_lock(&d->evtchn_lock); @@ -296,7 +291,7 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind) { chn = evtchn_from_port(d, port); chn->state = ECS_IPI; - chn->notify_vcpu_id = ipi_vcpu; + chn->notify_vcpu_id = current->vcpu_id; } spin_unlock(&d->evtchn_lock); @@ -326,8 +321,6 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind) chn = evtchn_from_port(d, port); - chn->notify_vcpu_id = 0; - d->pirq_to_evtchn[pirq] = port; rc = pirq_guest_bind(d->vcpu[0], pirq, !!(bind->flags & BIND_PIRQ__WILL_SHARE)); @@ -441,7 +434,9 @@ static long __evtchn_close(struct domain *d1, int port1) BUG(); } - chn1->state = ECS_FREE; + /* Reset binding to vcpu0 when the channel is freed. */ + chn1->state = ECS_FREE; + chn1->notify_vcpu_id = 0; out: if ( d2 != NULL ) @@ -570,26 +565,30 @@ static long evtchn_status(evtchn_status_t *status) status->u.virq = chn->u.virq; break; case ECS_IPI: - status->status = EVTCHNSTAT_ipi; - status->u.ipi_vcpu = chn->notify_vcpu_id; + status->status = EVTCHNSTAT_ipi; break; default: BUG(); } + status->vcpu = chn->notify_vcpu_id; + out: spin_unlock(&d->evtchn_lock); put_domain(d); return rc; } -static long evtchn_rebind(evtchn_rebind_t *bind) +static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind) { struct domain *d = current->domain; int port = bind->port; int vcpu = bind->vcpu; struct evtchn *chn; - long rc = 0; + long rc = 0; + + if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) ) + return -EINVAL; spin_lock(&d->evtchn_lock); @@ -600,7 +599,17 @@ static long evtchn_rebind(evtchn_rebind_t *bind) } chn = evtchn_from_port(d, port); - chn->notify_vcpu_id = vcpu; + switch ( chn->state ) + { + case ECS_UNBOUND: + case ECS_INTERDOMAIN: + case ECS_PIRQ: + chn->notify_vcpu_id = vcpu; + break; + default: + rc = -EINVAL; + break; + } out: spin_unlock(&d->evtchn_lock); @@ -664,10 +673,8 @@ long do_event_channel_op(evtchn_op_t *uop) rc = -EFAULT; break; - case EVTCHNOP_rebind: - rc = evtchn_rebind(&op.u.rebind); - if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) ) - rc = -EFAULT; + case EVTCHNOP_bind_vcpu: + rc = evtchn_bind_vcpu(&op.u.bind_vcpu); break; default: diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h index 60e215b09c..2502edd75a 100644 --- a/xen/include/public/dom0_ops.h +++ b/xen/include/public/dom0_ops.h @@ -19,7 +19,7 @@ * This makes sure that old versions of dom0 tools will stop working in a * well-defined way (rather than crashing the machine, for instance). */ -#define DOM0_INTERFACE_VERSION 0xAAAA100D +#define DOM0_INTERFACE_VERSION 0xAAAA100E /************************************************************************/ diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h index ceacf3fc34..d1629ec244 100644 --- a/xen/include/public/event_channel.h +++ b/xen/include/public/event_channel.h @@ -89,8 +89,6 @@ typedef struct evtchn_bind_pirq { */ #define EVTCHNOP_bind_ipi 7 typedef struct evtchn_bind_ipi { - /* IN parameters. */ - u32 ipi_vcpu; /* OUT parameters. */ u32 port; } evtchn_bind_ipi_t; @@ -144,6 +142,7 @@ typedef struct evtchn_status { #define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ #define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */ u32 status; + u32 vcpu; /* VCPU to which this channel is bound. */ union { struct { domid_t dom; @@ -154,16 +153,25 @@ typedef struct evtchn_status { } interdomain; /* EVTCHNSTAT_interdomain */ u32 pirq; /* EVTCHNSTAT_pirq */ u32 virq; /* EVTCHNSTAT_virq */ - u32 ipi_vcpu; /* EVTCHNSTAT_ipi */ } u; } evtchn_status_t; -#define EVTCHNOP_rebind 8 -typedef struct { +/* + * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an + * event is pending. + * NOTES: + * 1. IPI- and VIRQ-bound channels always notify the vcpu that initialised + * the binding. This binding cannot be changed. + * 2. All other channels notify vcpu0 by default. This default is set when + * the channel is allocated (a port that is freed and subsequently reused + * has its binding reset to vcpu0). + */ +#define EVTCHNOP_bind_vcpu 8 +typedef struct evtchn_bind_vcpu { /* IN parameters. */ - u32 port; /* 0 */ - u32 vcpu; /* 4 */ -} evtchn_rebind_t; /* 8 bytes */ + u32 port; + u32 vcpu; +} evtchn_bind_vcpu_t; typedef struct evtchn_op { u32 cmd; /* EVTCHNOP_* */ @@ -176,7 +184,7 @@ typedef struct evtchn_op { evtchn_close_t close; evtchn_send_t send; evtchn_status_t status; - evtchn_rebind_t rebind; + evtchn_bind_vcpu_t bind_vcpu; } u; } evtchn_op_t; -- cgit v1.2.3