lkml.org 
[lkml]   [2006]   [Dec]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    SubjectRe: IO-APIC + timer doesn't work
    Please check the revised patch

    YH
    [PATCH] x86_64: check_timer with io apic setup before try_apic_pin

    add io apic setup before try_apic_pin for check_timer

    also add remove_irq_to_pin call in io_apic.c

    cc: Andi Kleen <ak@suse.de>
    cc: Eric W. Biederman <ebiederm@xmission.com>
    Signed-off-by: Yinghai Lu <yinghai.lu@amd.com>

    diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
    index 017fddb..1ddfd4d 100644
    --- a/include/asm-x86_64/mpspec.h
    +++ b/include/asm-x86_64/mpspec.h
    @@ -165,6 +165,7 @@ extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
    extern unsigned int boot_cpu_physical_apicid;
    extern int smp_found_config;
    extern void find_smp_config (void);
    +extern int add_irq_entry (int type, int irqflag, int bus, int irq, int apic, int pin);
    extern void get_smp_config (void);
    extern int nr_ioapics;
    extern unsigned char apic_version [MAX_APICS];
    diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
    index 0807256..a054798 100644
    --- a/arch/x86_64/kernel/mpparse.c
    +++ b/arch/x86_64/kernel/mpparse.c
    @@ -314,6 +314,34 @@ static int __init ELCR_trigger(unsigned int irq)
    return (inb(port) >> (irq & 7)) & 1;
    }

    +int add_irq_entry(int type, int irqflag, int bus, int irq, int apic, int pin)
    +{
    + struct mpc_config_intsrc intsrc;
    + int idx;
    +
    + intsrc.mpc_type = MP_INTSRC;
    + intsrc.mpc_irqflag = irqflag; /* conforming */
    + intsrc.mpc_srcbus = bus;
    + intsrc.mpc_dstapic = (apic != -1) ? mp_ioapics[apic].mpc_apicid: MP_APIC_ALL;
    +
    + intsrc.mpc_irqtype = type;
    +
    + intsrc.mpc_srcbusirq = irq;
    + intsrc.mpc_dstirq = pin;
    +
    + mp_irqs [mp_irq_entries] = intsrc;
    + Dprintk("Int: type %d, pol %d, trig %d, bus %d,"
    + " IRQ %02x, APIC ID %x, APIC INT %02x\n",
    + intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3,
    + (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus,
    + intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
    + idx = mp_irq_entries;
    + if (++mp_irq_entries >= MAX_IRQ_SOURCES)
    + panic("Max # of irq sources exceeded!!\n");
    + return idx;
    +
    +}
    +
    static void __init construct_default_ioirq_mptable(int mpc_default_type)
    {
    struct mpc_config_intsrc intsrc;
    diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
    index 2a1dcd5..ad1a28a 100644
    --- a/arch/x86_64/kernel/io_apic.c
    +++ b/arch/x86_64/kernel/io_apic.c
    @@ -273,10 +273,17 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
    struct irq_pin_list *entry = irq_2_pin + irq;

    BUG_ON(irq >= NR_IRQS);
    - while (entry->next)
    + while (entry->next) {
    + if (entry->apic == apic && entry->pin == pin)
    + return;
    + if (entry->pin == -1)
    + break;
    entry = irq_2_pin + entry->next;
    + }

    if (entry->pin != -1) {
    + if (entry->apic == apic && entry->pin == pin)
    + return;
    entry->next = first_free_entry;
    entry = irq_2_pin + entry->next;
    if (++first_free_entry >= PIN_MAP_SIZE)
    @@ -286,6 +293,39 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
    entry->pin = pin;
    }

    +static void remove_pin_to_irq(unsigned int irq, int apic, int pin)
    +{
    + struct irq_pin_list *entry = irq_2_pin + irq;
    + struct irq_pin_list *pri;
    + struct irq_pin_list *next;
    +
    + BUG_ON(irq >= NR_IRQS);
    +
    + for (;;) {
    + if (entry->apic == apic && entry->pin == pin) {
    + if(entry->next) {
    + next = irq_2_pin + entry->next;
    + entry->apic = next->apic;
    + entry->pin = next->pin;
    + entry->next = next->next;
    + next->apic = -1;
    + next->pin = -1;
    + next->next = 0;
    + } else {
    + entry->apic = -1;
    + entry->pin = -1;
    + }
    + return;
    + }
    + pri = entry;
    + if (pri->next)
    + entry = irq_2_pin + pri->next;
    + else
    + break;
    + }
    +
    +}
    +

    #define DO_ACTION(name,R,ACTION, FINAL) \
    \
    @@ -1570,6 +1610,22 @@ static inline void unlock_ExtINT_logic(void)
    * fanatically on his truly buggy board.
    */

    +static void set_try_apic_pin(int apic, int pin, int type)
    +{
    + int idx;
    + int irq = 0;
    + int bus = 0; /* MP_ISA_BUS */
    + int irqflag = 5; /* MP_IRQ_TRIGGER_EDGE|MP_IRQ_POLARITY_HIGH */
    +
    + idx = find_irq_entry(apic,pin,type);
    +
    + if (idx == -1)
    + idx = add_irq_entry(type, irqflag, bus, irq, apic, pin);
    +
    + add_pin_to_irq(irq, apic, pin);
    + setup_IO_APIC_irq(apic, pin, idx, irq);
    +}
    +
    static int try_apic_pin(int apic, int pin, char *msg)
    {
    apic_printk(APIC_VERBOSE, KERN_INFO
    @@ -1588,7 +1644,7 @@ static int try_apic_pin(int apic, int pin, char *msg)
    }
    return 1;
    }
    - clear_IO_APIC_pin(apic, pin);
    +
    apic_printk(APIC_QUIET, KERN_ERR " .. failed\n");
    return 0;
    }
    @@ -1599,6 +1655,7 @@ static void check_timer(void)
    int apic1, pin1, apic2, pin2;
    int vector;
    cpumask_t mask;
    + int i;

    /*
    * get/set the timer IRQ vector:
    @@ -1621,33 +1678,51 @@ static void check_timer(void)
    pin2 = ioapic_i8259.pin;
    apic2 = ioapic_i8259.apic;

    - /* Do this first, otherwise we get double interrupts on ATI boards */
    - if ((pin1 != -1) && try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled"))
    - return;
    + apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
    + vector, apic1, pin1, apic2, pin2);

    - /* Now try again with IRQ0 8259A enabled.
    - Assumes timer is on IO-APIC 0 ?!? */
    - enable_8259A_irq(0);
    - unmask_IO_APIC_irq(0);
    - if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled"))
    - return;
    - disable_8259A_irq(0);
    + if (pin1 != -1) {
    + /* Do this first, otherwise we get double interrupts on ATI boards */
    + /* set_try_apic_pin will call disable_8259A_irq */
    + set_try_apic_pin(apic1, pin1, mp_INT);
    + unmask_IO_APIC_irq(0);
    + if (try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled"))
    + return;

    - /* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides
    - on Nvidia boards */
    - if (!(apic1 == 0 && pin1 == 0) &&
    - try_apic_pin(0, 0, "fallback with 8259 IRQ0 disabled"))
    - return;
    - if (!(apic1 == 0 && pin1 == 2) &&
    - try_apic_pin(0, 2, "fallback with 8259 IRQ0 disabled"))
    - return;
    + /* Now try again with IRQ0 8259A enabled.
    + Assumes timer is on IO-APIC 0 ?!? */
    + enable_8259A_irq(0);
    + if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled"))
    + return;
    + disable_8259A_irq(0);
    +
    + clear_IO_APIC_pin(apic1, pin1);
    + remove_pin_to_irq(0, apic1, pin1);
    + }

    /* Then try pure 8259A routing on the 8259 as reported by BIOS*/
    - enable_8259A_irq(0);
    if (pin2 != -1) {
    setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
    + add_pin_to_irq(0, apic2, pin2);
    + enable_8259A_irq(0);
    if (try_apic_pin(apic2,pin2,"8259A broadcast ExtINT from BIOS"))
    return;
    + clear_IO_APIC_pin(apic2, pin2);
    + remove_pin_to_irq(0, apic2, pin2);
    + }
    +
    + /* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides
    + on Nvidia boards */
    + for (i = 0; i <= 2; i += 2)
    + if (!(apic1 == 0 && pin1 == i)) {
    + /* set_try_apic_pin will call disable_8259A_irq */
    + set_try_apic_pin(0, i, mp_INT);
    + unmask_IO_APIC_irq(0);
    + if (try_apic_pin(0, i, "fallback with 8259 IRQ0 disabled"))
    + return;
    +
    + clear_IO_APIC_pin(0, i);
    + remove_pin_to_irq(0, 0, i);
    }

    /* Tried all possibilities to go through the IO-APIC. Now come the
    \
     
     \ /
      Last update: 2006-12-31 09:33    [W:0.032 / U:220.272 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site