diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-05-12 15:54:24 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-05-12 15:54:24 +0000 |
commit | c9cbf814f77829b03cf273042c147b4ef754e939 (patch) | |
tree | ba86fe2ad548b575e5dd835aadbbd7ec09682599 /xen | |
parent | 95e7814b6642863a49ad38d6a64b7eedde195b71 (diff) | |
download | xen-c9cbf814f77829b03cf273042c147b4ef754e939.tar.gz xen-c9cbf814f77829b03cf273042c147b4ef754e939.tar.bz2 xen-c9cbf814f77829b03cf273042c147b4ef754e939.zip |
bitkeeper revision 1.891.1.12 (40a248b0WTGoOa9206iWkyGN0mTPNw)
Allow forcing of IRQ trigger-type to edge or level
(NB. DANGEROUS!).
Diffstat (limited to 'xen')
-rw-r--r-- | xen/arch/i386/io_apic.c | 136 | ||||
-rw-r--r-- | xen/arch/i386/irq.c | 6 | ||||
-rw-r--r-- | xen/common/kernel.c | 44 | ||||
-rw-r--r-- | xen/common/physdev.c | 19 | ||||
-rw-r--r-- | xen/include/hypervisor-ifs/physdev.h | 62 |
5 files changed, 212 insertions, 55 deletions
diff --git a/xen/arch/i386/io_apic.c b/xen/arch/i386/io_apic.c index 3f0c81be7a..7c307922b3 100644 --- a/xen/arch/i386/io_apic.c +++ b/xen/arch/i386/io_apic.c @@ -208,7 +208,11 @@ static void set_ioapic_affinity (unsigned int irq, unsigned long mask) spin_unlock_irqrestore(&ioapic_lock, flags); } -#if CONFIG_SMP +/* + * In new I/O model, the interrupt is pinned to the CPU of the first + * device-driver domain that attaches. Dynamic balancing is pointless. + */ +#if defined(CONFIG_SMP) && !defined(NO_DEVICES_IN_XEN) typedef struct { unsigned int cpu; @@ -220,8 +224,6 @@ static irq_balance_t irq_balance[NR_IRQS] __cacheline_aligned extern unsigned long irq_affinity [NR_IRQS]; -#endif - #define IDLE_ENOUGH(cpu,now) \ (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1)) @@ -256,7 +258,6 @@ inside: static inline void balance_irq(int irq) { -#if CONFIG_SMP irq_balance_t *entry = irq_balance + irq; unsigned long now = jiffies; @@ -272,9 +273,14 @@ static inline void balance_irq(int irq) entry->cpu = move(entry->cpu, allowed_mask, now, random_number); set_ioapic_affinity(irq, apicid_to_phys_cpu_present(entry->cpu)); } -#endif } +#else + +#define balance_irq(_irq) ((void)0) + +#endif + /* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. @@ -883,6 +889,7 @@ void __init UNEXPECTED_IO_APIC(void) void __init print_IO_APIC(void) { +#ifndef NDEBUG int apic, i; struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_01 reg_01; @@ -1019,10 +1026,12 @@ void __init print_IO_APIC(void) } printk(KERN_INFO ".................................... done.\n"); - - return; +#endif } + +#if 0 /* Maybe useful for debugging, but not currently used anywhere. */ + static void print_APIC_bitfield (int base) { unsigned int v; @@ -1041,6 +1050,7 @@ static void print_APIC_bitfield (int base) } } + void /*__init*/ print_local_APIC(void * dummy) { unsigned int v, ver, maxlvt; @@ -1156,6 +1166,9 @@ void /*__init*/ print_PIC(void) printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); } +#endif /* 0 */ + + static void __init enable_IO_APIC(void) { struct IO_APIC_reg_01 reg_01; @@ -1874,7 +1887,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); if (edge_level) { - irq_desc[irq].handler = &ioapic_level_irq_type; + irq_desc[irq].handler = &ioapic_level_irq_type; } else { irq_desc[irq].handler = &ioapic_edge_irq_type; } @@ -1893,3 +1906,110 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a } #endif /*CONFIG_ACPI_BOOT*/ + +extern char opt_leveltrigger[], opt_edgetrigger[]; + +static int __init ioapic_trigger_setup(void) +{ + char *p; + irq_desc_t *desc; + long irq; + + p = opt_leveltrigger; + while ( *p != '\0' ) + { + irq = simple_strtol(p, &p, 10); + if ( (irq <= 0) || (irq >= NR_IRQS) ) + { + printk("IRQ '%ld' out of range in level-trigger list '%s'\n", + irq, opt_leveltrigger); + break; + } + + printk("Forcing IRQ %ld to level-trigger: ", irq); + + desc = &irq_desc[irq]; + spin_lock_irq(&desc->lock); + + if ( desc->handler == &ioapic_level_irq_type ) + { + printk("already level-triggered (no force applied).\n"); + } + else if ( desc->handler != &ioapic_edge_irq_type ) + { + printk("cannot force (can only force IO-APIC-edge IRQs).\n"); + } + else + { + desc->handler = &ioapic_level_irq_type; + __mask_IO_APIC_irq(irq); + __level_IO_APIC_irq(irq); + printk("done.\n"); + } + + spin_unlock_irq(&desc->lock); + + if ( *p == '\0' ) + break; + + if ( *p != ',' ) + { + printk("Unexpected character '%c' in level-trigger list '%s'\n", + *p, opt_leveltrigger); + break; + } + + p++; + } + + p = opt_edgetrigger; + while ( *p != '\0' ) + { + irq = simple_strtol(p, &p, 10); + if ( (irq <= 0) || (irq >= NR_IRQS) ) + { + printk("IRQ '%ld' out of range in edge-trigger list '%s'\n", + irq, opt_edgetrigger); + break; + } + + printk("Forcing IRQ %ld to edge-trigger: ", irq); + + desc = &irq_desc[irq]; + spin_lock_irq(&desc->lock); + + if ( desc->handler == &ioapic_edge_irq_type ) + { + printk("already edge-triggered (no force applied).\n"); + } + else if ( desc->handler != &ioapic_level_irq_type ) + { + printk("cannot force (can only force IO-APIC-level IRQs).\n"); + } + else + { + desc->handler = &ioapic_edge_irq_type; + __edge_IO_APIC_irq(irq); + desc->status |= IRQ_PENDING; /* may have lost a masked edge */ + printk("done.\n"); + } + + spin_unlock_irq(&desc->lock); + + if ( *p == '\0' ) + break; + + if ( *p != ',' ) + { + printk("Unexpected character '%c' in edge-trigger list '%s'\n", + *p, opt_edgetrigger); + break; + } + + p++; + } + + return 0; +} + +__initcall(ioapic_trigger_setup); diff --git a/xen/arch/i386/irq.c b/xen/arch/i386/irq.c index d3eaf6af12..5b16bb0e63 100644 --- a/xen/arch/i386/irq.c +++ b/xen/arch/i386/irq.c @@ -39,6 +39,7 @@ #include <xen/delay.h> #include <xen/timex.h> #include <xen/perfc.h> +#include <asm/smpboot.h> /* * Linux has a controller-independent x86 interrupt architecture. @@ -1034,6 +1035,11 @@ int pirq_guest_bind(struct task_struct *p, int irq, int will_share) desc->status |= IRQ_GUEST; desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING); desc->handler->startup(irq); + + /* Attempt to bind the interrupt target to the correct CPU. */ + if ( desc->handler->set_affinity != NULL ) + desc->handler->set_affinity( + irq, apicid_to_phys_cpu_present(p->processor)); } else if ( !will_share || !action->shareable ) { diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 6cd567d601..dd6fcefa58 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -74,31 +74,37 @@ unsigned char opt_pdb[10] = "none"; unsigned int opt_tbuf_size = 1; /* opt_sched: scheduler - default to Borrowed Virtual Time */ char opt_sched[10] = "bvt"; -/* opt_physdev_dom0_hide: list of PCI slots to hide from dom0 - * Should have the format '(%02x:%02x.%1x)(%02x:%02x.%1x)...etc' */ -char opt_physdev_dom0_hide[20] = ""; +/* opt_physdev_dom0_hide: list of PCI slots to hide from domain 0. */ +/* Format is '(%02x:%02x.%1x)(%02x:%02x.%1x)' and so on. */ +char opt_physdev_dom0_hide[200] = ""; +/* opt_leveltrigger, opt_edgetrigger: Force an IO-APIC-routed IRQ to be */ +/* level- or edge-triggered. */ +/* Example: 'leveltrigger=4,5,6,20 edgetrigger=21'. */ +char opt_leveltrigger[30] = "", opt_edgetrigger[30] = ""; static struct { unsigned char *name; enum { OPT_IP, OPT_STR, OPT_UINT, OPT_BOOL } type; void *var; } opts[] = { - { "console", OPT_STR, &opt_console }, - { "ser_baud", OPT_UINT, &opt_ser_baud }, - { "com1", OPT_STR, &opt_com1 }, - { "com2", OPT_STR, &opt_com2 }, - { "dom0_mem", OPT_UINT, &opt_dom0_mem }, - { "ifname", OPT_STR, &opt_ifname }, - { "noht", OPT_BOOL, &opt_noht }, - { "noacpi", OPT_BOOL, &opt_noacpi }, - { "nosmp", OPT_BOOL, &opt_nosmp }, - { "noreboot", OPT_BOOL, &opt_noreboot }, - { "ignorebiostables", OPT_BOOL, &opt_ignorebiostables }, - { "watchdog", OPT_BOOL, &opt_watchdog }, - { "pdb", OPT_STR, &opt_pdb }, - { "tbuf_size", OPT_UINT, &opt_tbuf_size }, - { "sched", OPT_STR, &opt_sched }, - { "physdev_dom0_hide",OPT_STR, &opt_physdev_dom0_hide }, + { "console", OPT_STR, &opt_console }, + { "ser_baud", OPT_UINT, &opt_ser_baud }, + { "com1", OPT_STR, &opt_com1 }, + { "com2", OPT_STR, &opt_com2 }, + { "dom0_mem", OPT_UINT, &opt_dom0_mem }, + { "ifname", OPT_STR, &opt_ifname }, + { "noht", OPT_BOOL, &opt_noht }, + { "noacpi", OPT_BOOL, &opt_noacpi }, + { "nosmp", OPT_BOOL, &opt_nosmp }, + { "noreboot", OPT_BOOL, &opt_noreboot }, + { "ignorebiostables", OPT_BOOL, &opt_ignorebiostables }, + { "watchdog", OPT_BOOL, &opt_watchdog }, + { "pdb", OPT_STR, &opt_pdb }, + { "tbuf_size", OPT_UINT, &opt_tbuf_size }, + { "sched", OPT_STR, &opt_sched }, + { "physdev_dom0_hide", OPT_STR, &opt_physdev_dom0_hide }, + { "leveltrigger", OPT_STR, &opt_leveltrigger }, + { "edgetrigger", OPT_STR, &opt_edgetrigger }, { NULL, 0, NULL } }; diff --git a/xen/common/physdev.c b/xen/common/physdev.c index d15183cb6e..61b7b22cb2 100644 --- a/xen/common/physdev.c +++ b/xen/common/physdev.c @@ -634,9 +634,10 @@ static long pci_probe_root_buses(u32 *busmask) */ long do_physdev_op(physdev_op_t *uop) { - phys_dev_t *pdev; + phys_dev_t *pdev; physdev_op_t op; - long ret; + long ret; + int irq; if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) return -EFAULT; @@ -674,10 +675,22 @@ long do_physdev_op(physdev_op_t *uop) ret = pci_probe_root_buses(op.u.pci_probe_root_buses.busmask); break; - case PHYSDEVOP_UNMASK_IRQ: + case PHYSDEVOP_IRQ_UNMASK_NOTIFY: ret = pirq_guest_unmask(current); break; + case PHYSDEVOP_IRQ_STATUS_QUERY: + irq = op.u.irq_status_query.irq; + ret = -EINVAL; + if ( (irq < 0) || (irq >= NR_IRQS) ) + break; + op.u.irq_status_query.flags = 0; + /* Edge-triggered interrupts don't need an explicit unmask downcall. */ + if ( strstr(irq_desc[irq].handler->typename, "edge") == NULL ) + op.u.irq_status_query.flags |= PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY; + ret = 0; + break; + default: ret = -EINVAL; break; diff --git a/xen/include/hypervisor-ifs/physdev.h b/xen/include/hypervisor-ifs/physdev.h index 914a555981..50372bf2be 100644 --- a/xen/include/hypervisor-ifs/physdev.h +++ b/xen/include/hypervisor-ifs/physdev.h @@ -14,44 +14,55 @@ #define PHYSDEVOP_PCI_CFGREG_WRITE 1 #define PHYSDEVOP_PCI_INITIALISE_DEVICE 2 #define PHYSDEVOP_PCI_PROBE_ROOT_BUSES 3 -#define PHYSDEVOP_UNMASK_IRQ 4 +#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4 +#define PHYSDEVOP_IRQ_STATUS_QUERY 5 /* Read from PCI configuration space. */ -typedef struct physdevop_pci_cfgreg_read_st -{ - int bus; /* IN */ - int dev; /* IN */ - int func; /* IN */ - int reg; /* IN */ - int len; /* IN */ - u32 value; /* OUT */ +typedef struct { + /* IN */ + int bus; + int dev; + int func; + int reg; + int len; + /* OUT */ + u32 value; } physdevop_pci_cfgreg_read_t; /* Write to PCI configuration space. */ -typedef struct physdevop_pci_cfgreg_write_st -{ - int bus; /* IN */ - int dev; /* IN */ - int func; /* IN */ - int reg; /* IN */ - int len; /* IN */ - u32 value; /* IN */ +typedef struct { + /* IN */ + int bus; + int dev; + int func; + int reg; + int len; + u32 value; } physdevop_pci_cfgreg_write_t; /* Do final initialisation of a PCI device (e.g., last-moment IRQ routing). */ -typedef struct physdevop_pci_initialise_device_st -{ - int bus; /* IN */ - int dev; /* IN */ - int func; /* IN */ +typedef struct { + /* IN */ + int bus; + int dev; + int func; } physdevop_pci_initialise_device_t; /* Find the root buses for subsequent scanning. */ -typedef struct physdevop_pci_probe_root_buses_st -{ - u32 busmask[256/32]; /* OUT */ +typedef struct { + /* OUT */ + u32 busmask[256/32]; } physdevop_pci_probe_root_buses_t; +typedef struct { + /* IN */ + int irq; + /* OUT */ +/* Need to call PHYSDEVOP_IRQ_UNMASK_NOTIFY when the IRQ has been serviced? */ +#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY (1<<0) + unsigned long flags; +} physdevop_irq_status_query_t; + typedef struct _physdev_op_st { unsigned long cmd; @@ -61,6 +72,7 @@ typedef struct _physdev_op_st physdevop_pci_cfgreg_write_t pci_cfgreg_write; physdevop_pci_initialise_device_t pci_initialise_device; physdevop_pci_probe_root_buses_t pci_probe_root_buses; + physdevop_irq_status_query_t irq_status_query; } u; } physdev_op_t; |