mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
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>
This commit is contained in:
1 parent
e8b7f0719c
commit
f6b7b3d0c4
10 files changed
+224
-137
No files matched your search
@@ -318,7 +318,7 @@ void __init init_8259A(int auto_eoi)
|
||||
* outb_p - this has to work on a wide range of PC hardware.
|
||||
*/
|
||||
outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */
|
||||
outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */
|
||||
outb_p(FIRST_LEGACY_VECTOR + 0, 0x21); /* ICW2: 8259A-1 IR0-7 */
|
||||
outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */
|
||||
if (auto_eoi)
|
||||
outb_p(0x03, 0x21); /* master does Auto EOI */
|
||||
@@ -326,7 +326,7 @@ void __init init_8259A(int auto_eoi)
|
||||
outb_p(0x01, 0x21); /* master expects normal EOI */
|
||||
|
||||
outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */
|
||||
outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */
|
||||
outb_p(FIRST_LEGACY_VECTOR + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 */
|
||||
outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */
|
||||
outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode
|
||||
is to be investigated) */
|
||||
|
||||
+20
-11
@@ -669,11 +669,11 @@ static inline int IO_APIC_irq_trigger(int irq)
|
||||
}
|
||||
|
||||
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
|
||||
u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
|
||||
u8 irq_vector[NR_IRQ_VECTORS] __read_mostly;
|
||||
|
||||
int assign_irq_vector(int irq)
|
||||
{
|
||||
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
|
||||
static int current_vector = FIRST_DYNAMIC_VECTOR, offset = 0;
|
||||
|
||||
BUG_ON(irq >= NR_IRQ_VECTORS);
|
||||
if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
|
||||
@@ -689,11 +689,11 @@ next:
|
||||
if (current_vector == 0x80)
|
||||
goto next;
|
||||
|
||||
if (current_vector >= FIRST_SYSTEM_VECTOR) {
|
||||
if (current_vector > LAST_DYNAMIC_VECTOR) {
|
||||
offset++;
|
||||
if (!(offset%8))
|
||||
return -ENOSPC;
|
||||
current_vector = FIRST_DEVICE_VECTOR + offset;
|
||||
current_vector = FIRST_DYNAMIC_VECTOR + offset;
|
||||
}
|
||||
|
||||
vector_irq[current_vector] = irq;
|
||||
@@ -1333,15 +1333,24 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq)
|
||||
return 0; /* don't check for pending */
|
||||
}
|
||||
|
||||
static int new_ack;
|
||||
boolean_param("new_ack", new_ack);
|
||||
int ioapic_ack_new = 1;
|
||||
static void setup_ioapic_ack(char *s)
|
||||
{
|
||||
if ( !strcmp(s, "old") )
|
||||
ioapic_ack_new = 0;
|
||||
else if ( !strcmp(s, "new") )
|
||||
ioapic_ack_new = 1;
|
||||
else
|
||||
printk("Unknown ioapic_ack value specified: '%s'\n", s);
|
||||
}
|
||||
custom_param("ioapic_ack", setup_ioapic_ack);
|
||||
|
||||
static void mask_and_ack_level_ioapic_irq (unsigned int irq)
|
||||
{
|
||||
unsigned long v;
|
||||
int i;
|
||||
|
||||
if ( new_ack )
|
||||
if ( ioapic_ack_new )
|
||||
return;
|
||||
|
||||
mask_IO_APIC_irq(irq);
|
||||
@@ -1384,7 +1393,7 @@ static void end_level_ioapic_irq (unsigned int irq)
|
||||
unsigned long v;
|
||||
int i;
|
||||
|
||||
if ( !new_ack )
|
||||
if ( !ioapic_ack_new )
|
||||
{
|
||||
unmask_IO_APIC_irq(irq);
|
||||
return;
|
||||
@@ -1753,7 +1762,7 @@ void __init setup_IO_APIC(void)
|
||||
io_apic_irqs = ~PIC_IRQS;
|
||||
|
||||
printk("ENABLING IO-APIC IRQs\n");
|
||||
printk(" -> Using %s ACK method\n", new_ack ? "new" : "old");
|
||||
printk(" -> Using %s ACK method\n", ioapic_ack_new ? "new" : "old");
|
||||
|
||||
/*
|
||||
* Set up IO-APIC IRQ routing.
|
||||
@@ -2015,9 +2024,9 @@ int ioapic_guest_write(unsigned long physbase, unsigned int reg, u32 val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( old_rte.vector >= FIRST_DEVICE_VECTOR )
|
||||
if ( old_rte.vector >= FIRST_DYNAMIC_VECTOR )
|
||||
old_irq = vector_irq[old_rte.vector];
|
||||
if ( new_rte.vector >= FIRST_DEVICE_VECTOR )
|
||||
if ( new_rte.vector >= FIRST_DYNAMIC_VECTOR )
|
||||
new_irq = vector_irq[new_rte.vector];
|
||||
|
||||
if ( (old_irq != new_irq) && (old_irq != -1) && IO_APIC_IRQ(old_irq) )
|
||||
|
||||
+144
-33
@@ -149,31 +149,49 @@ typedef struct {
|
||||
u8 in_flight;
|
||||
u8 shareable;
|
||||
u8 ack_type;
|
||||
#define ACKTYPE_NONE 0 /* Final ACK is not required */
|
||||
#define ACKTYPE_SINGLE 1 /* Final ACK on any CPU */
|
||||
#define ACKTYPE_MULTI 2 /* Final ACK on the CPU that was interrupted */
|
||||
cpumask_t cpu_ack_map;
|
||||
#define ACKTYPE_NONE 0 /* No final acknowledgement is required */
|
||||
#define ACKTYPE_UNMASK 1 /* Unmask PIC hardware (from any CPU) */
|
||||
#define ACKTYPE_LAPIC_EOI 2 /* EOI on the CPU that was interrupted */
|
||||
cpumask_t cpu_eoi_map; /* CPUs that need to EOI this interrupt */
|
||||
struct domain *guest[IRQ_MAX_GUESTS];
|
||||
} irq_guest_action_t;
|
||||
|
||||
/*
|
||||
* Stack of interrupts awaiting EOI on each CPU. These must be popped in
|
||||
* order, as only the current highest-priority pending irq can be EOIed.
|
||||
*/
|
||||
static struct {
|
||||
u8 vector;
|
||||
u8 ready_to_end;
|
||||
} pending_lapic_eoi[NR_CPUS][NR_VECTORS] __cacheline_aligned;
|
||||
#define pending_lapic_eoi_sp(cpu) (pending_lapic_eoi[cpu][NR_VECTORS-1].vector)
|
||||
|
||||
static void __do_IRQ_guest(int vector)
|
||||
{
|
||||
unsigned int irq = vector_to_irq(vector);
|
||||
irq_desc_t *desc = &irq_desc[vector];
|
||||
irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
|
||||
struct domain *d;
|
||||
int i;
|
||||
int i, sp, cpu = smp_processor_id();
|
||||
|
||||
if ( unlikely(action->nr_guests == 0) )
|
||||
{
|
||||
/* An interrupt may slip through while freeing an ACKTYPE_MULTI irq. */
|
||||
ASSERT(action->ack_type == ACKTYPE_MULTI);
|
||||
/* An interrupt may slip through while freeing a LAPIC_EOI irq. */
|
||||
ASSERT(action->ack_type == ACKTYPE_LAPIC_EOI);
|
||||
desc->handler->end(vector);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( action->ack_type == ACKTYPE_MULTI )
|
||||
cpu_set(smp_processor_id(), action->cpu_ack_map);
|
||||
if ( action->ack_type == ACKTYPE_LAPIC_EOI )
|
||||
{
|
||||
sp = pending_lapic_eoi_sp(cpu);
|
||||
ASSERT((sp == 0) || (pending_lapic_eoi[cpu][sp-1].vector < vector));
|
||||
ASSERT(sp < (NR_VECTORS-1));
|
||||
pending_lapic_eoi[cpu][sp].vector = vector;
|
||||
pending_lapic_eoi[cpu][sp].ready_to_end = 0;
|
||||
pending_lapic_eoi_sp(cpu) = sp+1;
|
||||
cpu_set(cpu, action->cpu_eoi_map);
|
||||
}
|
||||
|
||||
for ( i = 0; i < action->nr_guests; i++ )
|
||||
{
|
||||
@@ -190,20 +208,49 @@ static void end_guest_irq(void *data)
|
||||
irq_desc_t *desc = data;
|
||||
irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
|
||||
unsigned long flags;
|
||||
int vector, sp, cpu = smp_processor_id();
|
||||
|
||||
vector = desc - irq_desc;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
|
||||
if ( (desc->status & IRQ_GUEST) &&
|
||||
(action->in_flight == 0) &&
|
||||
test_and_clear_bit(smp_processor_id(), &action->cpu_ack_map) )
|
||||
desc->handler->end(desc - irq_desc);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
test_and_clear_bit(cpu, &action->cpu_eoi_map) )
|
||||
{
|
||||
sp = pending_lapic_eoi_sp(cpu);
|
||||
do {
|
||||
ASSERT(sp > 0);
|
||||
} while ( pending_lapic_eoi[cpu][--sp].vector != vector );
|
||||
ASSERT(!pending_lapic_eoi[cpu][sp].ready_to_end);
|
||||
pending_lapic_eoi[cpu][sp].ready_to_end = 1;
|
||||
}
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
sp = pending_lapic_eoi_sp(cpu);
|
||||
if ( (sp == 0) || !pending_lapic_eoi[cpu][sp-1].ready_to_end )
|
||||
{
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
return;
|
||||
}
|
||||
if ( pending_lapic_eoi[cpu][sp-1].vector != vector )
|
||||
{
|
||||
spin_unlock(&desc->lock);
|
||||
vector = pending_lapic_eoi[cpu][sp-1].vector;
|
||||
desc = &irq_desc[vector];
|
||||
spin_lock(&desc->lock);
|
||||
}
|
||||
desc->handler->end(vector);
|
||||
pending_lapic_eoi_sp(cpu) = sp-1;
|
||||
}
|
||||
}
|
||||
|
||||
int pirq_guest_unmask(struct domain *d)
|
||||
{
|
||||
irq_desc_t *desc;
|
||||
irq_guest_action_t *action;
|
||||
cpumask_t cpu_ack_map = CPU_MASK_NONE;
|
||||
cpumask_t cpu_eoi_map = CPU_MASK_NONE;
|
||||
unsigned int pirq, cpu = smp_processor_id();
|
||||
shared_info_t *s = d->shared_info;
|
||||
|
||||
@@ -221,24 +268,27 @@ int pirq_guest_unmask(struct domain *d)
|
||||
ASSERT(action->ack_type != ACKTYPE_NONE);
|
||||
if ( --action->in_flight == 0 )
|
||||
{
|
||||
if ( (action->ack_type == ACKTYPE_SINGLE) ||
|
||||
test_and_clear_bit(cpu, &action->cpu_ack_map) )
|
||||
if ( action->ack_type == ACKTYPE_UNMASK )
|
||||
desc->handler->end(irq_to_vector(pirq));
|
||||
cpu_ack_map = action->cpu_ack_map;
|
||||
cpu_eoi_map = action->cpu_eoi_map;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&desc->lock);
|
||||
|
||||
if ( !cpus_empty(cpu_ack_map) )
|
||||
if ( __test_and_clear_bit(cpu, &cpu_eoi_map) )
|
||||
end_guest_irq(desc);
|
||||
|
||||
if ( !cpus_empty(cpu_eoi_map) )
|
||||
{
|
||||
on_selected_cpus(cpu_ack_map, end_guest_irq, desc, 1, 0);
|
||||
cpu_ack_map = CPU_MASK_NONE;
|
||||
on_selected_cpus(cpu_eoi_map, end_guest_irq, desc, 1, 0);
|
||||
cpu_eoi_map = CPU_MASK_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int ioapic_ack_new;
|
||||
int pirq_acktype(int irq)
|
||||
{
|
||||
irq_desc_t *desc;
|
||||
@@ -259,14 +309,17 @@ int pirq_acktype(int irq)
|
||||
|
||||
/* Legacy PIC interrupts can be acknowledged from any CPU. */
|
||||
if ( !strcmp(desc->handler->typename, "XT-PIC") )
|
||||
return ACKTYPE_SINGLE;
|
||||
return ACKTYPE_UNMASK;
|
||||
|
||||
/*
|
||||
* By default assume that an interrupt must be finally acknowledged on
|
||||
* the CPU on which it was received. This is true for level-triggered
|
||||
* IO-APIC interrupts, for example, where we tickle the LAPIC to EOI.
|
||||
* Level-triggered IO-APIC interrupts need to be acknowledged on the CPU
|
||||
* on which they were received. This is because we tickle the LAPIC to EOI.
|
||||
*/
|
||||
return ACKTYPE_MULTI;
|
||||
if ( !strcmp(desc->handler->typename, "IO-APIC-level") )
|
||||
return ioapic_ack_new ? ACKTYPE_LAPIC_EOI : ACKTYPE_UNMASK;
|
||||
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
|
||||
@@ -313,7 +366,7 @@ int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
|
||||
action->in_flight = 0;
|
||||
action->shareable = will_share;
|
||||
action->ack_type = pirq_acktype(irq);
|
||||
action->cpu_ack_map = CPU_MASK_NONE;
|
||||
action->cpu_eoi_map = CPU_MASK_NONE;
|
||||
|
||||
desc->depth = 0;
|
||||
desc->status |= IRQ_GUEST;
|
||||
@@ -352,7 +405,7 @@ int pirq_guest_unbind(struct domain *d, int irq)
|
||||
unsigned int vector = irq_to_vector(irq);
|
||||
irq_desc_t *desc = &irq_desc[vector];
|
||||
irq_guest_action_t *action;
|
||||
cpumask_t cpu_ack_map;
|
||||
cpumask_t cpu_eoi_map;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
@@ -370,30 +423,30 @@ int pirq_guest_unbind(struct domain *d, int irq)
|
||||
|
||||
switch ( action->ack_type )
|
||||
{
|
||||
case ACKTYPE_SINGLE:
|
||||
case ACKTYPE_UNMASK:
|
||||
if ( test_and_clear_bit(irq, &d->pirq_mask) &&
|
||||
(--action->in_flight == 0) )
|
||||
desc->handler->end(vector);
|
||||
break;
|
||||
case ACKTYPE_MULTI:
|
||||
case ACKTYPE_LAPIC_EOI:
|
||||
if ( test_and_clear_bit(irq, &d->pirq_mask) )
|
||||
--action->in_flight;
|
||||
while ( action->in_flight == 0 )
|
||||
{
|
||||
/* We cannot release guest info until all pending ACKs are done. */
|
||||
cpu_ack_map = action->cpu_ack_map;
|
||||
if ( cpus_empty(cpu_ack_map) )
|
||||
cpu_eoi_map = action->cpu_eoi_map;
|
||||
if ( cpus_empty(cpu_eoi_map) )
|
||||
break;
|
||||
|
||||
/* We cannot hold the lock while interrupting other CPUs. */
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
on_selected_cpus(cpu_ack_map, end_guest_irq, desc, 1, 1);
|
||||
on_selected_cpus(cpu_eoi_map, end_guest_irq, desc, 1, 1);
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
|
||||
/* The world can change while we do not hold the lock. */
|
||||
if ( !(desc->status & IRQ_GUEST) )
|
||||
goto out;
|
||||
if ( (action->ack_type != ACKTYPE_MULTI) ||
|
||||
if ( (action->ack_type != ACKTYPE_LAPIC_EOI) ||
|
||||
(action->nr_guests != 0) )
|
||||
break;
|
||||
}
|
||||
@@ -406,7 +459,7 @@ int pirq_guest_unbind(struct domain *d, int irq)
|
||||
goto out;
|
||||
|
||||
BUG_ON(action->in_flight != 0);
|
||||
BUG_ON(!cpus_empty(action->cpu_ack_map));
|
||||
BUG_ON(!cpus_empty(action->cpu_eoi_map));
|
||||
|
||||
desc->action = NULL;
|
||||
xfree(action);
|
||||
@@ -487,3 +540,61 @@ static int __init setup_dump_irqs(void)
|
||||
return 0;
|
||||
}
|
||||
__initcall(setup_dump_irqs);
|
||||
|
||||
static struct timer end_irq_timer[NR_CPUS];
|
||||
|
||||
static void end_irq_timeout(void *unused)
|
||||
{
|
||||
irq_desc_t *desc;
|
||||
irq_guest_action_t *action;
|
||||
cpumask_t cpu_eoi_map;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
int sp, vector, i;
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
if ( (sp = pending_lapic_eoi_sp(cpu)) == 0 )
|
||||
{
|
||||
local_irq_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
vector = pending_lapic_eoi[cpu][sp-1].vector;
|
||||
ASSERT(!pending_lapic_eoi[cpu][sp-1].ready_to_end);
|
||||
|
||||
desc = &irq_desc[vector];
|
||||
spin_lock(&desc->lock);
|
||||
action = (irq_guest_action_t *)desc->action;
|
||||
ASSERT(action->ack_type == ACKTYPE_LAPIC_EOI);
|
||||
ASSERT(desc->status & IRQ_GUEST);
|
||||
for ( i = 0; i < action->nr_guests; i++ )
|
||||
clear_bit(vector_to_irq(vector), &action->guest[i]->pirq_mask);
|
||||
action->in_flight = 0;
|
||||
cpu_eoi_map = action->cpu_eoi_map;
|
||||
spin_unlock(&desc->lock);
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
if ( !cpus_empty(cpu_eoi_map) )
|
||||
on_selected_cpus(cpu_eoi_map, end_guest_irq, desc, 1, 0);
|
||||
|
||||
set_timer(&end_irq_timer[cpu], NOW() + MILLISECS(1000));
|
||||
}
|
||||
|
||||
static void __init __setup_irq_timeout(void *unused)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
init_timer(&end_irq_timer[cpu], end_irq_timeout, NULL, cpu);
|
||||
set_timer(&end_irq_timer[cpu], NOW() + MILLISECS(1000));
|
||||
}
|
||||
|
||||
static int force_intack;
|
||||
boolean_param("force_intack", force_intack);
|
||||
|
||||
static int __init setup_irq_timeout(void)
|
||||
{
|
||||
if ( force_intack )
|
||||
on_each_cpu(__setup_irq_timeout, NULL, 1, 1);
|
||||
return 0;
|
||||
}
|
||||
__initcall(setup_irq_timeout);
|
||||
+16
-2
@@ -41,6 +41,7 @@
|
||||
#include <xen/irq.h>
|
||||
#include <xen/delay.h>
|
||||
#include <xen/softirq.h>
|
||||
#include <xen/serial.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/mc146818rtc.h>
|
||||
#include <asm/desc.h>
|
||||
@@ -1231,12 +1232,25 @@ void __init smp_cpus_done(unsigned int max_cpus)
|
||||
|
||||
void __init smp_intr_init(void)
|
||||
{
|
||||
int irq, seridx;
|
||||
|
||||
/*
|
||||
* IRQ0 must be given a fixed assignment and initialized,
|
||||
* because it's used before the IO-APIC is set up.
|
||||
*/
|
||||
irq_vector[0] = FIRST_DEVICE_VECTOR;
|
||||
vector_irq[FIRST_DEVICE_VECTOR] = 0;
|
||||
irq_vector[0] = FIRST_HIPRIORITY_VECTOR;
|
||||
vector_irq[FIRST_HIPRIORITY_VECTOR] = 0;
|
||||
|
||||
/*
|
||||
* Also ensure serial interrupts are high priority. We do not
|
||||
* want them to be blocked by unacknowledged guest-bound interrupts.
|
||||
*/
|
||||
for (seridx = 0; seridx < 2; seridx++) {
|
||||
if ((irq = serial_irq(seridx)) < 0)
|
||||
continue;
|
||||
irq_vector[irq] = FIRST_HIPRIORITY_VECTOR + seridx + 1;
|
||||
vector_irq[FIRST_HIPRIORITY_VECTOR + seridx + 1] = irq;
|
||||
}
|
||||
|
||||
/* IPI for event checking. */
|
||||
set_intr_gate(EVENT_CHECK_VECTOR, event_check_interrupt);
|
||||
|
||||
@@ -260,13 +260,20 @@ static void ns16550_endboot(struct serial_port *port)
|
||||
#define ns16550_endboot NULL
|
||||
#endif
|
||||
|
||||
static int ns16550_irq(struct serial_port *port)
|
||||
{
|
||||
struct ns16550 *uart = port->uart;
|
||||
return ((uart->irq > 0) ? uart->irq : -1);
|
||||
}
|
||||
|
||||
static struct uart_driver ns16550_driver = {
|
||||
.init_preirq = ns16550_init_preirq,
|
||||
.init_postirq = ns16550_init_postirq,
|
||||
.endboot = ns16550_endboot,
|
||||
.tx_empty = ns16550_tx_empty,
|
||||
.putc = ns16550_putc,
|
||||
.getc = ns16550_getc
|
||||
.getc = ns16550_getc,
|
||||
.irq = ns16550_irq
|
||||
};
|
||||
|
||||
static int parse_parity_char(int c)
|
||||
|
||||
@@ -372,6 +372,15 @@ void serial_endboot(void)
|
||||
com[i].driver->endboot(&com[i]);
|
||||
}
|
||||
|
||||
int serial_irq(int idx)
|
||||
{
|
||||
if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
|
||||
com[idx].driver && com[idx].driver->irq )
|
||||
return com[idx].driver->irq(&com[idx]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
|
||||
{
|
||||
/* Store UART-specific info. */
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#define IO_APIC_IRQ(irq) (((irq) >= 16) || ((1<<(irq)) & io_apic_irqs))
|
||||
#define IO_APIC_VECTOR(irq) (irq_vector[irq])
|
||||
|
||||
#define LEGACY_VECTOR(irq) ((irq) + FIRST_EXTERNAL_VECTOR)
|
||||
#define LEGACY_IRQ_FROM_VECTOR(vec) ((vec) - FIRST_EXTERNAL_VECTOR)
|
||||
#define LEGACY_VECTOR(irq) ((irq) + FIRST_LEGACY_VECTOR)
|
||||
#define LEGACY_IRQ_FROM_VECTOR(vec) ((vec) - FIRST_LEGACY_VECTOR)
|
||||
|
||||
#define irq_to_vector(irq) \
|
||||
(IO_APIC_IRQ(irq) ? IO_APIC_VECTOR(irq) : LEGACY_VECTOR(irq))
|
||||
|
||||
@@ -1,96 +1,36 @@
|
||||
/*
|
||||
* This file should contain #defines for all of the interrupt vector
|
||||
* numbers used by this architecture.
|
||||
*
|
||||
* In addition, there are some standard defines:
|
||||
*
|
||||
* FIRST_EXTERNAL_VECTOR:
|
||||
* The first free place for external interrupts
|
||||
*
|
||||
* SYSCALL_VECTOR:
|
||||
* The IRQ vector a syscall makes the user to kernel transition
|
||||
* under.
|
||||
*
|
||||
* TIMER_IRQ:
|
||||
* The IRQ number the timer interrupt comes in at.
|
||||
*
|
||||
* NR_IRQS:
|
||||
* The total number of interrupt vectors (including all the
|
||||
* architecture specific interrupts) needed.
|
||||
*
|
||||
*/
|
||||
#ifndef _ASM_IRQ_VECTORS_H
|
||||
#define _ASM_IRQ_VECTORS_H
|
||||
|
||||
/*
|
||||
* IDT vectors usable for external interrupt sources start
|
||||
* at 0x20:
|
||||
*/
|
||||
#define FIRST_EXTERNAL_VECTOR 0x20
|
||||
|
||||
#define HYPERCALL_VECTOR 0x82
|
||||
|
||||
/*
|
||||
* Vectors 0x20-0x2f are used for ISA interrupts.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Special IRQ vectors used by the SMP architecture, 0xf0-0xff
|
||||
*
|
||||
* some of the following vectors are 'rare', they are merged
|
||||
* into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
|
||||
* TLB, reschedule and local APIC vectors are performance-critical.
|
||||
*
|
||||
* Vectors 0xf0-0xfa are free (reserved for future Linux use).
|
||||
*/
|
||||
/* Processor-initiated interrupts are all high priority. */
|
||||
#define SPURIOUS_APIC_VECTOR 0xff
|
||||
#define ERROR_APIC_VECTOR 0xfe
|
||||
#define INVALIDATE_TLB_VECTOR 0xfd
|
||||
#define EVENT_CHECK_VECTOR 0xfc
|
||||
#define CALL_FUNCTION_VECTOR 0xfb
|
||||
|
||||
#define THERMAL_APIC_VECTOR 0xf0
|
||||
/*
|
||||
* Local APIC timer IRQ vector is on a different priority level,
|
||||
* to work around the 'lost local interrupt if more than 2 IRQ
|
||||
* sources per level' errata.
|
||||
*/
|
||||
#define LOCAL_TIMER_VECTOR 0xef
|
||||
#define THERMAL_APIC_VECTOR 0xfa
|
||||
#define LOCAL_TIMER_VECTOR 0xf9
|
||||
|
||||
/*
|
||||
* First APIC vector available to drivers: (vectors 0x30-0xee)
|
||||
* we start at 0x31 to spread out vectors evenly between priority
|
||||
* levels. (0x80 is the syscall vector)
|
||||
* High-priority dynamically-allocated vectors. For interrupts that
|
||||
* must be higher priority than any guest-bound interrupt.
|
||||
*/
|
||||
#define FIRST_DEVICE_VECTOR 0x31
|
||||
#define FIRST_SYSTEM_VECTOR 0xef
|
||||
#define FIRST_HIPRIORITY_VECTOR 0xf0
|
||||
#define LAST_HIPRIORITY_VECTOR 0xf8
|
||||
|
||||
#define TIMER_IRQ 0
|
||||
/* Legacy PIC uses vectors 0xe0-0xef. */
|
||||
#define FIRST_LEGACY_VECTOR 0xe0
|
||||
#define LAST_LEGACY_VECTOR 0xef
|
||||
|
||||
/*
|
||||
* 16 8259A IRQ's, 208 potential APIC interrupt sources.
|
||||
* Right now the APIC is mostly only used for SMP.
|
||||
* 256 vectors is an architectural limit. (we can have
|
||||
* more than 256 devices theoretically, but they will
|
||||
* have to use shared interrupts)
|
||||
* Since vectors 0x00-0x1f are used/reserved for the CPU,
|
||||
* the usable vector space is 0x20-0xff (224 vectors)
|
||||
*/
|
||||
#define HYPERCALL_VECTOR 0x82
|
||||
|
||||
/* Dynamically-allocated vectors available to any driver. */
|
||||
#define FIRST_DYNAMIC_VECTOR 0x20
|
||||
#define LAST_DYNAMIC_VECTOR 0xdf
|
||||
|
||||
/*
|
||||
* The maximum number of vectors supported by i386 processors
|
||||
* is limited to 256. For processors other than i386, NR_VECTORS
|
||||
* should be changed accordingly.
|
||||
*/
|
||||
#define NR_VECTORS 256
|
||||
|
||||
#include "irq_vectors_limits.h"
|
||||
|
||||
#define FPU_IRQ 13
|
||||
|
||||
#define FIRST_VM86_IRQ 3
|
||||
#define LAST_VM86_IRQ 15
|
||||
#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15)
|
||||
|
||||
/* Limited by number of trap vectors. */
|
||||
#define NR_IRQS NR_VECTORS
|
||||
#define NR_IRQ_VECTORS NR_IRQS
|
||||
|
||||
#endif /* _ASM_IRQ_VECTORS_H */
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef _ASM_IRQ_VECTORS_LIMITS_H
|
||||
#define _ASM_IRQ_VECTORS_LIMITS_H
|
||||
|
||||
/* Limited by number of trap vectors. */
|
||||
#define NR_IRQS FIRST_SYSTEM_VECTOR
|
||||
#define NR_IRQ_VECTORS NR_IRQS
|
||||
|
||||
#endif /* _ASM_IRQ_VECTORS_LIMITS_H */
|
||||
@@ -57,6 +57,8 @@ struct uart_driver {
|
||||
void (*putc)(struct serial_port *, char);
|
||||
/* Get a character from the serial line: returns 0 if none available. */
|
||||
int (*getc)(struct serial_port *, char *);
|
||||
/* Get IRQ number for this port's serial line: returns -1 if none. */
|
||||
int (*irq)(struct serial_port *);
|
||||
};
|
||||
|
||||
/* 'Serial handles' are composed from the following fields. */
|
||||
@@ -99,6 +101,9 @@ void serial_end_sync(int handle);
|
||||
/* Return number of bytes headroom in transmit buffer. */
|
||||
int serial_tx_space(int handle);
|
||||
|
||||
/* Return irq number for specified serial port (identified by index). */
|
||||
int serial_irq(int idx);
|
||||
|
||||
/*
|
||||
* Initialisation and helper functions for uart drivers.
|
||||
*/
|
||||
|
||||