aboutsummaryrefslogtreecommitdiffstats
path: root/xen
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-05-12 15:54:24 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-05-12 15:54:24 +0000
commitc9cbf814f77829b03cf273042c147b4ef754e939 (patch)
treeba86fe2ad548b575e5dd835aadbbd7ec09682599 /xen
parent95e7814b6642863a49ad38d6a64b7eedde195b71 (diff)
downloadxen-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.c136
-rw-r--r--xen/arch/i386/irq.c6
-rw-r--r--xen/common/kernel.c44
-rw-r--r--xen/common/physdev.c19
-rw-r--r--xen/include/hypervisor-ifs/physdev.h62
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;