bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Add ioapic support disabled by default


From: Samuel Thibault
Subject: Re: [PATCH] Add ioapic support disabled by default
Date: Sun, 4 Apr 2021 16:55:12 +0200
User-agent: NeoMutt/20170609 (1.8.3)

Applied, thanks!


Damien Zammit, le dim. 04 avril 2021 15:08:12 +1000, a ecrit:
> Use --enable-ncpus=x --enable-apic where x > 1 for SMP+APIC support.
> 
> Use neither for no SMP and old PIC support.
> ---
>  i386/Makefrag.am                 |  13 +-
>  i386/configfrag.ac               |   8 +
>  i386/i386/fpu.c                  |   2 +-
>  i386/i386/irq.c                  |   9 +-
>  i386/i386/irq.h                  |   6 +-
>  i386/i386/locore.S               |  15 ++
>  i386/i386/pic.h                  |   6 +-
>  i386/i386/pit.c                  |  41 +++-
>  i386/i386/pit.h                  |   4 +
>  i386/i386at/autoconf.c           |   2 +-
>  i386/i386at/idt.h                |  13 +-
>  i386/i386at/int_init.c           |  15 +-
>  i386/i386at/interrupt.S          |  27 ++-
>  i386/i386at/ioapic.c             | 400 +++++++++++++++++++++++++++++++
>  i386/i386at/kd_mouse.c           |   2 +-
>  i386/i386at/model_dep.c          |  21 +-
>  linux/dev/arch/i386/kernel/irq.c |   4 +-
>  x86_64/interrupt.S               |  24 +-
>  18 files changed, 583 insertions(+), 29 deletions(-)
>  create mode 100644 i386/i386at/ioapic.c
> 
> diff --git a/i386/Makefrag.am b/i386/Makefrag.am
> index 73df45f4..679c0a3d 100644
> --- a/i386/Makefrag.am
> +++ b/i386/Makefrag.am
> @@ -57,7 +57,6 @@ libkernel_a_SOURCES += \
>       i386/i386at/kdsoft.h \
>       i386/i386at/mem.c \
>       i386/i386at/mem.h \
> -     i386/i386at/pic_isa.c \
>       i386/i386at/rtc.c \
>       i386/i386at/rtc.h
>  endif
> @@ -163,10 +162,18 @@ libkernel_a_SOURCES += \
>       i386/i386/io_map.c \
>       i386/i386/irq.c \
>       i386/i386/irq.h \
> -     i386/i386/pic.c \
> -     i386/i386/pic.h \
>       i386/i386/pit.c \
>       i386/i386/pit.h
> +
> +if enable_apic
> +libkernel_a_SOURCES += \
> +     i386/i386at/ioapic.c
> +else
> +libkernel_a_SOURCES += \
> +     i386/i386/pic.c \
> +     i386/i386/pic.h \
> +     i386/i386at/pic_isa.c
> +endif
>  endif
>  
>  #
> diff --git a/i386/configfrag.ac b/i386/configfrag.ac
> index bf4af110..f697e277 100644
> --- a/i386/configfrag.ac
> +++ b/i386/configfrag.ac
> @@ -92,6 +92,14 @@ if [ x"$enable_lpr" = xyes ]; then]
>    AM_CONDITIONAL([enable_lpr], [false])
>  [fi]
>  
> +AC_ARG_ENABLE([apic],
> +  AS_HELP_STRING([--enable-apic], [LAPIC/IOAPIC support]))
> +[if [ x"$enable_apic" = xyes ]; then]
> +  AC_DEFINE([APIC], [1], [APIC support])
> +  AM_CONDITIONAL([enable_apic], [true])
> +[else]
> +  AM_CONDITIONAL([enable_apic], [false])
> +[fi]
>  
>  [case $host_platform:$host_cpu in
>    xen:i?86)
> diff --git a/i386/i386/fpu.c b/i386/i386/fpu.c
> index a8459d65..cdfe264b 100644
> --- a/i386/i386/fpu.c
> +++ b/i386/i386/fpu.c
> @@ -51,7 +51,7 @@
>  #include <i386/thread.h>
>  #include <i386/fpu.h>
>  #include <i386/pio.h>
> -#include <i386/pic.h>
> +#include <i386/irq.h>
>  #include <i386/locore.h>
>  #include <i386/trap.h>
>  #include "cpu_number.h"
> diff --git a/i386/i386/irq.c b/i386/i386/irq.c
> index 35681191..42921617 100644
> --- a/i386/i386/irq.c
> +++ b/i386/i386/irq.c
> @@ -29,7 +29,10 @@ extern queue_head_t main_intr_queue;
>  static void
>  irq_eoi (struct irqdev *dev, int id)
>  {
> -  /* TODO EOI(dev->irq[id]) */
> +#ifdef APIC
> +  ioapic_irq_eoi (dev->irq[id]);
> +  lapic_eoi ();
> +#endif
>  }
>  
>  static unsigned int ndisabled_irq[NINTR];
> @@ -62,6 +65,10 @@ __enable_irq (irq_t irq_nr)
>  
>  struct irqdev irqtab = {
>    "irq", irq_eoi, &main_intr_queue, 0,
> +#ifdef APIC
> +  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 
> 21, 22, 23},
> +#else
>    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
> +#endif
>  };
>  
> diff --git a/i386/i386/irq.h b/i386/i386/irq.h
> index d48a8e92..72bbe57b 100644
> --- a/i386/i386/irq.h
> +++ b/i386/i386/irq.h
> @@ -15,7 +15,11 @@
>  #ifndef _I386_IRQ_H
>  #define _I386_IRQ_H
>  
> -#include <i386/pic.h>
> +#ifdef APIC
> +# include <i386/apic.h>
> +#else
> +# include <i386/pic.h>
> +#endif
>  
>  typedef unsigned int irq_t;
>  
> diff --git a/i386/i386/locore.S b/i386/i386/locore.S
> index bee3630c..8a1054a6 100644
> --- a/i386/i386/locore.S
> +++ b/i386/i386/locore.S
> @@ -607,6 +607,7 @@ ENTRY(call_continuation)
>       jmp     *%eax                           /* goto continuation */
>  
>  
> +/* IOAPIC has 24 interrupts, put spurious in the same array */
>  
>  #define INTERRUPT(n)                         \
>       .data   2                               ;\
> @@ -621,6 +622,7 @@ ENTRY(call_continuation)
>       .data   2
>  DATA(int_entry_table)
>       .text
> +/* Legacy APIC interrupts or PIC interrupts */
>  INTERRUPT(0)
>  INTERRUPT(1)
>  INTERRUPT(2)
> @@ -637,6 +639,19 @@ INTERRUPT(12)
>  INTERRUPT(13)
>  INTERRUPT(14)
>  INTERRUPT(15)
> +#ifdef APIC
> +/* APIC PCI interrupts PIRQ A-H */
> +INTERRUPT(16)
> +INTERRUPT(17)
> +INTERRUPT(18)
> +INTERRUPT(19)
> +INTERRUPT(20)
> +INTERRUPT(21)
> +INTERRUPT(22)
> +INTERRUPT(23)
> +/* Spurious interrupt, set irq number to vect number */
> +INTERRUPT(255)
> +#endif
>  
>  /* XXX handle NMI - at least print a warning like Linux does.  */
>  
> diff --git a/i386/i386/pic.h b/i386/i386/pic.h
> index b3365ed9..3ded9aba 100644
> --- a/i386/i386/pic.h
> +++ b/i386/i386/pic.h
> @@ -52,7 +52,9 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  #ifndef      _I386_PIC_H_
>  #define      _I386_PIC_H_
>  
> +#ifndef APIC
>  #define NINTR        0x10
> +#endif
>  #define      NPICS   0x02
>  
>  /*
> @@ -176,7 +178,9 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  #define READ_IR_ONRD         0x00
>  #define READ_IS_ONRD         0x01
>  
> -#ifndef __ASSEMBLER__
> +#define PIC_MASK_ZERO                0x00
> +
> +#if !defined(__ASSEMBLER__) && !defined(APIC)
>  extern void picinit (void);
>  extern int curr_pic_mask;
>  extern void intnull(int unit);
> diff --git a/i386/i386/pit.c b/i386/i386/pit.c
> index 4e3feeec..0ead8c9b 100644
> --- a/i386/i386/pit.c
> +++ b/i386/i386/pit.c
> @@ -51,7 +51,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  
>  #include <kern/mach_clock.h>
>  #include <i386/ipl.h>
> -#include <i386/pic.h>
> +#include <machine/irq.h>
>  #include <i386/pit.h>
>  #include <i386/pio.h>
>  #include <kern/cpu_number.h>
> @@ -66,14 +66,47 @@ int pit0_mode = PIT_C0|PIT_SQUAREMODE|PIT_READMODE ;
>  unsigned int clknumb = CLKNUM;               /* interrupt interval for timer 
> 0 */
>  
>  void
> -clkstart(void)
> +pit_prepare_sleep(int hz)
>  {
> -     unsigned char   byte;
> -     unsigned long s;
> +    /* Prepare to sleep for 1/hz seconds */
> +    int val = 0;
> +    int lsb, msb;
> +
> +    val = inb(PITAUX_PORT);
> +    val &= ~PITAUX_OUT2;
> +    val |= PITAUX_GATE2;
> +    outb (PITAUX_PORT, val);
> +    outb (PITCTL_PORT, PIT_C2 | PIT_LOADMODE | PIT_RATEMODE);
> +    val = CLKNUM / hz;
> +    lsb = val & 0xff;
> +    msb = val >> 8;
> +    outb (PITCTR2_PORT, lsb);
> +    val = inb(POST_PORT); /* ~1us i/o delay */
> +    outb (PITCTR2_PORT, msb);
>  
> +    /* Start counting down */
> +    val = inb(PITAUX_PORT);
> +    val &= ~PITAUX_GATE2;
> +    outb (PITAUX_PORT, val); /* Gate low */
> +    val |= PITAUX_GATE2;
> +    outb (PITAUX_PORT, val); /* Gate high */
> +}
> +
> +void
> +pit_sleep(void)
> +{
> +    /* Wait until counter reaches zero */
> +    while ((inb(PITAUX_PORT) & PITAUX_VAL) == 0);
> +}
> +
> +void
> +clkstart(void)
> +{
>       if (cpu_number() != 0)
>               /* Only one PIT initialization is needed */
>               return;
> +     unsigned char   byte;
> +     unsigned long s;
>  
>       s = sploff();         /* disable interrupts */
>  
> diff --git a/i386/i386/pit.h b/i386/i386/pit.h
> index cf0b74cc..bac4e985 100644
> --- a/i386/i386/pit.h
> +++ b/i386/i386/pit.h
> @@ -78,6 +78,8 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  /* Used for Timer 2. */
>  #define PIT_C2               0x80            /* select counter 2 */
>  
> +#define POST_PORT    0x80            /* used for tiny i/o delay */
> +
>  /*
>   * Clock speed for the timer in hz divided by the constant HZ
>   * (defined in param.h)
> @@ -87,5 +89,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  #endif       /* AT386 */
>  
>  extern void clkstart(void);
> +extern void pit_prepare_sleep(int hz);
> +extern void pit_sleep(void);
>  
>  #endif /* _I386_PIT_H_ */
> diff --git a/i386/i386at/autoconf.c b/i386/i386at/autoconf.c
> index 151e3fd2..0b1251f5 100644
> --- a/i386/i386at/autoconf.c
> +++ b/i386/i386at/autoconf.c
> @@ -26,7 +26,7 @@
>  
>  #include <kern/printf.h>
>  #include <mach/std_types.h>
> -#include <i386/pic.h>
> +#include <i386/irq.h>
>  #include <i386/ipl.h>
>  #include <chips/busses.h>
>  
> diff --git a/i386/i386at/idt.h b/i386/i386at/idt.h
> index fd2f62d8..ac065aef 100644
> --- a/i386/i386at/idt.h
> +++ b/i386/i386at/idt.h
> @@ -24,12 +24,19 @@
>  #ifndef _I386AT_IDT_
>  #define _I386AT_IDT_
>  
> -/* On a standard PC, we only need 16 interrupt vectors,
> -   because that's all the PIC hardware supports.  */
> -#define IDTSZ (0x20+0x10)
> +/* There are 256 interrupt vectors on x86,
> + * the first 32 are taken by cpu faults */
> +#define IDTSZ (0x100)
>  
> +/* PIC sits at 0x20-0x2f */
>  #define PIC_INT_BASE 0x20
>  
> +/* IOAPIC sits at 0x30-0x47 */
> +#define IOAPIC_INT_BASE 0x30
> +
> +/* IOAPIC spurious interrupt vector set to 0xff */
> +#define IOAPIC_SPURIOUS_BASE 0xff
> +
>  #include <i386/idt-gen.h>
>  
>  #ifndef __ASSEMBLER__
> diff --git a/i386/i386at/int_init.c b/i386/i386at/int_init.c
> index 43daad8b..6da627dd 100644
> --- a/i386/i386at/int_init.c
> +++ b/i386/i386at/int_init.c
> @@ -30,10 +30,21 @@ extern vm_offset_t int_entry_table[];
>  void int_init(void)
>  {
>       int i;
> -
> -     for (i = 0; i < 16; i++)
> +#ifndef APIC
> +     for (i = 0; i < 16; i++) {
>               fill_idt_gate(PIC_INT_BASE + i,
>                             int_entry_table[i], KERNEL_CS,
>                             ACC_PL_K|ACC_INTR_GATE, 0);
> +     }
> +#else
> +     for (i = 0; i < 24; i++) {
> +             fill_idt_gate(IOAPIC_INT_BASE + i,
> +                           int_entry_table[i], KERNEL_CS,
> +                           ACC_PL_K|ACC_INTR_GATE, 0);
> +     }
> +     fill_idt_gate(IOAPIC_SPURIOUS_BASE,
> +                           int_entry_table[24], KERNEL_CS,
> +                           ACC_PL_K|ACC_INTR_GATE, 0);
> +#endif
>  }
>  
> diff --git a/i386/i386at/interrupt.S b/i386/i386at/interrupt.S
> index 23a2e582..da0eb044 100644
> --- a/i386/i386at/interrupt.S
> +++ b/i386/i386at/interrupt.S
> @@ -16,7 +16,11 @@
>  #include <mach/machine/asm.h>
>  
>  #include <i386/ipl.h>
> -#include <i386/pic.h>
> +#ifdef APIC
> +# include <i386/apic.h>
> +#else
> +# include <i386/pic.h>
> +#endif
>  #include <i386/i386asm.h>
>  
>  #define READ_ISR     (OCW_TEMPLATE|READ_NEXT_RD|READ_IS_ONRD)
> @@ -27,6 +31,10 @@
>   * On entry, %eax contains the irq number.
>   */
>  ENTRY(interrupt)
> +#ifdef APIC
> +     cmpl    $255,%eax               /* was this a spurious intr? */
> +     je      _null_eoi               /* if so, null eoi handler */
> +#endif
>       pushl   %eax                    /* save irq number */
>       movl    %eax,%ecx               /* copy irq number */
>       shll    $2,%ecx                 /* irq * 4 */
> @@ -38,10 +46,9 @@ ENTRY(interrupt)
>       addl    $4,%esp                 /* pop unit number */
>       call    splx_cli                /* restore previous ipl */
>       addl    $4,%esp                 /* pop previous ipl */
> -
>       cli                             /* XXX no more nested interrupts */
>       popl    %ecx                    /* restore irq number */
> -
> +#ifndef APIC
>       movl    $1,%eax
>       shll    %cl,%eax                /* get corresponding IRQ mask */
>       orl     EXT(curr_pic_mask),%eax /* add current mask */
> @@ -78,4 +85,18 @@ ENTRY(interrupt)
>       outb    %al,$(PIC_MASTER_OCW)   /* unmask master */
>  2:
>       ret
> +#else
> +     cmpl    $16,%ecx                /* was this a low ISA intr? */
> +     jl      _isa_eoi                /* no, must be PCI */
> +     ret                             /* NB: let irq_acknowledge handle pci 
> EOI */
> +_isa_eoi:
> +     pushl   %ecx                    /* push irq number */
> +     call    EXT(ioapic_irq_eoi)     /* ioapic irq specific EOI */
> +     addl    $4,%esp                 /* pop irq number */
> +     call    EXT(lapic_eoi)          /* lapic broadcast EOI */
> +     ret
> +_null_eoi:
> +     call    EXT(lapic_eoi)          /* lapic broadcast EOI */
> +     ret
> +#endif
>  END(interrupt)
> diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c
> new file mode 100644
> index 00000000..016bd941
> --- /dev/null
> +++ b/i386/i386at/ioapic.c
> @@ -0,0 +1,400 @@
> +/*
> + * Copyright (C) 2019 Free Software Foundation, Inc.
> + *
> + * This file is part of GNU Mach.
> + *
> + * GNU Mach is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2, or (at your option)
> + * any later version.
> + *
> + * GNU Mach is distributed in the hope that it will be useful, but
> + * WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
> + */
> +
> +#include <sys/types.h>
> +#include <i386/ipl.h>
> +#include <machine/irq.h>
> +#include <i386/fpu.h>
> +#include <i386/hardclock.h>
> +#include <i386at/kd.h>
> +#include <i386at/idt.h>
> +#include <i386/pio.h>
> +#include <i386/pit.h>
> +#include <i386/pic.h> /* only for macros */
> +#include <mach/machine.h>
> +#include <kern/printf.h>
> +
> +static int timer_gsi;
> +int timer_pin;
> +
> +uint32_t lapic_timer_val = 0;
> +uint32_t calibrated_ticks = 0;
> +
> +spl_t curr_ipl;
> +
> +int iunit[NINTR] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
> +                    16, 17, 18, 19, 20, 21, 22, 23};
> +
> +void (*ivect[NINTR])() = {
> +    /* 00 */ intnull,        /* install timer later */
> +    /* 01 */ kdintr,         /* kdintr, ... */
> +    /* 02 */ intnull,
> +    /* 03 */ intnull,        /* lnpoll, comintr, ... */
> +
> +    /* 04 */ intnull,        /* comintr, ... */
> +    /* 05 */ intnull,        /* comintr, wtintr, ... */
> +    /* 06 */ intnull,        /* fdintr, ... */
> +    /* 07 */ intnull,        /* qdintr, ... */
> +
> +    /* 08 */ intnull,
> +    /* 09 */ intnull,        /* ether */
> +    /* 10 */ intnull,
> +    /* 11 */ intnull,
> +
> +    /* 12 */ intnull,
> +    /* 13 */ fpintr,         /* always */
> +    /* 14 */ intnull,        /* hdintr, ... */
> +    /* 15 */ intnull,        /* ??? */
> +
> +    /* 16 */ intnull,        /* PIRQA */
> +    /* 17 */ intnull,        /* PIRQB */
> +    /* 18 */ intnull,        /* PIRQC */
> +    /* 19 */ intnull,        /* PIRQD */
> +    /* 20 */ intnull,        /* PIRQE */
> +    /* 21 */ intnull,        /* PIRQF */
> +    /* 22 */ intnull,        /* PIRQG */
> +    /* 23 */ intnull,        /* PIRQH */
> +};
> +
> +void
> +picdisable(void)
> +{
> +    asm("cli");
> +
> +    /*
> +    ** Disable PIC
> +    */
> +    outb ( PIC_SLAVE_OCW, PICS_MASK );
> +    outb ( PIC_MASTER_OCW, PICM_MASK );
> +
> +    /*
> +    ** Route interrupts through IOAPIC
> +    */
> +    outb ( IMCR_SELECT, MODE_IMCR );
> +    outb ( IMCR_DATA, IMCR_USE_APIC );
> +}
> +
> +void
> +intnull(int unit_dev)
> +{
> +    printf("intnull(%d)\n", unit_dev);
> +}
> +
> +static uint32_t
> +ioapic_read(uint8_t id, uint8_t reg)
> +{
> +    volatile ApicIoUnit *ioapic = apic_get_ioapic(id)->ioapic;
> +    ioapic->select.r = reg;
> +    return ioapic->window.r;
> +}
> +
> +static void
> +ioapic_write(uint8_t id, uint8_t reg, uint32_t value)
> +{
> +    volatile ApicIoUnit *ioapic = apic_get_ioapic(id)->ioapic;
> +    ioapic->select.r = reg;
> +    ioapic->window.r = value;
> +}
> +
> +static struct ioapic_route_entry
> +ioapic_read_entry(int apic, int pin)
> +{
> +    union ioapic_route_entry_union entry;
> +
> +    entry.lo = ioapic_read(apic, APIC_IO_REDIR_LOW(pin));
> +    entry.hi = ioapic_read(apic, APIC_IO_REDIR_HIGH(pin));
> +
> +    return entry.both;
> +}
> +
> +/* Write the high word first because mask bit is in low word */
> +static void
> +ioapic_write_entry(int apic, int pin, struct ioapic_route_entry e)
> +{
> +    union ioapic_route_entry_union entry = {{0, 0}};
> +
> +    entry.both = e;
> +    ioapic_write(apic, APIC_IO_REDIR_HIGH(pin), entry.hi);
> +    ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo);
> +}
> +
> +/* When toggling the interrupt via mask, write low word only */
> +static void
> +ioapic_toggle_entry(int apic, int pin, int mask)
> +{
> +    union ioapic_route_entry_union entry;
> +
> +    entry.both = ioapic_read_entry(apic, pin);
> +    entry.both.mask = mask & 0x1;
> +    ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo);
> +}
> +
> +static void
> +cpu_rdmsr(uint32_t msr, uint32_t *lo, uint32_t *hi)
> +{
> +   __asm__ __volatile__("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
> +}
> +
> +static void
> +cpu_wrmsr(uint32_t msr, uint32_t lo, uint32_t hi)
> +{
> +   __asm__ __volatile__("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
> +}
> +
> +static void
> +global_enable_apic(void)
> +{
> +    uint32_t lo = 0;
> +    uint32_t hi = 0;
> +    uint32_t msr = 0x1b;
> +
> +    cpu_rdmsr(msr, &lo, &hi);
> +
> +    if (!(lo & (1 << 11))) {
> +        lo |= (1 << 11);
> +        cpu_wrmsr(msr, lo, hi);
> +    }
> +}
> +
> +static uint32_t
> +pit_measure_apic_hz(void)
> +{
> +    uint32_t start = 0xffffffff;
> +
> +    /* Prepare accurate delay for 1/100 seconds */
> +    pit_prepare_sleep(100);
> +
> +    /* Set APIC timer */
> +    lapic->init_count.r = start;
> +
> +    /* zZz */
> +    pit_sleep();
> +
> +    /* Stop APIC timer */
> +    lapic->lvt_timer.r = LAPIC_DISABLE;
> +
> +    return start - lapic->cur_count.r;
> +}
> +
> +void lapic_update_timer(void)
> +{
> +    /* Timer decrements until zero and then calls this on every interrupt */
> +    lapic_timer_val += calibrated_ticks;
> +}
> +
> +void
> +lapic_enable_timer(void)
> +{
> +    spl_t s;
> +
> +    s = sploff();
> +    asm("cli");
> +
> +    /* Set up counter */
> +    lapic->init_count.r = calibrated_ticks;
> +    lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16;
> +
> +    /* Set the timer to interrupt periodically on remapped timer GSI */
> +    lapic->lvt_timer.r = (IOAPIC_INT_BASE + timer_gsi) | 
> LAPIC_TIMER_PERIODIC;
> +
> +    /* Some buggy hardware requires this set again */
> +    lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16;
> +
> +    /* Unmask the remapped timer pin and pin 0 always */
> +    ioapic_toggle(0, IOAPIC_MASK_ENABLED);
> +    ioapic_toggle(timer_pin, IOAPIC_MASK_ENABLED);
> +
> +    splon(s);
> +    printf("LAPIC timer configured\n");
> +}
> +
> +void
> +ioapic_toggle(int pin, int mask)
> +{
> +    int apic = 0;
> +    ioapic_toggle_entry(apic, pin, mask);
> +}
> +
> +void
> +lapic_eoi(void)
> +{
> +    lapic->eoi.r = 0;
> +}
> +
> +void
> +ioapic_irq_eoi(int pin)
> +{
> +    int apic = 0;
> +    union ioapic_route_entry_union oldentry, entry;
> +
> +    /* Workaround for old IOAPICs with no specific EOI */
> +
> +    /* Mask the pin and change to edge triggered */
> +    oldentry.both = entry.both = ioapic_read_entry(apic, pin);
> +    entry.both.mask = IOAPIC_MASK_DISABLED;
> +    entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
> +    ioapic_write_entry(apic, pin, entry.both);
> +
> +    /* Restore level entry */
> +    ioapic_write_entry(apic, pin, oldentry.both);
> +}
> +
> +void
> +unmask_irq(unsigned int irq)
> +{
> +    ioapic_toggle(irq, IOAPIC_MASK_ENABLED);
> +}
> +
> +void
> +mask_irq(unsigned int irq)
> +{
> +    ioapic_toggle(irq, IOAPIC_MASK_DISABLED);
> +}
> +
> +static unsigned int
> +override_irq(IrqOverrideData *override, union ioapic_route_entry_union 
> *entry)
> +{
> +    if (override->flags & APIC_IRQ_OVERRIDE_TRIGGER_MASK) {
> +        entry->both.trigger = (override->flags & 
> APIC_IRQ_OVERRIDE_LEVEL_TRIGGERED) ?
> +                              IOAPIC_LEVEL_TRIGGERED : IOAPIC_EDGE_TRIGGERED;
> +    } else {
> +        if (override->bus == 0) {
> +            /* ISA is edge-triggered by default */
> +            entry->both.trigger = IOAPIC_EDGE_TRIGGERED;
> +        } else {
> +            entry->both.trigger = IOAPIC_LEVEL_TRIGGERED;
> +        }
> +    }
> +
> +    if (override->flags & APIC_IRQ_OVERRIDE_POLARITY_MASK) {
> +        entry->both.polarity = (override->flags & 
> APIC_IRQ_OVERRIDE_ACTIVE_LOW) ?
> +                               IOAPIC_ACTIVE_LOW : IOAPIC_ACTIVE_HIGH;
> +    } else {
> +        if (override->bus == 0) {
> +            /* EISA is active-low for level-triggered interrupts */
> +            if (entry->both.trigger == IOAPIC_LEVEL_TRIGGERED) {
> +                entry->both.polarity = IOAPIC_ACTIVE_LOW;
> +            } else {
> +                entry->both.polarity = IOAPIC_ACTIVE_HIGH;
> +            }
> +        }
> +    }
> +    printf("IRQ override: pin=%d gsi=%d trigger=%s polarity=%s\n",
> +           override->irq, override->gsi,
> +           entry->both.trigger == IOAPIC_LEVEL_TRIGGERED ? "LEVEL" : "EDGE",
> +           entry->both.polarity == IOAPIC_ACTIVE_LOW ? "LOW" : "HIGH");
> +
> +    return override->gsi;
> +}
> +
> +void
> +ioapic_configure(void)
> +{
> +    /* Assume first IO APIC maps to GSI base 0 */
> +    int gsi, apic = 0, bsp = 0, pin;
> +    IrqOverrideData *irq_over;
> +
> +    /* Disable IOAPIC interrupts and set spurious interrupt */
> +    lapic->spurious_vector.r = IOAPIC_SPURIOUS_BASE;
> +
> +    union ioapic_route_entry_union entry = {{0, 0}};
> +    union ioapic_route_entry_union timer_entry = {{0, 0}};
> +
> +    entry.both.delvmode = IOAPIC_FIXED;
> +    entry.both.destmode = IOAPIC_PHYSICAL;
> +    entry.both.mask = IOAPIC_MASK_DISABLED;
> +    entry.both.dest = apic_get_cpu_apic_id(bsp);
> +
> +    for (pin = 0; pin < 16; pin++) {
> +        gsi = pin;
> +
> +        /* ISA legacy IRQs */
> +        entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
> +        entry.both.polarity = IOAPIC_ACTIVE_HIGH;
> +
> +        if ((irq_over = acpi_get_irq_override(pin))) {
> +            gsi = override_irq(irq_over, &entry);
> +        }
> +        entry.both.vector = IOAPIC_INT_BASE + gsi;
> +        ioapic_write_entry(apic, pin, entry.both);
> +
> +        /* Timer workaround for x86 */
> +        if (pin == 0) {
> +            /* Save timer info */
> +            timer_gsi = gsi;
> +            timer_entry = entry;
> +        } else {
> +            /* Get the actual timer pin by assuming that the pin
> +             * with duplicated gsi from pin 0 maps to the timer pin */
> +            if (gsi == timer_gsi) {
> +                timer_pin = pin;
> +                /* Remap pin 0 interrupt vector to GSI base
> +                 * so we don't duplicate vectors */
> +                timer_entry.both.vector = IOAPIC_INT_BASE;
> +                ioapic_write_entry(apic, 0, timer_entry.both);
> +            }
> +        }
> +    }
> +
> +    for (pin = 16; pin < 24; pin++) {
> +        gsi = pin;
> +
> +        /* PCI IRQs PIRQ A-H */
> +        entry.both.trigger = IOAPIC_LEVEL_TRIGGERED;
> +        entry.both.polarity = IOAPIC_ACTIVE_LOW;
> +
> +        if ((irq_over = acpi_get_irq_override(pin))) {
> +            gsi = override_irq(irq_over, &entry);
> +        }
> +        entry.both.vector = IOAPIC_INT_BASE + gsi;
> +        ioapic_write_entry(apic, pin, entry.both);
> +    }
> +
> +    /* Start the IO APIC receiving interrupts */
> +    lapic->dest_format.r = 0xffffffff;       /* flat model */
> +    lapic->logical_dest.r = 0x00000000;      /* default, but we use physical 
> */
> +    lapic->lvt_timer.r = LAPIC_DISABLE;
> +    lapic->lvt_performance_monitor.r = LAPIC_NMI;
> +    lapic->lvt_lint0.r = LAPIC_DISABLE;
> +    lapic->lvt_lint1.r = LAPIC_DISABLE;
> +    lapic->task_pri.r = 0;
> +
> +    global_enable_apic();
> +
> +    /* Enable IOAPIC interrupts */
> +    lapic->spurious_vector.r |= LAPIC_ENABLE;
> +
> +    /* Set one-shot timer */
> +    lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16;
> +    lapic->lvt_timer.r = IOAPIC_INT_BASE + timer_gsi;
> +
> +    /* Measure number of APIC timer ticks in 10ms */
> +    calibrated_ticks = pit_measure_apic_hz();
> +
> +    /* Set up counter later */
> +    lapic->lvt_timer.r = LAPIC_DISABLE;
> +
> +    /* Install clock interrupt handler on both remapped timer pin and pin 0
> +     * since nobody knows how all x86 timers are wired up */
> +    ivect[0] = hardclock;
> +    ivect[timer_pin] = hardclock;
> +
> +    printf("IOAPIC 0 configured\n");
> +}
> diff --git a/i386/i386at/kd_mouse.c b/i386/i386at/kd_mouse.c
> index 2995587c..4b883ba8 100644
> --- a/i386/i386at/kd_mouse.c
> +++ b/i386/i386at/kd_mouse.c
> @@ -72,7 +72,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>  #include <device/io_req.h>
>  #include <device/subrs.h>
>  #include <i386/ipl.h>
> -#include <i386/pic.h>
> +#include <i386/irq.h>
>  #include <i386/pio.h>
>  #include <chips/busses.h>
>  #include <i386at/com.h>
> diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
> index 34045dc5..f83d24cb 100644
> --- a/i386/i386at/model_dep.c
> +++ b/i386/i386at/model_dep.c
> @@ -59,7 +59,6 @@
>  #include <i386/ldt.h>
>  #include <i386/machspl.h>
>  #include <i386/mp_desc.h>
> -#include <i386/pic.h>
>  #include <i386/pit.h>
>  #include <i386/pmap.h>
>  #include <i386/proc_reg.h>
> @@ -75,6 +74,7 @@
>  #include <i386at/kd.h>
>  #include <i386at/rtc.h>
>  #include <i386at/model_dep.h>
> +#include <machine/irq.h>
>  
>  #ifdef       MACH_XEN
>  #include <xen/console.h>
> @@ -169,17 +169,20 @@ void machine_init(void)
>  #ifdef MACH_HYP
>       hyp_init();
>  #else        /* MACH_HYP */
> +
> +#if (NCPUS > 1) && defined(APIC)
> +     smp_init();
> +     ioapic_configure();
> +     lapic_enable_timer();
> +     unmask_irq(1);
> +#endif /* NCPUS > 1 */
> +
>  #ifdef LINUX_DEV
>       /*
>        * Initialize Linux drivers.
>        */
>       linux_init();
>  #endif
> -
> -#if NCPUS > 1
> -     smp_init();
> -#endif /* NCPUS > 1 */
> -
>       /*
>        * Find the devices
>        */
> @@ -356,7 +359,11 @@ i386at_init(void)
>        * Initialize the PIC prior to any possible call to an spl.
>        */
>  #ifndef      MACH_HYP
> +# ifdef APIC
> +     picdisable();
> +# else
>       picinit();
> +# endif
>  #else        /* MACH_HYP */
>       hyp_intrinit();
>  #endif       /* MACH_HYP */
> @@ -678,7 +685,9 @@ timemmap(dev, off, prot)
>  void
>  startrtclock(void)
>  {
> +#ifndef APIC
>       clkstart();
> +#endif
>  }
>  
>  void
> diff --git a/linux/dev/arch/i386/kernel/irq.c 
> b/linux/dev/arch/i386/kernel/irq.c
> index b6729c12..656c1470 100644
> --- a/linux/dev/arch/i386/kernel/irq.c
> +++ b/linux/dev/arch/i386/kernel/irq.c
> @@ -714,13 +714,15 @@ init_IRQ (void)
>     */
>    (void) splhigh ();
>    
> +#ifndef APIC
>    /*
>     * Program counter 0 of 8253 to interrupt hz times per second.
>     */
>    outb_p (PIT_C0 | PIT_SQUAREMODE | PIT_READMODE, PITCTL_PORT);
>    outb_p (latch & 0xff, PITCTR0_PORT);
>    outb (latch >> 8, PITCTR0_PORT);
> -  
> +#endif
> +
>    /*
>     * Install our clock interrupt handler.
>     */
> diff --git a/x86_64/interrupt.S b/x86_64/interrupt.S
> index e634e34b..779eae67 100644
> --- a/x86_64/interrupt.S
> +++ b/x86_64/interrupt.S
> @@ -16,7 +16,11 @@
>  #include <mach/machine/asm.h>
>  
>  #include <i386/ipl.h>
> -#include <i386/pic.h>
> +#ifdef APIC
> +# include <i386/apic.h>
> +#else
> +# include <i386/pic.h>
> +#endif
>  #include <i386/i386asm.h>
>  
>  #define READ_ISR     (OCW_TEMPLATE|READ_NEXT_RD|READ_IS_ONRD)
> @@ -27,6 +31,10 @@
>   * On entry, %rax contains the irq number.
>   */
>  ENTRY(interrupt)
> +#ifdef APIC
> +     cmpl    $255,%eax               /* was this a spurious intr? */
> +     je      _null_eoi               /* if so, null eoi handler */
> +#endif
>       pushq   %rax                    /* save irq number */
>       call    spl7                    /* set ipl */
>       pushq   %rax                    /* save previous ipl */
> @@ -45,6 +53,7 @@ ENTRY(interrupt)
>       cli                             /* XXX no more nested interrupts */
>       popq    %rcx                    /* restore irq number */
>  
> +#ifndef APIC
>       movl    $1,%eax
>       shll    %cl,%eax                /* get corresponding IRQ mask */
>       orl     EXT(curr_pic_mask),%eax /* add current mask */
> @@ -81,4 +90,17 @@ ENTRY(interrupt)
>       outb    %al,$(PIC_MASTER_OCW)   /* unmask master */
>  2:
>       ret
> +#else
> +     cmpl    $16,%ecx                /* was this a low ISA intr? */
> +     jl      _isa_eoi                /* no, must be PCI */
> +     ret                             /* NB: let irq_acknowledge handle pci 
> EOI */
> +_isa_eoi:
> +     movl    %ecx,%edi               /* load irq number as 1st arg */
> +     call    EXT(ioapic_irq_eoi)     /* ioapic irq specific EOI */
> +     call    EXT(lapic_eoi)          /* lapic broadcast EOI */
> +     ret
> +_null_eoi:
> +     call    EXT(lapic_eoi)          /* lapic broadcast EOI */
> +     ret
> +#endif
>  END(interrupt)
> -- 
> 2.30.1
> 
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]