summaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-06-30 00:21:34 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-06-30 00:21:34 +0000
commit3917ac5846dd0f9ad1238166f90caab9912052e6 (patch)
tree1c298935def4f29edb39192365a65d73de999155 /arch/i386
parentaf2f803c8b2d469fe38e4a7ce952658dfcb6681a (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.c56
-rw-r--r--arch/i386/kernel/entry.S4
-rw-r--r--arch/i386/kernel/io_apic.c609
-rw-r--r--arch/i386/kernel/ioport.c4
-rw-r--r--arch/i386/kernel/irq.c204
-rw-r--r--arch/i386/kernel/irq.h1
-rw-r--r--arch/i386/kernel/mtrr.c12
-rw-r--r--arch/i386/kernel/process.c4
-rw-r--r--arch/i386/kernel/ptrace.c2
-rw-r--r--arch/i386/kernel/smp.c33
-rw-r--r--arch/i386/kernel/trampoline.S2
-rw-r--r--arch/i386/kernel/vm86.c2
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 *)&reg_00 = io_apic_read(0);
*(int *)&reg_01 = io_apic_read(1);
*(int *)&reg_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 *)&reg_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 *)&reg_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 *)&reg_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;