diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-03-26 12:26:45 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-03-26 12:26:45 +0000 |
commit | caca24b294766e927d4624fe1fc534fd10f51801 (patch) | |
tree | d739261f7bcdfbddb8829a03596616f6d46a18db | |
parent | 9c127f7b32ec4b1f9a3cdbc6bd6f80dfcfbaa627 (diff) | |
download | xen-caca24b294766e927d4624fe1fc534fd10f51801.tar.gz xen-caca24b294766e927d4624fe1fc534fd10f51801.tar.bz2 xen-caca24b294766e927d4624fe1fc534fd10f51801.zip |
bitkeeper revision 1.825.4.3 (40642185aZwwgLwBAies8HKAne40aw)
Many files:
Adding physirq support to new Xen upcall interface.
.del-physirq.c~e02f2ea038df07fa:
Delete: xenolinux-2.4.25-sparse/arch/xen/kernel/physirq.c
-rw-r--r-- | .rootkeys | 1 | ||||
-rw-r--r-- | xen/common/event_channel.c | 45 | ||||
-rw-r--r-- | xen/common/physdev.c | 95 | ||||
-rw-r--r-- | xen/include/hypervisor-ifs/dom0_ops.h | 2 | ||||
-rw-r--r-- | xen/include/hypervisor-ifs/event_channel.h | 28 | ||||
-rw-r--r-- | xen/include/hypervisor-ifs/physdev.h | 45 | ||||
-rw-r--r-- | xenolinux-2.4.25-sparse/arch/xen/kernel/Makefile | 2 | ||||
-rw-r--r-- | xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c | 260 | ||||
-rw-r--r-- | xenolinux-2.4.25-sparse/arch/xen/kernel/physirq.c | 175 | ||||
-rw-r--r-- | xenolinux-2.4.25-sparse/include/asm-xen/irq.h | 15 |
10 files changed, 268 insertions, 400 deletions
@@ -641,7 +641,6 @@ 4051db8dJYX86ZCLA-WfTW2dAyrehw xenolinux-2.4.25-sparse/arch/xen/kernel/pci-i386.h 4051db91BenvDZEMZxQCGkQyJYoG5w xenolinux-2.4.25-sparse/arch/xen/kernel/pci-irq.c 4051db95N9N99FjsRwi49YKUNHWI8A xenolinux-2.4.25-sparse/arch/xen/kernel/pci-pc.c -4051db99fbdTHgCpjywPCp7vjLCe7Q xenolinux-2.4.25-sparse/arch/xen/kernel/physirq.c 3e5a4e65IGt3WwQDNiL4h-gYWgNTWQ xenolinux-2.4.25-sparse/arch/xen/kernel/process.c 3e5a4e66tR-qJMLj3MppcKqmvuI2XQ xenolinux-2.4.25-sparse/arch/xen/kernel/setup.c 3e5a4e66fWSTagLGU2P8BGFGRjhDiw xenolinux-2.4.25-sparse/arch/xen/kernel/signal.c diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index f5e48f366e..d0c0f5bba0 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -146,7 +146,7 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind) int virq = bind->virq; int port; - if ( virq >= NR_VIRQS ) + if ( virq >= ARRAY_SIZE(p->virq_to_evtchn) ) return -EINVAL; spin_lock(&p->event_channel_lock); @@ -177,6 +177,37 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind) } +static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind) +{ + struct task_struct *p = current; + int pirq = bind->pirq; + int port; + + if ( pirq >= ARRAY_SIZE(p->pirq_to_evtchn) ) + return -EINVAL; + + spin_lock(&p->event_channel_lock); + + if ( ((port = p->pirq_to_evtchn[pirq]) != 0) || + ((port = get_free_port(p)) < 0) ) + goto out; + + p->event_channel[port].state = ECS_PIRQ; + p->event_channel[port].u.pirq = pirq; + + p->pirq_to_evtchn[pirq] = port; + + out: + spin_unlock(&p->event_channel_lock); + + if ( port < 0 ) + return port; + + bind->port = port; + return 0; +} + + static long __evtchn_close(struct task_struct *p1, int port1) { struct task_struct *p2 = NULL; @@ -396,13 +427,19 @@ long do_event_channel_op(evtchn_op_t *uop) { case EVTCHNOP_bind_interdomain: rc = evtchn_bind_interdomain(&op.u.bind_interdomain); - if ( copy_to_user(uop, &op, sizeof(op)) != 0 ) + if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) ) rc = -EFAULT; /* Cleaning up here would be a mess! */ break; case EVTCHNOP_bind_virq: rc = evtchn_bind_virq(&op.u.bind_virq); - if ( copy_to_user(uop, &op, sizeof(op)) != 0 ) + if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) ) + rc = -EFAULT; /* Cleaning up here would be a mess! */ + break; + + case EVTCHNOP_bind_pirq: + rc = evtchn_bind_pirq(&op.u.bind_pirq); + if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) ) rc = -EFAULT; /* Cleaning up here would be a mess! */ break; @@ -416,7 +453,7 @@ long do_event_channel_op(evtchn_op_t *uop) case EVTCHNOP_status: rc = evtchn_status(&op.u.status); - if ( copy_to_user(uop, &op, sizeof(op)) != 0 ) + if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) ) rc = -EFAULT; break; diff --git a/xen/common/physdev.c b/xen/common/physdev.c index da22f88cfe..08da1b5206 100644 --- a/xen/common/physdev.c +++ b/xen/common/physdev.c @@ -601,7 +601,7 @@ static void end_virt_irq (unsigned int i) * - shared interrupts are not allowed for now * - we change the hw_irq handler to something else */ -static long pci_request_irq(int irq) +static long pirq_request(int irq) { int err; phys_dev_t *pdev = NULL, *t; @@ -685,7 +685,7 @@ static long pci_request_irq(int irq) return 0; } -static long pci_free_irq(int irq) +long pirq_free(int irq) { phys_dev_t *pdev; @@ -719,55 +719,12 @@ static long pci_free_irq(int irq) return 0; } -static long pci_enable_irq(int irq) +static long pci_unmask_irq(void) { - /* XXX not sure we need this */ - /* guest can enable phys_irq event for now */ - return 0; -} - -static long pci_disable_irq(int irq) -{ - /* XXX not sure we need this */ - /* guest can disable phys_irq event for now */ - return 0; -} - -static long pci_finished_irq(int irq) -{ - phys_dev_t *pdev; - - if ( !(pdev = irqs[irq]) ) - { - printk("finished_irq called for unregistered irq %d\n", irq); - return -EINVAL; - } - - if ( pdev->owner != current ) - { - printk("finished_irq called dom not owning irq %d\n", irq); - return -EPERM; - } - - if ( !test_bit(ST_IRQ_DELIVERED, &pdev->state) ) - { - printk("finished_irq called for undelivered irq %d\n", irq); - return -EINVAL; - } - -#if 0 /* XXX KAF: do we need this? */ - if ( test_bit(irq, ¤t->shared_info->physirq_pend) ) - { - printk("finished_irq called for un-acknowleged irq %d\n", irq); - return -EINVAL; - } -#endif - +#if 0 clear_bit(ST_IRQ_DELIVERED, &pdev->state); - - /* call original end handler */ pdev->orig_handler->end(irq); - +#endif return 0; } @@ -786,43 +743,27 @@ long do_physdev_op(physdev_op_t *uop) switch ( op.cmd ) { case PHYSDEVOP_CFGREG_READ: - ret = pci_cfgreg_read (op.u.cfg_read.seg, op.u.cfg_read.bus, - op.u.cfg_read.dev, op.u.cfg_read.func, - op.u.cfg_read.reg, op.u.cfg_read.len, - &op.u.cfg_read.value); + ret = pci_cfgreg_read(op.u.cfg_read.seg, op.u.cfg_read.bus, + op.u.cfg_read.dev, op.u.cfg_read.func, + op.u.cfg_read.reg, op.u.cfg_read.len, + &op.u.cfg_read.value); break; case PHYSDEVOP_CFGREG_WRITE: - ret = pci_cfgreg_write (op.u.cfg_write.seg, op.u.cfg_write.bus, - op.u.cfg_write.dev, op.u.cfg_write.func, - op.u.cfg_write.reg, op.u.cfg_write.len, - op.u.cfg_write.value); + ret = pci_cfgreg_write(op.u.cfg_write.seg, op.u.cfg_write.bus, + op.u.cfg_write.dev, op.u.cfg_write.func, + op.u.cfg_write.reg, op.u.cfg_write.len, + op.u.cfg_write.value); break; case PHYSDEVOP_FIND_IRQ: - ret = pci_find_irq (op.u.find_irq.seg, op.u.find_irq.bus, - op.u.find_irq.dev, op.u.find_irq.func, - &op.u.find_irq.irq); - break; - - case PHYSDEVOP_REQUEST_IRQ: - ret = pci_request_irq (op.u.request_irq.irq); - break; - - case PHYSDEVOP_FREE_IRQ: - ret = pci_free_irq (op.u.free_irq.irq); - break; - - case PHYSDEVOP_ENABLE_IRQ: - ret = pci_enable_irq (op.u.enable_irq.irq); - break; - - case PHYSDEVOP_DISABLE_IRQ: - ret = pci_disable_irq (op.u.disable_irq.irq); + ret = pci_find_irq(op.u.find_irq.seg, op.u.find_irq.bus, + op.u.find_irq.dev, op.u.find_irq.func, + &op.u.find_irq.irq); break; - case PHYSDEVOP_FINISHED_IRQ: - ret = pci_finished_irq (op.u.finished_irq.irq); + case PHYSDEVOP_UNMASK_IRQ: + ret = pci_unmask_irq(); break; default: diff --git a/xen/include/hypervisor-ifs/dom0_ops.h b/xen/include/hypervisor-ifs/dom0_ops.h index 8574f02531..ce748d5d31 100644 --- a/xen/include/hypervisor-ifs/dom0_ops.h +++ b/xen/include/hypervisor-ifs/dom0_ops.h @@ -18,7 +18,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 0xAAAA0009 +#define DOM0_INTERFACE_VERSION 0xAAAA000A #define MAX_CMD_LEN 256 #define MAX_DOMAIN_NAME 16 diff --git a/xen/include/hypervisor-ifs/event_channel.h b/xen/include/hypervisor-ifs/event_channel.h index 6fae72cc38..fdc4eaeb1b 100644 --- a/xen/include/hypervisor-ifs/event_channel.h +++ b/xen/include/hypervisor-ifs/event_channel.h @@ -30,7 +30,7 @@ typedef struct evtchn_bind_interdomain * NOTES: * 1. A virtual IRQ may be bound to at most one event channel per domain. */ -#define EVTCHNOP_bind_virq 1 +#define EVTCHNOP_bind_virq 1 typedef struct evtchn_bind_virq { /* IN parameters. */ @@ -40,6 +40,21 @@ typedef struct evtchn_bind_virq } evtchn_bind_virq_t; /* + * EVTCHNOP_bind_pirq: Bind a local event channel to IRQ <irq>. + * NOTES: + * 1. A physical IRQ may be bound to at most one event channel per domain. + * 2. Only a sufficiently-privileged domain may bind to a physical IRQ. + */ +#define EVTCHNOP_bind_pirq 2 +typedef struct evtchn_bind_pirq +{ + /* IN parameters. */ + int pirq; + /* OUT parameters. */ + int port; +} evtchn_bind_pirq_t; + +/* * EVTCHNOP_close: Close the communication channel which has an endpoint at * <dom, port>. * NOTES: @@ -47,7 +62,7 @@ typedef struct evtchn_bind_virq * 2. Only a sufficiently-privileged domain may close an event channel * for which <dom> is not DOMID_SELF. */ -#define EVTCHNOP_close 2 +#define EVTCHNOP_close 3 typedef struct evtchn_close { /* IN parameters. */ @@ -60,7 +75,7 @@ typedef struct evtchn_close * EVTCHNOP_send: Send an event to the remote end of the channel whose local * endpoint is <DOMID_SELF, local_port>. */ -#define EVTCHNOP_send 3 +#define EVTCHNOP_send 4 typedef struct evtchn_send { /* IN parameters. */ @@ -76,7 +91,7 @@ typedef struct evtchn_send * 2. Only a sufficiently-privileged domain may obtain the status of an event * channel for which <dom> is not DOMID_SELF. */ -#define EVTCHNOP_status 4 +#define EVTCHNOP_status 5 typedef struct evtchn_status { /* IN parameters */ @@ -86,8 +101,8 @@ typedef struct evtchn_status #define EVTCHNSTAT_closed 0 /* Chennel is not in use. */ #define EVTCHNSTAT_unbound 1 /* Channel is not bound to a source. */ #define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */ -#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ -#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ +#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */ +#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */ int status; union { int __none; /* EVTCHNSTAT_closed, EVTCHNSTAT_unbound */ @@ -106,6 +121,7 @@ typedef struct evtchn_op union { evtchn_bind_interdomain_t bind_interdomain; evtchn_bind_virq_t bind_virq; + evtchn_bind_pirq_t bind_pirq; evtchn_close_t close; evtchn_send_t send; evtchn_status_t status; diff --git a/xen/include/hypervisor-ifs/physdev.h b/xen/include/hypervisor-ifs/physdev.h index 925023056c..383bb13097 100644 --- a/xen/include/hypervisor-ifs/physdev.h +++ b/xen/include/hypervisor-ifs/physdev.h @@ -19,11 +19,7 @@ #define PHYSDEVOP_CFGREG_READ 0 #define PHYSDEVOP_CFGREG_WRITE 1 #define PHYSDEVOP_FIND_IRQ 2 -#define PHYSDEVOP_REQUEST_IRQ 3 -#define PHYSDEVOP_FREE_IRQ 4 -#define PHYSDEVOP_ENABLE_IRQ 5 -#define PHYSDEVOP_DISABLE_IRQ 6 -#define PHYSDEVOP_FINISHED_IRQ 7 +#define PHYSDEVOP_UNMASK_IRQ 3 /* read pci config */ typedef struct physdevop_cfgreg_read_st @@ -32,8 +28,8 @@ typedef struct physdevop_cfgreg_read_st int bus; /* IN */ int dev; /* IN */ int func; /* IN */ - int reg; /* IN */ - int len; /* IN */ + int reg; /* IN */ + int len; /* IN */ u32 value; /* OUT */ } physdevop_cfgreg_read_t; @@ -59,36 +55,6 @@ typedef struct physdevop_find_irq_st u32 irq; /* OUT */ } physdevop_find_irq_t; -/* request physical IRQ to be routed to guest */ -typedef struct physdevop_request_irq_st -{ - u32 irq; /* IN */ -} physdevop_request_irq_t; - -/* stop routing physical interrupts to guest */ -typedef struct physdevop_free_irq_st -{ - u32 irq; /* IN */ -} physdevop_free_irq_t; - -/* enable IRQ for the caller */ -typedef struct physdevop_enable_irq_st -{ - u32 irq; /* IN */ -} physdevop_enable_irq_t; - -/* disable interrupts */ -typedef struct physdevop_disable_irq_st -{ - u32 irq; /* IN */ -} physdevop_disable_irq_t; - -typedef struct physdevop_finished_irq_st -{ - u32 irq; /* IN */ -} physdevop_finished_irq_t; - - typedef struct _physdev_op_st { unsigned long cmd; @@ -99,11 +65,6 @@ typedef struct _physdev_op_st physdevop_cfgreg_read_t cfg_read; physdevop_cfgreg_write_t cfg_write; physdevop_find_irq_t find_irq; - physdevop_request_irq_t request_irq; - physdevop_free_irq_t free_irq; - physdevop_enable_irq_t enable_irq; - physdevop_disable_irq_t disable_irq; - physdevop_finished_irq_t finished_irq; } u; } physdev_op_t; diff --git a/xenolinux-2.4.25-sparse/arch/xen/kernel/Makefile b/xenolinux-2.4.25-sparse/arch/xen/kernel/Makefile index 9f86b6d297..5abf0a0d62 100644 --- a/xenolinux-2.4.25-sparse/arch/xen/kernel/Makefile +++ b/xenolinux-2.4.25-sparse/arch/xen/kernel/Makefile @@ -10,7 +10,7 @@ export-objs := i386_ksyms.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \ - i386_ksyms.o i387.o evtchn.o physirq.o pci-dma.o + i386_ksyms.o i387.o evtchn.o pci-dma.o ifdef CONFIG_PCI obj-y += pci-i386.o pci-pc.o pci-irq.o diff --git a/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c b/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c index 266867fc74..4eb83c4b4c 100644 --- a/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c +++ b/xenolinux-2.4.25-sparse/arch/xen/kernel/evtchn.c @@ -17,20 +17,23 @@ #include <asm/synch_bitops.h> #include <asm/hypervisor.h> #include <asm/hypervisor-ifs/event_channel.h> - -/* Dynamic IRQ <-> event-channel mappings. */ -static int evtchn_to_dynirq[1024]; -static int dynirq_to_evtchn[NR_IRQS]; - -/* Dynamic IRQ <-> VIRQ mapping. */ -static int virq_to_dynirq[NR_VIRQS]; +#include <asm/hypervisor-ifs/physdev.h> /* - * Reference counts for bindings to dynamic IRQs. - * NB. This array is referenced with respect to DYNIRQ_BASE! + * This lock protects updates to the following mapping and reference-count + * arrays. The lock does not need to be acquired to read the mapping tables. */ -static int dynirq_bindcount[NR_DYNIRQS]; -static spinlock_t dynirq_lock; +static spinlock_t irq_mapping_update_lock; + +/* IRQ <-> event-channel mappings. */ +static int evtchn_to_irq[NR_EVENT_CHANNELS]; +static int irq_to_evtchn[NR_IRQS]; + +/* IRQ <-> VIRQ mapping. */ +static int virq_to_irq[NR_VIRQS]; + +/* Reference counts for bindings to IRQs. */ +static int irq_bindcount[NR_IRQS]; /* Upcall to generic IRQ layer. */ extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs); @@ -39,7 +42,7 @@ static void evtchn_handle_normal(shared_info_t *s, struct pt_regs *regs) { unsigned long l1, l2; unsigned int l1i, l2i, port; - int dynirq; + int irq; l1 = xchg(&s->evtchn_pending_sel, 0); while ( (l1i = ffs(l1)) != 0 ) @@ -54,8 +57,8 @@ static void evtchn_handle_normal(shared_info_t *s, struct pt_regs *regs) l2 &= ~(1 << l2i); port = (l1i << 5) + l2i; - if ( (dynirq = evtchn_to_dynirq[port]) != -1 ) - do_IRQ(dynirq + DYNIRQ_BASE, regs); + if ( (irq = evtchn_to_irq[port]) != -1 ) + do_IRQ(irq, regs); else evtchn_device_upcall(port, 0); } @@ -66,7 +69,7 @@ static void evtchn_handle_exceptions(shared_info_t *s, struct pt_regs *regs) { unsigned long l1, l2; unsigned int l1i, l2i, port; - int dynirq; + int irq; l1 = xchg(&s->evtchn_exception_sel, 0); while ( (l1i = ffs(l1)) != 0 ) @@ -81,10 +84,9 @@ static void evtchn_handle_exceptions(shared_info_t *s, struct pt_regs *regs) l2 &= ~(1 << l2i); port = (l1i << 5) + l2i; - if ( (dynirq = evtchn_to_dynirq[port]) != -1 ) + if ( (irq = evtchn_to_irq[port]) != -1 ) { - printk(KERN_ALERT "Error on IRQ line %d!\n", - dynirq + DYNIRQ_BASE); + printk(KERN_ALERT "Error on IRQ line %d!\n", irq); synch_clear_bit(port, &s->evtchn_exception[0]); } else @@ -112,28 +114,28 @@ void evtchn_do_upcall(struct pt_regs *regs) } -static int find_unbound_dynirq(void) +static int find_unbound_irq(void) { - int i; + int irq; - for ( i = 0; i < NR_DYNIRQS; i++ ) - if ( dynirq_bindcount[i] == 0 ) + for ( irq = 0; irq < NR_IRQS; irq++ ) + if ( irq_bindcount[irq] == 0 ) break; - if ( i == NR_DYNIRQS ) + if ( irq == NR_IRQS ) BUG(); - return i; + return irq; } int bind_virq_to_irq(int virq) { evtchn_op_t op; - int evtchn, dynirq; + int evtchn, irq; - spin_lock(&dynirq_lock); + spin_lock(&irq_mapping_update_lock); - if ( (dynirq = virq_to_dynirq[virq]) == -1 ) + if ( (irq = virq_to_irq[virq]) == -1 ) { op.cmd = EVTCHNOP_bind_virq; op.u.bind_virq.virq = virq; @@ -141,29 +143,29 @@ int bind_virq_to_irq(int virq) BUG(); evtchn = op.u.bind_virq.port; - dynirq = find_unbound_dynirq(); - evtchn_to_dynirq[evtchn] = dynirq; - dynirq_to_evtchn[dynirq] = evtchn; + irq = find_unbound_irq(); + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; - virq_to_dynirq[virq] = dynirq; + virq_to_irq[virq] = irq; } - dynirq_bindcount[dynirq]++; + irq_bindcount[irq]++; - spin_unlock(&dynirq_lock); + spin_unlock(&irq_mapping_update_lock); - return dynirq + DYNIRQ_BASE; + return irq; } void unbind_virq_from_irq(int virq) { evtchn_op_t op; - int dynirq = virq_to_dynirq[virq]; - int evtchn = dynirq_to_evtchn[dynirq]; + int irq = virq_to_irq[virq]; + int evtchn = irq_to_evtchn[irq]; - spin_lock(&dynirq_lock); + spin_lock(&irq_mapping_update_lock); - if ( --dynirq_bindcount[dynirq] == 0 ) + if ( --irq_bindcount[irq] == 0 ) { op.cmd = EVTCHNOP_close; op.u.close.dom = DOMID_SELF; @@ -171,47 +173,47 @@ void unbind_virq_from_irq(int virq) if ( HYPERVISOR_event_channel_op(&op) != 0 ) BUG(); - evtchn_to_dynirq[evtchn] = -1; - dynirq_to_evtchn[dynirq] = -1; - virq_to_dynirq[virq] = -1; + evtchn_to_irq[evtchn] = -1; + irq_to_evtchn[irq] = -1; + virq_to_irq[virq] = -1; } - spin_unlock(&dynirq_lock); + spin_unlock(&irq_mapping_update_lock); } int bind_evtchn_to_irq(int evtchn) { - int dynirq; + int irq; - spin_lock(&dynirq_lock); + spin_lock(&irq_mapping_update_lock); - if ( (dynirq = evtchn_to_dynirq[evtchn]) == -1 ) + if ( (irq = evtchn_to_irq[evtchn]) == -1 ) { - dynirq = find_unbound_dynirq(); - evtchn_to_dynirq[evtchn] = dynirq; - dynirq_to_evtchn[dynirq] = evtchn; + irq = find_unbound_irq(); + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; } - dynirq_bindcount[dynirq]++; + irq_bindcount[irq]++; - spin_unlock(&dynirq_lock); + spin_unlock(&irq_mapping_update_lock); - return dynirq + DYNIRQ_BASE; + return irq; } void unbind_evtchn_from_irq(int evtchn) { - int dynirq = evtchn_to_dynirq[evtchn]; + int irq = evtchn_to_irq[evtchn]; - spin_lock(&dynirq_lock); + spin_lock(&irq_mapping_update_lock); - if ( --dynirq_bindcount[dynirq] == 0 ) + if ( --irq_bindcount[irq] == 0 ) { - evtchn_to_dynirq[evtchn] = -1; - dynirq_to_evtchn[dynirq] = -1; + evtchn_to_irq[evtchn] = -1; + irq_to_evtchn[irq] = -1; } - spin_unlock(&dynirq_lock); + spin_unlock(&irq_mapping_update_lock); } @@ -221,41 +223,35 @@ void unbind_evtchn_from_irq(int evtchn) static unsigned int startup_dynirq(unsigned int irq) { - int dynirq = irq - DYNIRQ_BASE; - unmask_evtchn(dynirq_to_evtchn[dynirq]); + unmask_evtchn(irq_to_evtchn[irq]); return 0; } static void shutdown_dynirq(unsigned int irq) { - int dynirq = irq - DYNIRQ_BASE; - mask_evtchn(dynirq_to_evtchn[dynirq]); + mask_evtchn(irq_to_evtchn[irq]); } static void enable_dynirq(unsigned int irq) { - int dynirq = irq - DYNIRQ_BASE; - unmask_evtchn(dynirq_to_evtchn[dynirq]); + unmask_evtchn(irq_to_evtchn[irq]); } static void disable_dynirq(unsigned int irq) { - int dynirq = irq - DYNIRQ_BASE; - mask_evtchn(dynirq_to_evtchn[dynirq]); + mask_evtchn(irq_to_evtchn[irq]); } static void ack_dynirq(unsigned int irq) { - int dynirq = irq - DYNIRQ_BASE; - mask_evtchn(dynirq_to_evtchn[dynirq]); - clear_evtchn(dynirq_to_evtchn[dynirq]); + mask_evtchn(irq_to_evtchn[irq]); + clear_evtchn(irq_to_evtchn[irq]); } static void end_dynirq(unsigned int irq) { - int dynirq = irq - DYNIRQ_BASE; if ( !(irq_desc[irq].status & IRQ_DISABLED) ) - unmask_evtchn(dynirq_to_evtchn[dynirq]); + unmask_evtchn(irq_to_evtchn[irq]); } static struct hw_interrupt_type dynirq_type = { @@ -269,6 +265,87 @@ static struct hw_interrupt_type dynirq_type = { NULL }; +static inline void pirq_unmask_notify(int pirq) +{ + physdev_op_t op; + op.cmd = PHYSDEVOP_UNMASK_IRQ; + (void)HYPERVISOR_physdev_op(&op); +} + +static unsigned int startup_pirq(unsigned int irq) +{ + evtchn_op_t op; + int evtchn; + + op.cmd = EVTCHNOP_bind_pirq; + op.u.bind_pirq.pirq = irq; + if ( HYPERVISOR_event_channel_op(&op) != 0 ) + BUG(); + evtchn = op.u.bind_virq.port; + + evtchn_to_irq[evtchn] = irq; + irq_to_evtchn[irq] = evtchn; + + unmask_evtchn(evtchn); + pirq_unmask_notify(irq_to_pirq(irq)); + + return 0; +} + +static void shutdown_pirq(unsigned int irq) +{ + evtchn_op_t op; + int evtchn = irq_to_evtchn[irq]; + + mask_evtchn(evtchn); + + op.cmd = EVTCHNOP_close; + op.u.close.dom = DOMID_SELF; + op.u.close.port = evtchn; + if ( HYPERVISOR_event_channel_op(&op) != 0 ) + BUG(); + + evtchn_to_irq[evtchn] = -1; + irq_to_evtchn[irq] = -1; +} + +static void enable_pirq(unsigned int irq) +{ + unmask_evtchn(irq_to_evtchn[irq]); + pirq_unmask_notify(irq_to_pirq(irq)); +} + +static void disable_pirq(unsigned int irq) +{ + mask_evtchn(irq_to_evtchn[irq]); +} + +static void ack_pirq(unsigned int irq) +{ + mask_evtchn(irq_to_evtchn[irq]); + clear_evtchn(irq_to_evtchn[irq]); +} + +static void end_pirq(unsigned int irq) +{ + if ( !(irq_desc[irq].status & IRQ_DISABLED) ) + { + unmask_evtchn(irq_to_evtchn[irq]); + pirq_unmask_notify(irq_to_pirq(irq)); + } +} + +static struct hw_interrupt_type pirq_type = { + "Phys-irq", + startup_pirq, + shutdown_pirq, + enable_pirq, + disable_pirq, + ack_pirq, + end_pirq, + NULL +}; + static void error_interrupt(int irq, void *dev_id, struct pt_regs *regs) { printk(KERN_ALERT "unexpected VIRQ_ERROR trap to vector %d\n", irq); @@ -287,32 +364,41 @@ void __init init_IRQ(void) { int i; + spin_lock_init(&irq_mapping_update_lock); + + /* No VIRQ -> IRQ mappings. */ for ( i = 0; i < NR_VIRQS; i++ ) - virq_to_dynirq[i] = -1; + virq_to_irq[i] = -1; - for ( i = 0; i < 1024; i++ ) - evtchn_to_dynirq[i] = -1; + /* No event-channel -> IRQ mappings. */ + for ( i = 0; i < NR_EVENT_CHANNELS; i++ ) + evtchn_to_irq[i] = -1; + + /* No IRQ -> event-channel mappings. */ + for ( i = 0; i < NR_IRQS; i++ ) + irq_to_evtchn[i] = -1; for ( i = 0; i < NR_DYNIRQS; i++ ) { - dynirq_to_evtchn[i] = -1; - dynirq_bindcount[i] = 0; - } + /* Dynamic IRQ space is currently unbound. Zero the refcnts. */ + irq_bindcount[dynirq_to_irq(i)] = 0; - spin_lock_init(&dynirq_lock); + irq_desc[dynirq_to_irq(i)].status = IRQ_DISABLED; + irq_desc[dynirq_to_irq(i)].action = 0; + irq_desc[dynirq_to_irq(i)].depth = 1; + irq_desc[dynirq_to_irq(i)].handler = &dynirq_type; + } - for ( i = 0; i < NR_DYNIRQS; i++ ) + for ( i = 0; i < NR_PIRQS; i++ ) { - irq_desc[i + DYNIRQ_BASE].status = IRQ_DISABLED; - irq_desc[i + DYNIRQ_BASE].action = 0; - irq_desc[i + DYNIRQ_BASE].depth = 1; - irq_desc[i + DYNIRQ_BASE].handler = &dynirq_type; + /* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */ + irq_bindcount[pirq_to_irq(i)] = 1; + + irq_desc[pirq_to_irq(i)].status = IRQ_DISABLED; + irq_desc[pirq_to_irq(i)].action = 0; + irq_desc[pirq_to_irq(i)].depth = 1; + irq_desc[pirq_to_irq(i)].handler = &pirq_type; } (void)setup_irq(bind_virq_to_irq(VIRQ_ERROR), &error_action); - -#ifdef CONFIG_PCI - /* Also initialise the physical IRQ handlers. */ - physirq_init(); -#endif } diff --git a/xenolinux-2.4.25-sparse/arch/xen/kernel/physirq.c b/xenolinux-2.4.25-sparse/arch/xen/kernel/physirq.c deleted file mode 100644 index 7c04c9d9dc..0000000000 --- a/xenolinux-2.4.25-sparse/arch/xen/kernel/physirq.c +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- - **************************************************************************** - * (C) 2004 - Rolf Neugebauer - Intel Research Cambridge - **************************************************************************** - * - * File: physirq.c - * Author: Rolf Neugebauer (rolf.neugebauer@intel.com) - * Date: Mar 2004 - * - * Description: guests may receive virtual interrupts directly - * corresponding to physical interrupts. these virtual - * interrupts require special handling provided - * by the virq irq type. - */ - -#ifdef CONFIG_PCI - -#include <linux/config.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/hypervisor.h> -#include <asm/system.h> - -#include <linux/irq.h> -#include <linux/sched.h> - -#include <asm/hypervisor-ifs/hypervisor-if.h> -#include <asm/hypervisor-ifs/physdev.h> - -static void physirq_interrupt(int irq, void *unused, struct pt_regs *ptregs); - -static int setup_event_handler = 0; - -static unsigned int startup_physirq_event(unsigned int irq) -{ - physdev_op_t op; - int err; - - printk("startup_physirq_event %d\n", irq); - - /* - * install a interrupt handler for physirq event when called first time - * we actually are never executing the handler as _EVENT_PHYSIRQ is - * handled specially in hypervisor.c But we need to enable the event etc. - */ - if ( !setup_event_handler ) - { - printk("startup_physirq_event %d: setup event handler\n", irq); - /* set up a event handler to demux virtualised physical interrupts */ - err = request_irq(IRQ_FROM_XEN_VIRQ(VIRQ_PHYSIRQ), physirq_interrupt, - SA_SAMPLE_RANDOM, "physirq", NULL); - if ( err ) - { - printk(KERN_WARNING "Could not allocate physirq interrupt\n"); - return err; - } - setup_event_handler = 1; - } - - /* - * request the irq from hypervisor - */ - op.cmd = PHYSDEVOP_REQUEST_IRQ; - op.u.request_irq.irq = irq; - if ( (err = HYPERVISOR_physdev_op(&op)) != 0 ) - { - printk(KERN_ALERT "could not get IRQ %d from Xen\n", irq); - return err; - } - return 0; -} -/* - * This is a dummy interrupt handler. - * It should never be called. events for physical interrupts are handled - * differently in hypervisor.c - */ -static void physirq_interrupt(int irq, void *unused, struct pt_regs *ptregs) -{ - printk("XXX This should never be called!"); -} - - -/* - * IRQ is not needed anymore. - */ -static void shutdown_physirq_event(unsigned int irq) -{ - physdev_op_t op; - int err; - - printk("shutdown_phys_irq called."); - - /* - * tell hypervisor - */ - op.cmd = PHYSDEVOP_FREE_IRQ; - op.u.free_irq.irq = irq; - if ( (err = HYPERVISOR_physdev_op(&op)) != 0 ) - { - printk(KERN_ALERT "could not free IRQ %d\n", irq); - return; - } - return; -} - - -static void enable_physirq_event(unsigned int irq) -{ - /* XXX just enable all phys interrupts for now */ - enable_irq(IRQ_FROM_XEN_VIRQ(VIRQ_PHYSIRQ)); -} - -static void disable_physirq_event(unsigned int irq) -{ - /* XXX just disable all phys interrupts for now */ - disable_irq(IRQ_FROM_XEN_VIRQ(VIRQ_PHYSIRQ)); -} - -static void ack_physirq_event(unsigned int irq) -{ - /* clear bit */ - if ( irq <= 0 || irq >= 32 ) - { - printk("wrong irq %d\n", irq); - } - - clear_bit(irq, &HYPERVISOR_shared_info->physirq_pend); -} - -static void end_physirq_event(unsigned int irq) -{ - int err; - physdev_op_t op; - - /* call hypervisor */ - op.cmd = PHYSDEVOP_FINISHED_IRQ; - op.u.finished_irq.irq = irq; - if ( (err = HYPERVISOR_physdev_op(&op)) != 0 ) - { - printk(KERN_ALERT "could not finish IRQ %d\n", irq); - return; - } - return; -} - -static struct hw_interrupt_type physirq_irq_type = { - "physical-irq", - startup_physirq_event, - shutdown_physirq_event, - enable_physirq_event, - disable_physirq_event, - ack_physirq_event, - end_physirq_event, - NULL -}; - - - -void __init physirq_init(void) -{ - int i; - - printk("Initialise irq handlers [%d-%d] for physical interrupts.\n", - PHYS_IRQ_BASE, PHYS_IRQ_BASE+NR_PHYS_IRQS-1); - - for ( i = 0; i < NR_PHYS_IRQS; i++ ) - { - irq_desc[i + PHYS_IRQ_BASE].status = IRQ_DISABLED; - irq_desc[i + PHYS_IRQ_BASE].action = 0; - irq_desc[i + PHYS_IRQ_BASE].depth = 1; - irq_desc[i + PHYS_IRQ_BASE].handler = &physirq_irq_type; - } -} - -#endif diff --git a/xenolinux-2.4.25-sparse/include/asm-xen/irq.h b/xenolinux-2.4.25-sparse/include/asm-xen/irq.h index 6d175ce6ab..a05b99640e 100644 --- a/xenolinux-2.4.25-sparse/include/asm-xen/irq.h +++ b/xenolinux-2.4.25-sparse/include/asm-xen/irq.h @@ -32,7 +32,11 @@ #define NR_IRQS (NR_PIRQS + NR_DYNIRQS) -extern void physirq_init(void); +#define pirq_to_irq(_x) ((_x) + PIRQ_BASE) +#define irq_to_pirq(_x) ((_x) - PIRQ_BASE) + +#define dynirq_to_irq(_x) ((_x) + DYNIRQ_BASE) +#define irq_to_dynirq(_x) ((_x) - DYNIRQ_BASE) /* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */ extern int bind_virq_to_irq(int virq); @@ -40,14 +44,13 @@ extern void unbind_virq_from_irq(int virq); extern int bind_evtchn_to_irq(int evtchn); extern void unbind_evtchn_from_irq(int evtchn); -#define irq_cannonicalize(_irq) (_irq) +static __inline__ int irq_cannonicalize(int irq) +{ + return (irq == 2) ? 9 : irq; +} extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); -#ifdef CONFIG_X86_LOCAL_APIC -#define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */ -#endif - #endif /* _ASM_IRQ_H */ |