diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-06-30 00:21:34 +0000 |
commit | 3917ac5846dd0f9ad1238166f90caab9912052e6 (patch) | |
tree | 1c298935def4f29edb39192365a65d73de999155 /arch/i386 | |
parent | af2f803c8b2d469fe38e4a7ce952658dfcb6681a (diff) |
o Merge with Linux 2.1.100.
o Cleanup the machine dependencies of floppy and rtc. The driver for
the Dallas thingy in the Indy is still missing.
o Handle allocation of zero'd pages correct for R4000SC / R4400SC.
o Page colouring shit to match the virtual and physical colour of all
mapped pages. This tends to produce extreme fragmentation problems,
so it's deactivated for now. Users of R4000SC / R4400SC may re-enable
the code in arch/mips/mm/init.c by removing the definition of
CONF_GIVE_A_SHIT_ABOUT_COLOURS. Should get them somewhat further -
but don't shake to hard ...
o Fixed ptrace(2)-ing of syscalls, strace is now working again.
o Fix the interrupt forwarding from the keyboard driver to the psaux
driver, PS/2 mice are now working on the Indy. The fix is somewhat
broken as it prevents generic kernels for Indy and machines which handle
things different.
o Things I can't remember.
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/bios32.c | 56 | ||||
-rw-r--r-- | arch/i386/kernel/entry.S | 4 | ||||
-rw-r--r-- | arch/i386/kernel/io_apic.c | 609 | ||||
-rw-r--r-- | arch/i386/kernel/ioport.c | 4 | ||||
-rw-r--r-- | arch/i386/kernel/irq.c | 204 | ||||
-rw-r--r-- | arch/i386/kernel/irq.h | 1 | ||||
-rw-r--r-- | arch/i386/kernel/mtrr.c | 12 | ||||
-rw-r--r-- | arch/i386/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/i386/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/i386/kernel/smp.c | 33 | ||||
-rw-r--r-- | arch/i386/kernel/trampoline.S | 2 | ||||
-rw-r--r-- | arch/i386/kernel/vm86.c | 2 |
12 files changed, 642 insertions, 291 deletions
diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index f2955918a..d778841e3 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -1,7 +1,7 @@ /* * bios32.c - Low-Level PCI Access * - * $Id: bios32.c,v 1.29 1998/04/17 16:31:15 mj Exp $ + * $Id: bios32.c,v 1.32 1998/05/02 12:03:05 davem Exp $ * * Sponsored by * iX Multiuser Multitasking Magazine @@ -66,6 +66,8 @@ * and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz> * * Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj] + * + * May 1, 1998 : Support for peer host bridges. [mj] */ #include <linux/config.h> @@ -74,6 +76,7 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/ioport.h> +#include <linux/malloc.h> #include <asm/page.h> #include <asm/segment.h> @@ -832,7 +835,10 @@ __initfunc(static struct pci_access *pci_find_bios(void)) } /* - * Sort the device list according to PCI BIOS. + * Sort the device list according to PCI BIOS. Nasty hack, but since some + * fool forgot to define the `correct' device order in the PCI BIOS specs + * and we want to be (possibly bug-to-bug ;-]) compatible with older kernels + * which used BIOS ordering, we are bound to do this... */ __initfunc(void pcibios_sort(void)) @@ -924,11 +930,41 @@ __initfunc(void pcibios_fixup_io_addr(struct pci_dev *dev, int idx)) } /* - * Arch-dependent fixups. We need to fix here base addresses, I/O - * and memory enables and IRQ's as the PCI BIOS'es are buggy as hell. + * In case there are peer host bridges, scan bus behind each of them. + * Although several sources claim that the host bridges should have + * header type 1 and be assigned a bus number as for PCI2PCI bridges, + * the reality doesn't pass this test and the bus number is usually + * hard-wired to 1. */ +__initfunc(void pcibios_fixup_peer_bridges(void)) +{ + struct pci_dev *dev; + int cnt = 0; + + for(dev=pci_root.devices; dev; dev=dev->sibling) + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) { + DBG("PCI: Host bridge at %02x\n", dev->devfn); + if (cnt) { + struct pci_bus *b = kmalloc(sizeof(struct pci_bus), GFP_KERNEL); + memset(b, 0, sizeof(*b)); + b->parent = &pci_root; + b->next = pci_root.next; + pci_root.next = b; + b->self = dev; + b->number = b->secondary = cnt; + b->subordinate = 0xff; + b->subordinate = pci_scan_bus(b); + } + cnt++; + } +} -__initfunc(void pcibios_fixup(void)) +/* + * Fix base addresses, I/O and memory enables and IRQ's (mostly work-arounds + * for buggy PCI BIOS'es :-[). + */ + +__initfunc(void pcibios_fixup_devices(void)) { struct pci_dev *dev; int i, has_io, has_mem; @@ -991,6 +1027,16 @@ __initfunc(void pcibios_fixup(void)) if (dev->irq >= NR_IRQS) dev->irq = 0; } +} + +/* + * Arch-dependent fixups. + */ + +__initfunc(void pcibios_fixup(void)) +{ + pcibios_fixup_peer_bridges(); + pcibios_fixup_devices(); #ifdef CONFIG_PCI_BIOS if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT)) diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index b6541005f..b3848c945 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -544,7 +544,9 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_pwrite) .long SYMBOL_NAME(sys_chown) .long SYMBOL_NAME(sys_getcwd) + .long SYMBOL_NAME(sys_capget) + .long SYMBOL_NAME(sys_capset) /* 185 */ - .rept NR_syscalls-182 + .rept NR_syscalls-184 .long SYMBOL_NAME(sys_ni_syscall) .endr diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 6e422614e..13ca35d2d 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1,7 +1,7 @@ /* * Intel IO-APIC support for multi-pentium hosts. * - * (c) 1997 Ingo Molnar, Hajnalka Szabo + * Copyright (C) 1997, 1998 Ingo Molnar, Hajnalka Szabo * * Many thanks to Stig Venaas for trying out countless experimental * patches and reporting/debugging problems patiently! @@ -34,6 +34,19 @@ */ #define IO_APIC_BASE ((volatile int *)0xfec00000) +enum mp_irq_source_types { + mp_INT = 0, + mp_NMI = 1, + mp_SMI = 2, + mp_ExtINT = 3 +}; + +enum ioapic_irq_destination_types { + dest_Fixed = 0, + dest_LowestPrio = 1, + dest_ExtINT = 7 +}; + /* * The structure of the IO-APIC: */ @@ -60,7 +73,7 @@ struct IO_APIC_route_entry { __u32 vector : 8, delivery_mode : 3, /* 000: FIXED * 001: lowest prio - * 111: ExtInt + * 111: ExtINT */ dest_mode : 1, /* 0: physical, 1: logical */ delivery_status : 1, @@ -137,7 +150,7 @@ void disable_IO_APIC_irq (unsigned int irq) io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); } -void clear_IO_APIC_irq (unsigned int irq) +void clear_IO_APIC_pin (unsigned int pin) { struct IO_APIC_route_entry entry; @@ -146,12 +159,12 @@ void clear_IO_APIC_irq (unsigned int irq) */ memset(&entry, 0, sizeof(entry)); entry.mask = 1; - io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); - io_apic_write(0x11+2*irq, *(((int *)&entry)+1)); + io_apic_write(0x10+2*pin, *(((int *)&entry)+0)); + io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); } /* - * support for broken MP BIOSes, enables hand-redirection of PIRQ0-3 to + * support for broken MP BIOSes, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. */ @@ -159,7 +172,7 @@ void clear_IO_APIC_irq (unsigned int irq) int pirq_entries [MAX_PIRQS]; int pirqs_enabled; -void ioapic_pirq_setup(char *str, int *ints) +__initfunc(void ioapic_pirq_setup(char *str, int *ints)) { int i, max; @@ -187,12 +200,15 @@ void ioapic_pirq_setup(char *str, int *ints) } } -int find_irq_entry(int pin) +/* + * Find the irq entry nr of a certain pin. + */ +__initfunc(static int find_irq_entry(int pin, int type)) { int i; for (i=0; i<mp_irq_entries; i++) - if ( (mp_irqs[i].mpc_irqtype == 0x00) && + if ( (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_dstirq == pin)) return i; @@ -200,7 +216,227 @@ int find_irq_entry(int pin) return -1; } -void setup_IO_APIC_irqs (void) +/* + * Find the pin to which IRQ0 (ISA) is connected + */ +__initfunc(int find_timer_pin (int type)) +{ + int i; + + for (i=0; i<mp_irq_entries; i++) { + int lbus = mp_irqs[i].mpc_srcbus; + + if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA) && + (mp_irqs[i].mpc_irqtype == type) && + (mp_irqs[i].mpc_srcbusirq == 0x00)) + + return mp_irqs[i].mpc_dstirq; + } + return -1; +} + +/* + * Find a specific PCI IRQ entry. + * Not an initfunc, possibly needed by modules + */ +int IO_APIC_get_PCI_irq_vector (int bus, int slot, int pci_pin) +{ + int i; + + for (i=0; i<mp_irq_entries; i++) { + int lbus = mp_irqs[i].mpc_srcbus; + + if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) && + (mp_bus_id_to_type[lbus] == MP_BUS_PCI) && + !mp_irqs[i].mpc_irqtype && + (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) && + (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) && + (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))) + + return mp_irqs[i].mpc_dstirq; + } + return -1; +} + +static int irq_trigger(int idx) +{ + int bus = mp_irqs[idx].mpc_srcbus; + int trigger; + + /* + * Determine IRQ trigger mode (edge or level sensitive): + */ + switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) + { + case 0: /* conforms, ie. bus-type dependent */ + { + switch (mp_bus_id_to_type[bus]) + { + case MP_BUS_ISA: /* ISA pin, edge */ + { + trigger = 0; + break; + } + case MP_BUS_PCI: /* PCI pin, level */ + { + trigger = 1; + break; + } + default: + { + printk("broken BIOS!!\n"); + trigger = 1; + break; + } + } + break; + } + case 1: /* edge */ + { + trigger = 0; + break; + } + case 2: /* reserved */ + { + printk("broken BIOS!!\n"); + trigger = 1; + break; + } + case 3: /* level */ + { + trigger = 1; + break; + } + default: /* invalid */ + { + printk("broken BIOS!!\n"); + trigger = 0; + break; + } + } + return trigger; +} + +__initfunc(static int irq_polarity(int idx)) +{ + int bus = mp_irqs[idx].mpc_srcbus; + int polarity; + + /* + * Determine IRQ line polarity (high active or low active): + */ + switch (mp_irqs[idx].mpc_irqflag & 3) + { + case 0: /* conforms, ie. bus-type dependent polarity */ + { + switch (mp_bus_id_to_type[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + { + polarity = 0; + break; + } + case MP_BUS_PCI: /* PCI pin */ + { + polarity = 1; + break; + } + default: + { + printk("broken BIOS!!\n"); + polarity = 1; + break; + } + } + break; + } + case 1: /* high active */ + { + polarity = 0; + break; + } + case 2: /* reserved */ + { + printk("broken BIOS!!\n"); + polarity = 1; + break; + } + case 3: /* low active */ + { + polarity = 1; + break; + } + default: /* invalid */ + { + printk("broken BIOS!!\n"); + polarity = 1; + break; + } + } + return polarity; +} + +__initfunc(static int pin_2_irq (int idx, int pin)) +{ + int irq; + int bus = mp_irqs[idx].mpc_srcbus; + + switch (mp_bus_id_to_type[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + { + irq = mp_irqs[idx].mpc_srcbusirq; + break; + } + case MP_BUS_PCI: /* PCI pin */ + { + /* + * PCI IRQs are 'directly mapped' + */ + irq = pin; + break; + } + default: + { + printk("unknown bus type %d.\n",bus); + irq = 0; + break; + } + } + + /* + * PCI IRQ command line redirection. Yes, limits are hardcoded. + */ + if ((pin>=16) && (pin<=23)) { + if (pirq_entries[pin-16] != -1) { + if (!pirq_entries[pin-16]) { + printk("disabling PIRQ%d\n", pin-16); + } else { + irq = pirq_entries[pin-16]; + printk("using PIRQ%d -> IRQ %d\n", + pin-16, irq); + } + } + } + return irq; +} + +int IO_APIC_irq_trigger (int irq) +{ + int idx, i; + + for (i=0; i<nr_ioapic_registers; i++) { + idx = find_irq_entry(i,mp_INT); + if (irq == pin_2_irq(idx,i)) + return irq_trigger(idx); + } + /* + * nonexistant IRQs are edge default + */ + return 0; +} + +__initfunc(void setup_IO_APIC_irqs (void)) { struct IO_APIC_route_entry entry; int i, idx, bus, irq, first_notcon=1; @@ -214,12 +450,12 @@ void setup_IO_APIC_irqs (void) */ memset(&entry,0,sizeof(entry)); - entry.delivery_mode = 1; /* lowest prio */ + entry.delivery_mode = dest_LowestPrio; entry.dest_mode = 1; /* logical delivery */ entry.mask = 0; /* enable IRQ */ entry.dest.logical.logical_dest = 0xff; /* all CPUs */ - idx = find_irq_entry(i); + idx = find_irq_entry(i,mp_INT); if (idx == -1) { if (first_notcon) { printk(" IO-APIC pin %d", i); @@ -228,137 +464,32 @@ void setup_IO_APIC_irqs (void) printk(", %d", i); continue; } - bus = mp_irqs[idx].mpc_srcbus; - switch (mp_bus_id_to_type[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - { - irq = mp_irqs[idx].mpc_srcbusirq; - break; - } - case MP_BUS_PCI: /* PCI pin */ - { - /* - * PCI IRQs are 'directly mapped' - */ - irq = i; - break; - } - default: - { - printk("unknown bus type %d.\n",bus); - irq = 0; - break; - } - } + entry.trigger = irq_trigger(idx); + entry.polarity = irq_polarity(idx); - /* - * PCI IRQ redirection. Yes, limits are hardcoded. - */ - if ((i>=16) && (i<=23)) { - if (pirq_entries[i-16] != -1) { - if (!pirq_entries[i-16]) { - printk("disabling PIRQ%d\n", i-16); - } else { - irq = pirq_entries[i-16]; - printk("using PIRQ%d -> IRQ %d\n", - i-16, irq); - } - } - } + irq = pin_2_irq(idx,i); if (!IO_APIC_IRQ(irq)) continue; entry.vector = IO_APIC_VECTOR(irq); - /* - * Determine IRQ line polarity (high active or low active): - */ - switch (mp_irqs[idx].mpc_irqflag & 3) - { - case 0: /* conforms, ie. bus-type dependent polarity */ - { - switch (mp_bus_id_to_type[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - { - entry.polarity = 0; - break; - } - case MP_BUS_PCI: /* PCI pin */ - { - entry.polarity = 1; - break; - } - default: - { - printk("broken BIOS!!\n"); - break; - } - } - break; - } - case 1: /* high active */ - { - entry.polarity = 0; - break; - } - case 2: /* reserved */ - { - printk("broken BIOS!!\n"); - break; - } - case 3: /* low active */ - { - entry.polarity = 1; - break; - } - } + /* + * There are broken mptables which register ISA+high-active+level IRQs, + * these are illegal and are converted here to ISA+high-active+edge + * IRQ sources. Careful, ISA+low-active+level is another broken entry + * type, it represents PCI IRQs 'embedded into an ISA bus', they have + * to be accepted. Yes, ugh. + */ + bus = mp_irqs[idx].mpc_srcbus; - /* - * Determine IRQ trigger mode (edge or level sensitive): - */ - switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) + if ( (mp_bus_id_to_type[bus] == MP_BUS_ISA) && + (entry.polarity == 0) /* active-high */ && + (entry.trigger == 1) /* level */ ) { - case 0: /* conforms, ie. bus-type dependent */ - { - switch (mp_bus_id_to_type[bus]) - { - case MP_BUS_ISA: /* ISA pin, edge */ - { - entry.trigger = 0; - break; - } - case MP_BUS_PCI: /* PCI pin, level */ - { - entry.trigger = 1; - break; - } - default: - { - printk("broken BIOS!!\n"); - break; - } - } - break; - } - case 1: /* edge */ - { - entry.trigger = 0; - break; - } - case 2: /* reserved */ - { - printk("broken BIOS!!\n"); - break; - } - case 3: /* level */ - { - entry.trigger = 1; - break; - } + printk("broken BIOS, changing pin %d to edge\n", i); + entry.trigger = 0; } io_apic_write(0x10+2*i, *(((int *)&entry)+0)); @@ -369,7 +500,7 @@ void setup_IO_APIC_irqs (void) printk(" not connected.\n"); } -void setup_IO_APIC_irq_ISA_default (unsigned int irq) +__initfunc(void setup_IO_APIC_irq_ISA_default (unsigned int irq)) { struct IO_APIC_route_entry entry; @@ -378,9 +509,9 @@ void setup_IO_APIC_irq_ISA_default (unsigned int irq) */ memset(&entry,0,sizeof(entry)); - entry.delivery_mode = 1; /* lowest prio */ + entry.delivery_mode = dest_LowestPrio; /* lowest prio */ entry.dest_mode = 1; /* logical delivery */ - entry.mask = 1; /* unmask IRQ now */ + entry.mask = 0; /* unmask IRQ now */ entry.dest.logical.logical_dest = 0xff; /* all CPUs */ entry.vector = IO_APIC_VECTOR(irq); @@ -392,56 +523,42 @@ void setup_IO_APIC_irq_ISA_default (unsigned int irq) io_apic_write(0x11+2*irq, *(((int *)&entry)+1)); } -int IO_APIC_get_PCI_irq_vector (int bus, int slot, int pci_pin) -{ - int i; - - for (i=0; i<mp_irq_entries; i++) { - int lbus = mp_irqs[i].mpc_srcbus; - - if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) && - (mp_bus_id_to_type[lbus] == MP_BUS_PCI) && - !mp_irqs[i].mpc_irqtype && - (bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) && - (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) && - (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))) - - return mp_irqs[i].mpc_dstirq; - } - return -1; -} - /* - * There is a nasty bug in some older SMP boards, their mptable lies - * about the timer IRQ. We do the following to work around the situation: - * - * - timer IRQ defaults to IO-APIC IRQ - * - if this function detects that timer IRQs are defunct, then we fall - * back to ISA timer IRQs + * Set up a certain pin as ExtINT delivered interrupt */ -static int timer_irq_works (void) +__initfunc(void setup_ExtINT_pin (unsigned int pin)) { - unsigned int t1=jiffies; - unsigned long flags; + struct IO_APIC_route_entry entry; - save_flags(flags); - sti(); + /* + * add it to the IO-APIC irq-routing table: + */ + memset(&entry,0,sizeof(entry)); - udelay(100*1000); + entry.delivery_mode = dest_ExtINT; + entry.dest_mode = 1; /* logical delivery */ + entry.mask = 0; /* unmask IRQ now */ + entry.dest.logical.logical_dest = 0xff; /* all CPUs */ - if (jiffies-t1>1) - return 1; + entry.vector = IO_APIC_VECTOR(pin); /* it's ignored */ - return 0; + entry.polarity=0; + entry.trigger=0; + + io_apic_write(0x10+2*pin, *(((int *)&entry)+0)); + io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); } -void print_IO_APIC (void) +__initfunc(void print_IO_APIC (void)) { int i; struct IO_APIC_reg_00 reg_00; struct IO_APIC_reg_01 reg_01; struct IO_APIC_reg_02 reg_02; + printk("nr of MP irq sources: %d.\n", mp_irq_entries); + printk("nr of IO-APIC registers: %d.\n", nr_ioapic_registers); + *(int *)®_00 = io_apic_read(0); *(int *)®_01 = io_apic_read(1); *(int *)®_02 = io_apic_read(2); @@ -513,14 +630,41 @@ void print_IO_APIC (void) return; } -static void init_sym_mode (void) +__initfunc(static void init_sym_mode (void)) { + int i; + + if (!pirqs_enabled) + for (i=0; i<MAX_PIRQS; i++) + pirq_entries[i]=-1; + printk("enabling Symmetric IO mode ... "); - outb_p (0x70, 0x22); - outb_p (0x01, 0x23); + + outb(0x70, 0x22); + outb(0x01, 0x23); + printk("...done.\n"); + + /* + * The number of IO-APIC irq-registers (== #pins): + */ + { + struct IO_APIC_reg_01 reg_01; + + *(int *)®_01 = io_apic_read(1); + nr_ioapic_registers = reg_01.entries+1; + } + + /* + * Do not trust the IO-APIC being empty at bootup + */ + for (i=0; i<nr_ioapic_registers; i++) + clear_IO_APIC_pin (i); } +/* + * Not an initfunc, needed by the reboot code + */ void init_pic_mode (void) { printk("disabling Symmetric IO mode ... "); @@ -551,8 +695,7 @@ struct ioapic_list_entry ioapic_blacklist [] = { { 0 , 0 } }; - -static int in_ioapic_list (struct ioapic_list_entry * table) +__initfunc(static int in_ioapic_list (struct ioapic_list_entry * table)) { for (;table->oem_id; table++) if ((!strcmp(table->oem_id,ioapic_OEM_ID)) && @@ -561,7 +704,7 @@ static int in_ioapic_list (struct ioapic_list_entry * table) return 0; } -static int ioapic_whitelisted (void) +__initfunc(static int ioapic_whitelisted (void)) { /* * Right now, whitelist everything to see whether the new parsing @@ -574,12 +717,12 @@ static int ioapic_whitelisted (void) #endif } -static int ioapic_blacklisted (void) +__initfunc(static int ioapic_blacklisted (void)) { return in_ioapic_list(ioapic_blacklist); } -static void setup_ioapic_id (void) +__initfunc(static void setup_ioapic_id (void)) { struct IO_APIC_reg_00 reg_00; @@ -598,7 +741,7 @@ static void setup_ioapic_id (void) panic("APIC ID 2 already used"); /* - * set the ID + * Set the ID */ *(int *)®_00 = io_apic_read(0); printk("... changing IO-APIC physical APIC ID to 2 ...\n"); @@ -613,7 +756,7 @@ static void setup_ioapic_id (void) panic("could not set ID"); } -static void construct_default_ISA_mptable (void) +__initfunc(static void construct_default_ISA_mptable (void)) { int i, pos=0; @@ -650,31 +793,84 @@ static void construct_default_ISA_mptable (void) setup_ioapic_id(); } - -void setup_IO_APIC (void) + +/* + * There is a nasty bug in some older SMP boards, their mptable lies + * about the timer IRQ. We do the following to work around the situation: + * + * - timer IRQ defaults to IO-APIC IRQ + * - if this function detects that timer IRQs are defunct, then we fall + * back to ISA timer IRQs + */ +__initfunc(static int timer_irq_works (void)) { - int i; + unsigned int t1=jiffies; + unsigned long flags; - if (!pirqs_enabled) - for (i=0; i<MAX_PIRQS; i++) - pirq_entries[i]=-1; + save_flags(flags); + sti(); - init_sym_mode(); - { - struct IO_APIC_reg_01 reg_01; + udelay(10*10000); - *(int *)®_01 = io_apic_read(1); - nr_ioapic_registers = reg_01.entries+1; + if (jiffies-t1>1) + return 1; + + return 0; +} + +/* + * This code may look a bit paranoid, but it's supposed to cooperate with + * a wide range of boards and BIOS bugs ... fortunately only the timer IRQ + * is so screwy. Thanks to Brian Perkins for testing/hacking this beast + * fanatically on his truly bugged board. + */ +__initfunc(static void check_timer (void)) +{ + int pin1, pin2; + + pin1 = find_timer_pin (mp_INT); + pin2 = find_timer_pin (mp_ExtINT); + + if (!timer_irq_works ()) { + if (pin1 != -1) + printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); + printk("..trying to set up timer as ExtINT ... "); + + if (pin2 != -1) { + printk(".. (found pin %d) ...", pin2); + setup_ExtINT_pin (pin2); + make_8259A_irq(0); + } + + if (!timer_irq_works ()) { + printk(" failed.\n"); + printk("..trying to set up timer as BP irq ..."); + /* + * Just in case ... + */ + if (pin1 != -1) + clear_IO_APIC_pin (pin1); + if (pin2 != -1) + clear_IO_APIC_pin (pin2); + + make_8259A_irq(0); + + if (!timer_irq_works ()) { + printk(" failed.\n"); + panic("IO-APIC + timer doesnt work!"); + } + } + printk(" works.\n"); } +} - /* - * do not trust the IO-APIC being empty at bootup - */ - for (i=0; i<nr_ioapic_registers; i++) - clear_IO_APIC_irq (i); +__initfunc(void setup_IO_APIC (void)) +{ + init_sym_mode(); /* - * the following IO-APIC's can be enabled: + * Determine the range of IRQs handled by the IO-APIC. The + * following boards can be fully enabled: * * - whitelisted ones * - those which have no PCI pins connected @@ -699,7 +895,7 @@ void setup_IO_APIC (void) /* * If there are no explicit mp irq entries: it's either one of the * default configuration types or we are broken. In both cases it's - * fine to set up most of the low 16 IOAPIC pins to ISA defaults. + * fine to set up most of the low 16 IO-APIC pins to ISA defaults. */ if (!mp_irq_entries) { printk("no explicit IRQ entries, using default mptable\n"); @@ -708,18 +904,13 @@ void setup_IO_APIC (void) init_IO_APIC_traps(); + /* + * Set up the IO-APIC irq routing table by parsing the MP-BIOS + * mptable: + */ setup_IO_APIC_irqs (); - - if (!timer_irq_works ()) { - make_8259A_irq(0); - if (!timer_irq_works ()) - panic("IO-APIC + timer doesnt work!"); - printk("..MP-BIOS bug: i8254 timer not connected to IO-APIC\n"); - printk("..falling back to 8259A-based timer interrupt\n"); - } + check_timer(); - printk("nr of MP irq sources: %d.\n", mp_irq_entries); - printk("nr of IOAPIC registers: %d.\n", nr_ioapic_registers); print_IO_APIC(); } diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c index 19587312a..2e3beb11b 100644 --- a/arch/i386/kernel/ioport.c +++ b/arch/i386/kernel/ioport.c @@ -58,7 +58,7 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; /* * If it's the first ioperm() call in this thread's lifetime, set the @@ -94,7 +94,7 @@ asmlinkage int sys_iopl(unsigned long unused) if (level > 3) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); return 0; diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 2b8b86cc7..fddc57c1f 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -70,9 +70,8 @@ spinlock_t irq_controller_lock; /* * Not all IRQs can be routed through the IO-APIC, eg. on certain (older) - * boards the timer interrupt and sometimes the keyboard interrupt is - * not connected to any IO-APIC pin, it's fed to the CPU ExtInt IRQ line - * directly. + * boards the timer interrupt is not connected to any IO-APIC pin, it's + * fed to the CPU IRQ line directly. * * Any '1' bit in this mask means the IRQ is routed through the IO-APIC. * this 'mixed mode' IRQ handling costs us one more branch in do_IRQ, @@ -82,11 +81,8 @@ spinlock_t irq_controller_lock; /* * Default to all normal IRQ's _not_ using the IO APIC. * - * To get IO-APIC interrupts you should either: - * - turn some of them into IO-APIC interrupts at runtime - * with some magic system call interface. - * - explicitly use irq 16-19 depending on which PCI irq - * line your PCI controller uses. + * To get IO-APIC interrupts we turn some of them into IO-APIC + * interrupts during boot. */ unsigned int io_apic_irqs = 0; @@ -109,15 +105,34 @@ static struct hw_interrupt_type i8259A_irq_type = { #ifdef __SMP__ -static void do_ioapic_IRQ (unsigned int irq, int cpu, struct pt_regs * regs); -static void enable_ioapic_irq (unsigned int irq); -static void disable_ioapic_irq (unsigned int irq); - -static struct hw_interrupt_type ioapic_irq_type = { - do_ioapic_IRQ, - enable_ioapic_irq, - disable_ioapic_irq + +/* + * Level and edge triggered IO-APIC interrupts need different handling, + * so we use two separate irq descriptors: + */ + +static void do_edge_ioapic_IRQ (unsigned int irq, int cpu, + struct pt_regs * regs); +static void enable_edge_ioapic_irq (unsigned int irq); +static void disable_edge_ioapic_irq (unsigned int irq); + +static struct hw_interrupt_type ioapic_edge_irq_type = { + do_edge_ioapic_IRQ, + enable_edge_ioapic_irq, + disable_edge_ioapic_irq +}; + +static void do_level_ioapic_IRQ (unsigned int irq, int cpu, + struct pt_regs * regs); +static void enable_level_ioapic_irq (unsigned int irq); +static void disable_level_ioapic_irq (unsigned int irq); + +static struct hw_interrupt_type ioapic_level_irq_type = { + do_level_ioapic_IRQ, + enable_level_ioapic_irq, + disable_level_ioapic_irq }; + #endif /* @@ -147,7 +162,7 @@ typedef struct { irq_desc_t irq_desc[NR_IRQS] = { [0 ... 15] = { 0, 0, 0, &i8259A_irq_type, }, /* standard ISA IRQs */ #ifdef __SMP__ - [16 ... 23] = { 0, 0, 0, &ioapic_irq_type, }, /* 'high' PCI IRQs */ + [16 ... 23] = { 0, 0, 0, &ioapic_edge_irq_type, }, /* 'high' PCI IRQs */ #endif }; @@ -341,11 +356,16 @@ int get_irq_list(char *buf) p += sprintf(p, "%10u ", kstat.irqs[cpu_logical_map(j)][i]); #endif - - if (IO_APIC_IRQ(i)) - p += sprintf(p, " IO-APIC "); - else - p += sprintf(p, " XT-PIC "); + if (IO_APIC_IRQ(i)) { + p += sprintf(p, " IO-APIC"); +#ifdef __SMP__ + if (irq_desc[i].handler == &ioapic_level_irq_type) + p += sprintf(p, "-level "); + else + p += sprintf(p, "-edge "); +#endif + } else + p += sprintf(p, " XT-PIC "); p += sprintf(p, " %s", action->name); for (action=action->next; action; action = action->next) { @@ -732,38 +752,53 @@ static void do_8259A_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) * better to do it this way as thus we dont have to be aware of * 'pending' interrupts in the IRQ path, except at this point. */ -static void enable_ioapic_irq(unsigned int irq) +static inline void self_IPI (unsigned int irq) { irq_desc_t *desc = irq_desc + irq; + if (desc->events && !desc->ipi) { desc->ipi = 1; send_IPI(APIC_DEST_SELF, IO_APIC_VECTOR(irq)); } } -/* - * We do not actually disable IO-APIC irqs in hardware ... - */ -static void disable_ioapic_irq(unsigned int irq) +static void enable_edge_ioapic_irq(unsigned int irq) { + self_IPI(irq); } -static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) +static void disable_edge_ioapic_irq(unsigned int irq) { - irq_desc_t *desc = irq_desc + irq; +} - spin_lock(&irq_controller_lock); +/* + * if we enable this, why does it cause a hang in the BusLogic + * driver, when level triggered PCI IRQs are used? + */ +#define NOT_BROKEN 0 - /* Ack the irq inside the lock! */ - ack_APIC_irq(); - desc->ipi = 0; +static void enable_level_ioapic_irq(unsigned int irq) +{ +#if NOT_BROKEN + enable_IO_APIC_irq(irq); +#endif + self_IPI(irq); +} - /* If the irq is disabled for whatever reason, just set a flag and return */ - if (desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)) { - desc->events = 1; - spin_unlock(&irq_controller_lock); - return; - } +static void disable_level_ioapic_irq(unsigned int irq) +{ +#if NOT_BROKEN + disable_IO_APIC_irq(irq); +#endif +} + +/* + * Has to be called with the irq controller locked + */ +static void handle_ioapic_event (unsigned int irq, int cpu, + struct pt_regs * regs) +{ + irq_desc_t *desc = irq_desc + irq; desc->status = IRQ_INPROGRESS; desc->events = 0; @@ -790,6 +825,65 @@ static void do_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) spin_unlock(&irq_controller_lock); no_handler: +} + +static void do_edge_ioapic_IRQ(unsigned int irq, int cpu, struct pt_regs * regs) +{ + irq_desc_t *desc = irq_desc + irq; + + /* + * Edge triggered IRQs can be acked immediately + */ + ack_APIC_irq(); + + spin_lock(&irq_controller_lock); + desc->ipi = 0; + + /* + * If the irq is disabled for whatever reason, just + * set a flag and return + */ + if (desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)) { + desc->events = 1; + spin_unlock(&irq_controller_lock); + return; + } + + handle_ioapic_event(irq,cpu,regs); + + hardirq_exit(cpu); + release_irqlock(cpu); +} + +static void do_level_ioapic_IRQ (unsigned int irq, int cpu, + struct pt_regs * regs) +{ + irq_desc_t *desc = irq_desc + irq; + + spin_lock(&irq_controller_lock); + /* + * in the level triggered case we first disable the IRQ + * in the IO-APIC, then we 'early ACK' the IRQ, then we + * handle it and enable the IRQ when finished. + */ +#if NOT_BROKEN + disable_IO_APIC_irq(irq); +#endif + ack_APIC_irq(); + desc->ipi = 0; + + /* + * If the irq is disabled for whatever reason, just + * set a flag and return + */ + if (desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)) { + desc->events = 1; + spin_unlock(&irq_controller_lock); + return; + } + + handle_ioapic_event(irq,cpu,regs); + hardirq_exit(cpu); release_irqlock(cpu); } @@ -912,7 +1006,12 @@ int setup_x86_irq(unsigned int irq, struct irqaction * new) spin_lock(&irq_controller_lock); #ifdef __SMP__ if (IO_APIC_IRQ(irq)) { - irq_desc[irq].handler = &ioapic_irq_type; + if (IO_APIC_VECTOR(irq) > 0xfe) + /* + * break visibly for now, FIXME + */ + panic("ayiee, tell mingo"); + /* * First disable it in the 8259A: */ @@ -1066,18 +1165,21 @@ void init_IO_APIC_traps(void) * also, we've got to be careful not to trash gate * 0x80, because int 0x80 is hm, kindof importantish ;) */ - for (i = 0; i < NR_IRQS ; i++) - if (IO_APIC_VECTOR(i) <= 0xfe) /* HACK */ { - if (IO_APIC_IRQ(i)) { - irq_desc[i].handler = &ioapic_irq_type; - /* - * First disable it in the 8259A: - */ - cached_irq_mask |= 1 << i; - if (i < 16) - set_8259A_irq_mask(i); - } + for (i = 0; i < NR_IRQS ; i++) { + if ((IO_APIC_VECTOR(i) <= 0xfe) /* HACK */ && + (IO_APIC_IRQ(i))) { + if (IO_APIC_irq_trigger(i)) + irq_desc[i].handler = &ioapic_level_irq_type; + else + irq_desc[i].handler = &ioapic_edge_irq_type; + /* + * disable it in the 8259A: + */ + cached_irq_mask |= 1 << i; + if (i < 16) + set_8259A_irq_mask(i); } + } } #endif diff --git a/arch/i386/kernel/irq.h b/arch/i386/kernel/irq.h index 81795c85c..a769369c2 100644 --- a/arch/i386/kernel/irq.h +++ b/arch/i386/kernel/irq.h @@ -17,6 +17,7 @@ void ack_APIC_irq (void); void setup_IO_APIC (void); void init_IO_APIC_traps(void); int IO_APIC_get_PCI_irq_vector (int bus, int slot, int fn); +int IO_APIC_irq_trigger (int irq); void make_8259A_irq (unsigned int irq); void send_IPI (int dest, int vector); void init_pic_mode (void); diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index f2981c5cf..98364a339 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -104,6 +104,12 @@ Moved register-setting macros into this file. Moved setup code from init/main.c to i386-specific areas. v1.18 + 19980502 Richard Gooch <rgooch@atnf.csiro.au> + Moved MTRR detection outside conditionals in <mtrr_init>. + v1.19 + 19980502 Richard Gooch <rgooch@atnf.csiro.au> + Documentation improvement: mention Pentium II and AGP. + v1.20 */ #include <linux/types.h> #include <linux/errno.h> @@ -137,7 +143,7 @@ #include <asm/atomic.h> #include <linux/smp.h> -#define MTRR_VERSION "1.18 (19980429)" +#define MTRR_VERSION "1.20 (19980502)" #define TRUE 1 #define FALSE 0 @@ -801,7 +807,7 @@ int mtrr_add (unsigned long base, unsigned long size, unsigned int type, if (ltype != type) { spin_unlock (&main_lock); - printk ( "mtrr: type missmatch for %lx,%lx old: %s new: %s\n", + printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n", base, size, attrib_to_str (ltype), attrib_to_str (type) ); return -EINVAL; } @@ -1193,8 +1199,8 @@ int init_module (void) __initfunc(int mtrr_init(void)) #endif { -# if !defined(__SMP__) || defined(MODULE) if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0; +# if !defined(__SMP__) || defined(MODULE) printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); #endif diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index a06477b9d..88030a0f2 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -297,9 +297,9 @@ void machine_restart(char * __unused) int i; for (i=0; i<100; i++) { kb_wait(); - udelay(10); + udelay(50); outb(0xfe,0x64); /* pulse reset low */ - udelay(10); + udelay(50); } /* That didn't work - force a triple fault.. */ __asm__ __volatile__("lidt %0": :"m" (no_idt)); diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index d05b54b63..294043faf 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -386,7 +386,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 0793410a6..ec7ee88c4 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -439,6 +439,8 @@ __initfunc(int smp_scan_config(unsigned long base, unsigned long length)) { unsigned long cfg; + /* local APIC has default address */ + mp_lapic_addr = 0xFEE00000; /* * We need to know what the local * APIC id of the boot CPU is! @@ -627,20 +629,29 @@ __initfunc(void smp_commence(void)) smp_commenced=1; } +__initfunc(void enable_local_APIC(void)) +{ + unsigned long value; + + value = apic_read(APIC_SPIV); + value |= (1<<8); /* Enable APIC (bit==1) */ + value &= ~(1<<9); /* Enable focus processor (bit==0) */ + apic_write(APIC_SPIV,value); + + udelay(100); /* B safe */ +} + __initfunc(void smp_callin(void)) { extern void calibrate_delay(void); int cpuid=GET_APIC_ID(apic_read(APIC_ID)); - unsigned long l; /* * Activate our APIC */ SMP_PRINTK(("CALLIN %d %d\n",hard_smp_processor_id(), smp_processor_id())); - l=apic_read(APIC_SPIV); - l|=(1<<8); /* Enable */ - apic_write(APIC_SPIV,l); + enable_local_APIC(); /* * Set up our APIC timer. @@ -1004,15 +1015,7 @@ __initfunc(void smp_boot_cpus(void)) } #endif - /* - * Enable the local APIC - */ - - cfg=apic_read(APIC_SPIV); - cfg|=(1<<8); /* Enable APIC */ - apic_write(APIC_SPIV,cfg); - - udelay(10); + enable_local_APIC(); /* * Set up our local APIC timer: @@ -1561,7 +1564,7 @@ __initfunc(static unsigned int get_8254_timer_count (void)) * APIC double write bug. */ -#define APIC_DIVISOR 16 +#define APIC_DIVISOR 1 void setup_APIC_timer (unsigned int clocks) { @@ -1585,7 +1588,7 @@ void setup_APIC_timer (unsigned int clocks) */ tmp_value = apic_read(APIC_TDCR); apic_write(APIC_TDCR , (tmp_value & ~APIC_TDR_DIV_1 ) - | APIC_TDR_DIV_16); + | APIC_TDR_DIV_1); tmp_value = apic_read(APIC_TMICT); apic_write(APIC_TMICT, clocks/APIC_DIVISOR); diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S index 1f5303a9e..12c1dbe34 100644 --- a/arch/i386/kernel/trampoline.S +++ b/arch/i386/kernel/trampoline.S @@ -54,7 +54,7 @@ r_base = . lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmp $__KERNEL_CS, $0x00100000 + ljmpl $__KERNEL_CS, $0x00100000 # jump to startup_32 idt_48: diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index db7da10fc..03bab3454 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -660,7 +660,7 @@ static int do_vm86_irq_handling(int subfunction, int irqnumber) int sig = irqnumber >> 8; int irq = irqnumber & 255; handle_irq_zombies(); - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM; if ( (irq<3) || (irq>15) ) return -EPERM; if (vm86_irqs[irq].tsk) return -EPERM; |