ia64/xen-unstable

changeset 9734:b39365343de0

Big fixes for the new IO-APIC acknowledging method. The problems
were:
1. Some critical Xen interrupts could get blocked behind
unacknowledged guest interrupts. This is avoided by making
all Xen-bound interrrupts strictly higher priority.
2. Interrupts must not only be EOIed on the CPU that received
them, but also in reverse order when interrupts are nested.
A whole load of logic has been added to ensure this.

There are two boot parameters relating to all this:
'ioapic_ack=old' -- use the old IO-APIC ACK method
'ioapic_ack=new' -- use the new IO-APIC ACK method (default)
'force_intack' -- periodically force acknowledgement of
interrupts (default is no; useful for debugging)

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Apr 15 18:09:52 2006 +0100 (2006-04-15)
parents 4613f42db780
children 91da9a1b7196
files xen/arch/x86/i8259.c xen/arch/x86/io_apic.c xen/arch/x86/irq.c xen/arch/x86/smpboot.c xen/drivers/char/ns16550.c xen/drivers/char/serial.c xen/include/asm-x86/irq.h xen/include/asm-x86/mach-default/irq_vectors.h xen/include/xen/serial.h
line diff
     1.1 --- a/xen/arch/x86/i8259.c	Sat Apr 15 15:53:53 2006 +0100
     1.2 +++ b/xen/arch/x86/i8259.c	Sat Apr 15 18:09:52 2006 +0100
     1.3 @@ -318,7 +318,7 @@ void __init init_8259A(int auto_eoi)
     1.4       * outb_p - this has to work on a wide range of PC hardware.
     1.5       */
     1.6      outb_p(0x11, 0x20);     /* ICW1: select 8259A-1 init */
     1.7 -    outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
     1.8 +    outb_p(FIRST_LEGACY_VECTOR + 0, 0x21); /* ICW2: 8259A-1 IR0-7 */
     1.9      outb_p(0x04, 0x21);     /* 8259A-1 (the master) has a slave on IR2 */
    1.10      if (auto_eoi)
    1.11          outb_p(0x03, 0x21); /* master does Auto EOI */
    1.12 @@ -326,7 +326,7 @@ void __init init_8259A(int auto_eoi)
    1.13          outb_p(0x01, 0x21); /* master expects normal EOI */
    1.14  
    1.15      outb_p(0x11, 0xA0);     /* ICW1: select 8259A-2 init */
    1.16 -    outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
    1.17 +    outb_p(FIRST_LEGACY_VECTOR + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 */
    1.18      outb_p(0x02, 0xA1);     /* 8259A-2 is a slave on master's IR2 */
    1.19      outb_p(0x01, 0xA1);     /* (slave's support for AEOI in flat mode
    1.20                                 is to be investigated) */
     2.1 --- a/xen/arch/x86/io_apic.c	Sat Apr 15 15:53:53 2006 +0100
     2.2 +++ b/xen/arch/x86/io_apic.c	Sat Apr 15 18:09:52 2006 +0100
     2.3 @@ -669,11 +669,11 @@ static inline int IO_APIC_irq_trigger(in
     2.4  }
     2.5  
     2.6  /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
     2.7 -u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
     2.8 +u8 irq_vector[NR_IRQ_VECTORS] __read_mostly;
     2.9  
    2.10  int assign_irq_vector(int irq)
    2.11  {
    2.12 -    static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
    2.13 +    static int current_vector = FIRST_DYNAMIC_VECTOR, offset = 0;
    2.14  
    2.15      BUG_ON(irq >= NR_IRQ_VECTORS);
    2.16      if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
    2.17 @@ -689,11 +689,11 @@ next:
    2.18      if (current_vector == 0x80)
    2.19          goto next;
    2.20  
    2.21 -    if (current_vector >= FIRST_SYSTEM_VECTOR) {
    2.22 +    if (current_vector > LAST_DYNAMIC_VECTOR) {
    2.23          offset++;
    2.24          if (!(offset%8))
    2.25              return -ENOSPC;
    2.26 -        current_vector = FIRST_DEVICE_VECTOR + offset;
    2.27 +        current_vector = FIRST_DYNAMIC_VECTOR + offset;
    2.28      }
    2.29  
    2.30      vector_irq[current_vector] = irq;
    2.31 @@ -1333,15 +1333,24 @@ static unsigned int startup_level_ioapic
    2.32      return 0; /* don't check for pending */
    2.33  }
    2.34  
    2.35 -static int new_ack;
    2.36 -boolean_param("new_ack", new_ack);
    2.37 +int ioapic_ack_new = 1;
    2.38 +static void setup_ioapic_ack(char *s)
    2.39 +{
    2.40 +    if ( !strcmp(s, "old") )
    2.41 +        ioapic_ack_new = 0;
    2.42 +    else if ( !strcmp(s, "new") )
    2.43 +        ioapic_ack_new = 1;
    2.44 +    else
    2.45 +        printk("Unknown ioapic_ack value specified: '%s'\n", s);
    2.46 +}
    2.47 +custom_param("ioapic_ack", setup_ioapic_ack);
    2.48  
    2.49  static void mask_and_ack_level_ioapic_irq (unsigned int irq)
    2.50  {
    2.51      unsigned long v;
    2.52      int i;
    2.53  
    2.54 -    if ( new_ack )
    2.55 +    if ( ioapic_ack_new )
    2.56          return;
    2.57  
    2.58      mask_IO_APIC_irq(irq);
    2.59 @@ -1384,7 +1393,7 @@ static void end_level_ioapic_irq (unsign
    2.60      unsigned long v;
    2.61      int i;
    2.62  
    2.63 -    if ( !new_ack )
    2.64 +    if ( !ioapic_ack_new )
    2.65      {
    2.66          unmask_IO_APIC_irq(irq);
    2.67          return;
    2.68 @@ -1753,7 +1762,7 @@ void __init setup_IO_APIC(void)
    2.69          io_apic_irqs = ~PIC_IRQS;
    2.70  
    2.71      printk("ENABLING IO-APIC IRQs\n");
    2.72 -    printk(" -> Using %s ACK method\n", new_ack ? "new" : "old");
    2.73 +    printk(" -> Using %s ACK method\n", ioapic_ack_new ? "new" : "old");
    2.74  
    2.75      /*
    2.76       * Set up IO-APIC IRQ routing.
    2.77 @@ -2015,9 +2024,9 @@ int ioapic_guest_write(unsigned long phy
    2.78          return 0;
    2.79      }
    2.80  
    2.81 -    if ( old_rte.vector >= FIRST_DEVICE_VECTOR )
    2.82 +    if ( old_rte.vector >= FIRST_DYNAMIC_VECTOR )
    2.83          old_irq = vector_irq[old_rte.vector];
    2.84 -    if ( new_rte.vector >= FIRST_DEVICE_VECTOR )
    2.85 +    if ( new_rte.vector >= FIRST_DYNAMIC_VECTOR )
    2.86          new_irq = vector_irq[new_rte.vector];
    2.87  
    2.88      if ( (old_irq != new_irq) && (old_irq != -1) && IO_APIC_IRQ(old_irq) )
     3.1 --- a/xen/arch/x86/irq.c	Sat Apr 15 15:53:53 2006 +0100
     3.2 +++ b/xen/arch/x86/irq.c	Sat Apr 15 18:09:52 2006 +0100
     3.3 @@ -149,31 +149,49 @@ typedef struct {
     3.4      u8 in_flight;
     3.5      u8 shareable;
     3.6      u8 ack_type;
     3.7 -#define ACKTYPE_NONE   0 /* Final ACK is not required */
     3.8 -#define ACKTYPE_SINGLE 1 /* Final ACK on any CPU */
     3.9 -#define ACKTYPE_MULTI  2 /* Final ACK on the CPU that was interrupted */
    3.10 -    cpumask_t cpu_ack_map;
    3.11 +#define ACKTYPE_NONE   0     /* No final acknowledgement is required */
    3.12 +#define ACKTYPE_UNMASK 1     /* Unmask PIC hardware (from any CPU)   */
    3.13 +#define ACKTYPE_LAPIC_EOI  2 /* EOI on the CPU that was interrupted  */
    3.14 +    cpumask_t cpu_eoi_map;   /* CPUs that need to EOI this interrupt */
    3.15      struct domain *guest[IRQ_MAX_GUESTS];
    3.16  } irq_guest_action_t;
    3.17  
    3.18 +/*
    3.19 + * Stack of interrupts awaiting EOI on each CPU. These must be popped in
    3.20 + * order, as only the current highest-priority pending irq can be EOIed.
    3.21 + */
    3.22 +static struct {
    3.23 +    u8 vector;
    3.24 +    u8 ready_to_end;
    3.25 +} pending_lapic_eoi[NR_CPUS][NR_VECTORS] __cacheline_aligned;
    3.26 +#define pending_lapic_eoi_sp(cpu) (pending_lapic_eoi[cpu][NR_VECTORS-1].vector)
    3.27 +
    3.28  static void __do_IRQ_guest(int vector)
    3.29  {
    3.30      unsigned int        irq = vector_to_irq(vector);
    3.31      irq_desc_t         *desc = &irq_desc[vector];
    3.32      irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
    3.33      struct domain      *d;
    3.34 -    int                 i;
    3.35 +    int                 i, sp, cpu = smp_processor_id();
    3.36  
    3.37      if ( unlikely(action->nr_guests == 0) )
    3.38      {
    3.39 -        /* An interrupt may slip through while freeing an ACKTYPE_MULTI irq. */
    3.40 -        ASSERT(action->ack_type == ACKTYPE_MULTI);
    3.41 +        /* An interrupt may slip through while freeing a LAPIC_EOI irq. */
    3.42 +        ASSERT(action->ack_type == ACKTYPE_LAPIC_EOI);
    3.43          desc->handler->end(vector);
    3.44          return;
    3.45      }
    3.46  
    3.47 -    if ( action->ack_type == ACKTYPE_MULTI )
    3.48 -        cpu_set(smp_processor_id(), action->cpu_ack_map);
    3.49 +    if ( action->ack_type == ACKTYPE_LAPIC_EOI )
    3.50 +    {
    3.51 +        sp = pending_lapic_eoi_sp(cpu);
    3.52 +        ASSERT((sp == 0) || (pending_lapic_eoi[cpu][sp-1].vector < vector));
    3.53 +        ASSERT(sp < (NR_VECTORS-1));
    3.54 +        pending_lapic_eoi[cpu][sp].vector = vector;
    3.55 +        pending_lapic_eoi[cpu][sp].ready_to_end = 0;
    3.56 +        pending_lapic_eoi_sp(cpu) = sp+1;
    3.57 +        cpu_set(cpu, action->cpu_eoi_map);
    3.58 +    }
    3.59  
    3.60      for ( i = 0; i < action->nr_guests; i++ )
    3.61      {
    3.62 @@ -190,20 +208,49 @@ static void end_guest_irq(void *data)
    3.63      irq_desc_t         *desc = data;
    3.64      irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
    3.65      unsigned long       flags;
    3.66 +    int                 vector, sp, cpu = smp_processor_id();
    3.67 +
    3.68 +    vector = desc - irq_desc;
    3.69  
    3.70      spin_lock_irqsave(&desc->lock, flags);
    3.71 +
    3.72      if ( (desc->status & IRQ_GUEST) &&
    3.73           (action->in_flight == 0) &&
    3.74 -         test_and_clear_bit(smp_processor_id(), &action->cpu_ack_map) )
    3.75 -        desc->handler->end(desc - irq_desc);
    3.76 -    spin_unlock_irqrestore(&desc->lock, flags);    
    3.77 +         test_and_clear_bit(cpu, &action->cpu_eoi_map) )
    3.78 +    {
    3.79 +        sp = pending_lapic_eoi_sp(cpu);
    3.80 +        do {
    3.81 +            ASSERT(sp > 0);
    3.82 +        } while ( pending_lapic_eoi[cpu][--sp].vector != vector );
    3.83 +        ASSERT(!pending_lapic_eoi[cpu][sp].ready_to_end);
    3.84 +        pending_lapic_eoi[cpu][sp].ready_to_end = 1;
    3.85 +    }
    3.86 +
    3.87 +    for ( ; ; )
    3.88 +    {
    3.89 +        sp = pending_lapic_eoi_sp(cpu);
    3.90 +        if ( (sp == 0) || !pending_lapic_eoi[cpu][sp-1].ready_to_end )
    3.91 +        {
    3.92 +            spin_unlock_irqrestore(&desc->lock, flags);    
    3.93 +            return;
    3.94 +        }
    3.95 +        if ( pending_lapic_eoi[cpu][sp-1].vector != vector )
    3.96 +        {
    3.97 +            spin_unlock(&desc->lock);
    3.98 +            vector = pending_lapic_eoi[cpu][sp-1].vector;
    3.99 +            desc = &irq_desc[vector];
   3.100 +            spin_lock(&desc->lock);
   3.101 +        }
   3.102 +        desc->handler->end(vector);
   3.103 +        pending_lapic_eoi_sp(cpu) = sp-1;
   3.104 +    }
   3.105  }
   3.106  
   3.107  int pirq_guest_unmask(struct domain *d)
   3.108  {
   3.109      irq_desc_t         *desc;
   3.110      irq_guest_action_t *action;
   3.111 -    cpumask_t           cpu_ack_map = CPU_MASK_NONE;
   3.112 +    cpumask_t           cpu_eoi_map = CPU_MASK_NONE;
   3.113      unsigned int        pirq, cpu = smp_processor_id();
   3.114      shared_info_t      *s = d->shared_info;
   3.115  
   3.116 @@ -221,24 +268,27 @@ int pirq_guest_unmask(struct domain *d)
   3.117              ASSERT(action->ack_type != ACKTYPE_NONE);
   3.118              if ( --action->in_flight == 0 )
   3.119              {
   3.120 -                if ( (action->ack_type == ACKTYPE_SINGLE) ||
   3.121 -                     test_and_clear_bit(cpu, &action->cpu_ack_map) )
   3.122 +                if ( action->ack_type == ACKTYPE_UNMASK )
   3.123                      desc->handler->end(irq_to_vector(pirq));
   3.124 -                cpu_ack_map = action->cpu_ack_map;
   3.125 +                cpu_eoi_map = action->cpu_eoi_map;
   3.126              }
   3.127          }
   3.128          spin_unlock_irq(&desc->lock);
   3.129  
   3.130 -        if ( !cpus_empty(cpu_ack_map) )
   3.131 +        if ( __test_and_clear_bit(cpu, &cpu_eoi_map) )
   3.132 +            end_guest_irq(desc);
   3.133 +
   3.134 +        if ( !cpus_empty(cpu_eoi_map) )
   3.135          {
   3.136 -            on_selected_cpus(cpu_ack_map, end_guest_irq, desc, 1, 0);
   3.137 -            cpu_ack_map = CPU_MASK_NONE;
   3.138 +            on_selected_cpus(cpu_eoi_map, end_guest_irq, desc, 1, 0);
   3.139 +            cpu_eoi_map = CPU_MASK_NONE;
   3.140          }
   3.141      }
   3.142  
   3.143      return 0;
   3.144  }
   3.145  
   3.146 +extern int ioapic_ack_new;
   3.147  int pirq_acktype(int irq)
   3.148  {
   3.149      irq_desc_t  *desc;
   3.150 @@ -259,14 +309,17 @@ int pirq_acktype(int irq)
   3.151  
   3.152      /* Legacy PIC interrupts can be acknowledged from any CPU. */
   3.153      if ( !strcmp(desc->handler->typename, "XT-PIC") )
   3.154 -        return ACKTYPE_SINGLE;
   3.155 +        return ACKTYPE_UNMASK;
   3.156  
   3.157      /*
   3.158 -     * By default assume that an interrupt must be finally acknowledged on
   3.159 -     * the CPU on which it was received. This is true for level-triggered
   3.160 -     * IO-APIC interrupts, for example, where we tickle the LAPIC to EOI.
   3.161 +     * Level-triggered IO-APIC interrupts need to be acknowledged on the CPU
   3.162 +     * on which they were received. This is because we tickle the LAPIC to EOI.
   3.163       */
   3.164 -    return ACKTYPE_MULTI;
   3.165 +    if ( !strcmp(desc->handler->typename, "IO-APIC-level") )
   3.166 +        return ioapic_ack_new ? ACKTYPE_LAPIC_EOI : ACKTYPE_UNMASK;
   3.167 +
   3.168 +    BUG();
   3.169 +    return 0;
   3.170  }
   3.171  
   3.172  int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
   3.173 @@ -313,7 +366,7 @@ int pirq_guest_bind(struct vcpu *v, int 
   3.174          action->in_flight   = 0;
   3.175          action->shareable   = will_share;
   3.176          action->ack_type    = pirq_acktype(irq);
   3.177 -        action->cpu_ack_map = CPU_MASK_NONE;
   3.178 +        action->cpu_eoi_map = CPU_MASK_NONE;
   3.179  
   3.180          desc->depth = 0;
   3.181          desc->status |= IRQ_GUEST;
   3.182 @@ -352,7 +405,7 @@ int pirq_guest_unbind(struct domain *d, 
   3.183      unsigned int        vector = irq_to_vector(irq);
   3.184      irq_desc_t         *desc = &irq_desc[vector];
   3.185      irq_guest_action_t *action;
   3.186 -    cpumask_t           cpu_ack_map;
   3.187 +    cpumask_t           cpu_eoi_map;
   3.188      unsigned long       flags;
   3.189      int                 i;
   3.190  
   3.191 @@ -370,30 +423,30 @@ int pirq_guest_unbind(struct domain *d, 
   3.192  
   3.193      switch ( action->ack_type )
   3.194      {
   3.195 -    case ACKTYPE_SINGLE:
   3.196 +    case ACKTYPE_UNMASK:
   3.197          if ( test_and_clear_bit(irq, &d->pirq_mask) &&
   3.198               (--action->in_flight == 0) )
   3.199              desc->handler->end(vector);
   3.200          break;
   3.201 -    case ACKTYPE_MULTI:
   3.202 +    case ACKTYPE_LAPIC_EOI:
   3.203          if ( test_and_clear_bit(irq, &d->pirq_mask) )
   3.204              --action->in_flight;
   3.205          while ( action->in_flight == 0 )
   3.206          {
   3.207              /* We cannot release guest info until all pending ACKs are done. */
   3.208 -            cpu_ack_map = action->cpu_ack_map;
   3.209 -            if ( cpus_empty(cpu_ack_map) )
   3.210 +            cpu_eoi_map = action->cpu_eoi_map;
   3.211 +            if ( cpus_empty(cpu_eoi_map) )
   3.212                  break;
   3.213  
   3.214              /* We cannot hold the lock while interrupting other CPUs. */
   3.215              spin_unlock_irqrestore(&desc->lock, flags);    
   3.216 -            on_selected_cpus(cpu_ack_map, end_guest_irq, desc, 1, 1);
   3.217 +            on_selected_cpus(cpu_eoi_map, end_guest_irq, desc, 1, 1);
   3.218              spin_lock_irqsave(&desc->lock, flags);
   3.219  
   3.220              /* The world can change while we do not hold the lock. */
   3.221              if ( !(desc->status & IRQ_GUEST) )
   3.222                  goto out;
   3.223 -            if ( (action->ack_type != ACKTYPE_MULTI) ||
   3.224 +            if ( (action->ack_type != ACKTYPE_LAPIC_EOI) ||
   3.225                   (action->nr_guests != 0) )
   3.226                  break;
   3.227          }
   3.228 @@ -406,7 +459,7 @@ int pirq_guest_unbind(struct domain *d, 
   3.229          goto out;
   3.230  
   3.231      BUG_ON(action->in_flight != 0);
   3.232 -    BUG_ON(!cpus_empty(action->cpu_ack_map));
   3.233 +    BUG_ON(!cpus_empty(action->cpu_eoi_map));
   3.234  
   3.235      desc->action = NULL;
   3.236      xfree(action);
   3.237 @@ -487,3 +540,61 @@ static int __init setup_dump_irqs(void)
   3.238      return 0;
   3.239  }
   3.240  __initcall(setup_dump_irqs);
   3.241 +
   3.242 +static struct timer end_irq_timer[NR_CPUS];
   3.243 +
   3.244 +static void end_irq_timeout(void *unused)
   3.245 +{
   3.246 +    irq_desc_t         *desc;
   3.247 +    irq_guest_action_t *action;
   3.248 +    cpumask_t           cpu_eoi_map;
   3.249 +    unsigned int        cpu = smp_processor_id();
   3.250 +    int                 sp, vector, i;
   3.251 +
   3.252 +    local_irq_disable();
   3.253 +
   3.254 +    if ( (sp = pending_lapic_eoi_sp(cpu)) == 0 )
   3.255 +    {
   3.256 +        local_irq_enable();
   3.257 +        return;
   3.258 +    }
   3.259 +
   3.260 +    vector = pending_lapic_eoi[cpu][sp-1].vector;
   3.261 +    ASSERT(!pending_lapic_eoi[cpu][sp-1].ready_to_end);
   3.262 +
   3.263 +    desc = &irq_desc[vector];
   3.264 +    spin_lock(&desc->lock);
   3.265 +    action = (irq_guest_action_t *)desc->action;
   3.266 +    ASSERT(action->ack_type == ACKTYPE_LAPIC_EOI);
   3.267 +    ASSERT(desc->status & IRQ_GUEST);
   3.268 +    for ( i = 0; i < action->nr_guests; i++ )
   3.269 +        clear_bit(vector_to_irq(vector), &action->guest[i]->pirq_mask);
   3.270 +    action->in_flight = 0;
   3.271 +    cpu_eoi_map = action->cpu_eoi_map;
   3.272 +    spin_unlock(&desc->lock);
   3.273 +
   3.274 +    local_irq_enable();
   3.275 +
   3.276 +    if ( !cpus_empty(cpu_eoi_map) )
   3.277 +        on_selected_cpus(cpu_eoi_map, end_guest_irq, desc, 1, 0);
   3.278 +
   3.279 +    set_timer(&end_irq_timer[cpu], NOW() + MILLISECS(1000));
   3.280 +}
   3.281 +
   3.282 +static void __init __setup_irq_timeout(void *unused)
   3.283 +{
   3.284 +    int cpu = smp_processor_id();
   3.285 +    init_timer(&end_irq_timer[cpu], end_irq_timeout, NULL, cpu);
   3.286 +    set_timer(&end_irq_timer[cpu], NOW() + MILLISECS(1000));
   3.287 +}
   3.288 +
   3.289 +static int force_intack;
   3.290 +boolean_param("force_intack", force_intack);
   3.291 +
   3.292 +static int __init setup_irq_timeout(void)
   3.293 +{
   3.294 +    if ( force_intack )
   3.295 +        on_each_cpu(__setup_irq_timeout, NULL, 1, 1);
   3.296 +    return 0;
   3.297 +}
   3.298 +__initcall(setup_irq_timeout);
     4.1 --- a/xen/arch/x86/smpboot.c	Sat Apr 15 15:53:53 2006 +0100
     4.2 +++ b/xen/arch/x86/smpboot.c	Sat Apr 15 18:09:52 2006 +0100
     4.3 @@ -41,6 +41,7 @@
     4.4  #include <xen/irq.h>
     4.5  #include <xen/delay.h>
     4.6  #include <xen/softirq.h>
     4.7 +#include <xen/serial.h>
     4.8  #include <asm/current.h>
     4.9  #include <asm/mc146818rtc.h>
    4.10  #include <asm/desc.h>
    4.11 @@ -1231,12 +1232,25 @@ void __init smp_cpus_done(unsigned int m
    4.12  
    4.13  void __init smp_intr_init(void)
    4.14  {
    4.15 +	int irq, seridx;
    4.16 +
    4.17  	/*
    4.18  	 * IRQ0 must be given a fixed assignment and initialized,
    4.19  	 * because it's used before the IO-APIC is set up.
    4.20  	 */
    4.21 -	irq_vector[0] = FIRST_DEVICE_VECTOR;
    4.22 -	vector_irq[FIRST_DEVICE_VECTOR] = 0;
    4.23 +	irq_vector[0] = FIRST_HIPRIORITY_VECTOR;
    4.24 +	vector_irq[FIRST_HIPRIORITY_VECTOR] = 0;
    4.25 +
    4.26 +	/*
    4.27 +	 * Also ensure serial interrupts are high priority. We do not
    4.28 +	 * want them to be blocked by unacknowledged guest-bound interrupts.
    4.29 +	 */
    4.30 +	for (seridx = 0; seridx < 2; seridx++) {
    4.31 +		if ((irq = serial_irq(seridx)) < 0)
    4.32 +			continue;
    4.33 +		irq_vector[irq] = FIRST_HIPRIORITY_VECTOR + seridx + 1;
    4.34 +		vector_irq[FIRST_HIPRIORITY_VECTOR + seridx + 1] = irq;
    4.35 +	}
    4.36  
    4.37  	/* IPI for event checking. */
    4.38  	set_intr_gate(EVENT_CHECK_VECTOR, event_check_interrupt);
     5.1 --- a/xen/drivers/char/ns16550.c	Sat Apr 15 15:53:53 2006 +0100
     5.2 +++ b/xen/drivers/char/ns16550.c	Sat Apr 15 18:09:52 2006 +0100
     5.3 @@ -260,13 +260,20 @@ static void ns16550_endboot(struct seria
     5.4  #define ns16550_endboot NULL
     5.5  #endif
     5.6  
     5.7 +static int ns16550_irq(struct serial_port *port)
     5.8 +{
     5.9 +    struct ns16550 *uart = port->uart;
    5.10 +    return ((uart->irq > 0) ? uart->irq : -1);
    5.11 +}
    5.12 +
    5.13  static struct uart_driver ns16550_driver = {
    5.14      .init_preirq  = ns16550_init_preirq,
    5.15      .init_postirq = ns16550_init_postirq,
    5.16      .endboot      = ns16550_endboot,
    5.17      .tx_empty     = ns16550_tx_empty,
    5.18      .putc         = ns16550_putc,
    5.19 -    .getc         = ns16550_getc
    5.20 +    .getc         = ns16550_getc,
    5.21 +    .irq          = ns16550_irq
    5.22  };
    5.23  
    5.24  static int parse_parity_char(int c)
     6.1 --- a/xen/drivers/char/serial.c	Sat Apr 15 15:53:53 2006 +0100
     6.2 +++ b/xen/drivers/char/serial.c	Sat Apr 15 18:09:52 2006 +0100
     6.3 @@ -372,6 +372,15 @@ void serial_endboot(void)
     6.4              com[i].driver->endboot(&com[i]);
     6.5  }
     6.6  
     6.7 +int serial_irq(int idx)
     6.8 +{
     6.9 +    if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
    6.10 +         com[idx].driver && com[idx].driver->irq )
    6.11 +        return com[idx].driver->irq(&com[idx]);
    6.12 +
    6.13 +    return -1;
    6.14 +}
    6.15 +
    6.16  void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
    6.17  {
    6.18      /* Store UART-specific info. */
     7.1 --- a/xen/include/asm-x86/irq.h	Sat Apr 15 15:53:53 2006 +0100
     7.2 +++ b/xen/include/asm-x86/irq.h	Sat Apr 15 18:09:52 2006 +0100
     7.3 @@ -11,8 +11,8 @@
     7.4  #define IO_APIC_IRQ(irq)    (((irq) >= 16) || ((1<<(irq)) & io_apic_irqs))
     7.5  #define IO_APIC_VECTOR(irq) (irq_vector[irq])
     7.6  
     7.7 -#define LEGACY_VECTOR(irq)          ((irq) + FIRST_EXTERNAL_VECTOR)
     7.8 -#define LEGACY_IRQ_FROM_VECTOR(vec) ((vec) - FIRST_EXTERNAL_VECTOR)
     7.9 +#define LEGACY_VECTOR(irq)          ((irq) + FIRST_LEGACY_VECTOR)
    7.10 +#define LEGACY_IRQ_FROM_VECTOR(vec) ((vec) - FIRST_LEGACY_VECTOR)
    7.11  
    7.12  #define irq_to_vector(irq)  \
    7.13      (IO_APIC_IRQ(irq) ? IO_APIC_VECTOR(irq) : LEGACY_VECTOR(irq))
     8.1 --- a/xen/include/asm-x86/mach-default/irq_vectors.h	Sat Apr 15 15:53:53 2006 +0100
     8.2 +++ b/xen/include/asm-x86/mach-default/irq_vectors.h	Sat Apr 15 18:09:52 2006 +0100
     8.3 @@ -1,96 +1,36 @@
     8.4 -/*
     8.5 - * This file should contain #defines for all of the interrupt vector
     8.6 - * numbers used by this architecture.
     8.7 - *
     8.8 - * In addition, there are some standard defines:
     8.9 - *
    8.10 - *	FIRST_EXTERNAL_VECTOR:
    8.11 - *		The first free place for external interrupts
    8.12 - *
    8.13 - *	SYSCALL_VECTOR:
    8.14 - *		The IRQ vector a syscall makes the user to kernel transition
    8.15 - *		under.
    8.16 - *
    8.17 - *	TIMER_IRQ:
    8.18 - *		The IRQ number the timer interrupt comes in at.
    8.19 - *
    8.20 - *	NR_IRQS:
    8.21 - *		The total number of interrupt vectors (including all the
    8.22 - *		architecture specific interrupts) needed.
    8.23 - *
    8.24 - */			
    8.25  #ifndef _ASM_IRQ_VECTORS_H
    8.26  #define _ASM_IRQ_VECTORS_H
    8.27  
    8.28 -/*
    8.29 - * IDT vectors usable for external interrupt sources start
    8.30 - * at 0x20:
    8.31 - */
    8.32 -#define FIRST_EXTERNAL_VECTOR	0x20
    8.33 -
    8.34 -#define HYPERCALL_VECTOR	0x82
    8.35 -
    8.36 -/*
    8.37 - * Vectors 0x20-0x2f are used for ISA interrupts.
    8.38 - */
    8.39 -
    8.40 -/*
    8.41 - * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
    8.42 - *
    8.43 - *  some of the following vectors are 'rare', they are merged
    8.44 - *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
    8.45 - *  TLB, reschedule and local APIC vectors are performance-critical.
    8.46 - *
    8.47 - *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
    8.48 - */
    8.49 +/* Processor-initiated interrupts are all high priority. */
    8.50  #define SPURIOUS_APIC_VECTOR	0xff
    8.51  #define ERROR_APIC_VECTOR	0xfe
    8.52  #define INVALIDATE_TLB_VECTOR	0xfd
    8.53  #define EVENT_CHECK_VECTOR	0xfc
    8.54  #define CALL_FUNCTION_VECTOR	0xfb
    8.55 -
    8.56 -#define THERMAL_APIC_VECTOR	0xf0
    8.57 -/*
    8.58 - * Local APIC timer IRQ vector is on a different priority level,
    8.59 - * to work around the 'lost local interrupt if more than 2 IRQ
    8.60 - * sources per level' errata.
    8.61 - */
    8.62 -#define LOCAL_TIMER_VECTOR	0xef
    8.63 -
    8.64 -/*
    8.65 - * First APIC vector available to drivers: (vectors 0x30-0xee)
    8.66 - * we start at 0x31 to spread out vectors evenly between priority
    8.67 - * levels. (0x80 is the syscall vector)
    8.68 - */
    8.69 -#define FIRST_DEVICE_VECTOR	0x31
    8.70 -#define FIRST_SYSTEM_VECTOR	0xef
    8.71 -
    8.72 -#define TIMER_IRQ 0
    8.73 +#define THERMAL_APIC_VECTOR	0xfa
    8.74 +#define LOCAL_TIMER_VECTOR	0xf9
    8.75  
    8.76  /*
    8.77 - * 16 8259A IRQ's, 208 potential APIC interrupt sources.
    8.78 - * Right now the APIC is mostly only used for SMP.
    8.79 - * 256 vectors is an architectural limit. (we can have
    8.80 - * more than 256 devices theoretically, but they will
    8.81 - * have to use shared interrupts)
    8.82 - * Since vectors 0x00-0x1f are used/reserved for the CPU,
    8.83 - * the usable vector space is 0x20-0xff (224 vectors)
    8.84 + * High-priority dynamically-allocated vectors. For interrupts that
    8.85 + * must be higher priority than any guest-bound interrupt.
    8.86   */
    8.87 +#define FIRST_HIPRIORITY_VECTOR	0xf0
    8.88 +#define LAST_HIPRIORITY_VECTOR  0xf8
    8.89  
    8.90 -/*
    8.91 - * The maximum number of vectors supported by i386 processors
    8.92 - * is limited to 256. For processors other than i386, NR_VECTORS
    8.93 - * should be changed accordingly.
    8.94 - */
    8.95 +/* Legacy PIC uses vectors 0xe0-0xef. */
    8.96 +#define FIRST_LEGACY_VECTOR	0xe0
    8.97 +#define LAST_LEGACY_VECTOR      0xef
    8.98 +
    8.99 +#define HYPERCALL_VECTOR	0x82
   8.100 +
   8.101 +/* Dynamically-allocated vectors available to any driver. */
   8.102 +#define FIRST_DYNAMIC_VECTOR	0x20
   8.103 +#define LAST_DYNAMIC_VECTOR	0xdf
   8.104 +
   8.105  #define NR_VECTORS 256
   8.106  
   8.107 -#include "irq_vectors_limits.h"
   8.108 -
   8.109 -#define FPU_IRQ			13
   8.110 -
   8.111 -#define	FIRST_VM86_IRQ		3
   8.112 -#define LAST_VM86_IRQ		15
   8.113 -#define invalid_vm86_irq(irq)	((irq) < 3 || (irq) > 15)
   8.114 -
   8.115 +/* Limited by number of trap vectors. */
   8.116 +#define NR_IRQS        NR_VECTORS
   8.117 +#define NR_IRQ_VECTORS NR_IRQS
   8.118  
   8.119  #endif /* _ASM_IRQ_VECTORS_H */
     9.1 --- a/xen/include/asm-x86/mach-default/irq_vectors_limits.h	Sat Apr 15 15:53:53 2006 +0100
     9.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.3 @@ -1,8 +0,0 @@
     9.4 -#ifndef _ASM_IRQ_VECTORS_LIMITS_H
     9.5 -#define _ASM_IRQ_VECTORS_LIMITS_H
     9.6 -
     9.7 -/* Limited by number of trap vectors. */
     9.8 -#define NR_IRQS        FIRST_SYSTEM_VECTOR
     9.9 -#define NR_IRQ_VECTORS NR_IRQS
    9.10 -
    9.11 -#endif /* _ASM_IRQ_VECTORS_LIMITS_H */
    10.1 --- a/xen/include/xen/serial.h	Sat Apr 15 15:53:53 2006 +0100
    10.2 +++ b/xen/include/xen/serial.h	Sat Apr 15 18:09:52 2006 +0100
    10.3 @@ -57,6 +57,8 @@ struct uart_driver {
    10.4      void (*putc)(struct serial_port *, char);
    10.5      /* Get a character from the serial line: returns 0 if none available. */
    10.6      int  (*getc)(struct serial_port *, char *);
    10.7 +    /* Get IRQ number for this port's serial line: returns -1 if none. */
    10.8 +    int  (*irq)(struct serial_port *);
    10.9  };
   10.10  
   10.11  /* 'Serial handles' are composed from the following fields. */
   10.12 @@ -99,6 +101,9 @@ void serial_end_sync(int handle);
   10.13  /* Return number of bytes headroom in transmit buffer. */
   10.14  int serial_tx_space(int handle);
   10.15  
   10.16 +/* Return irq number for specified serial port (identified by index). */
   10.17 +int serial_irq(int idx);
   10.18 +
   10.19  /*
   10.20   * Initialisation and helper functions for uart drivers.
   10.21   */