summaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r--arch/i386/kernel/Makefile2
-rw-r--r--arch/i386/kernel/acpi.c25
-rw-r--r--arch/i386/kernel/i8259.c2
-rw-r--r--arch/i386/kernel/io_apic.c3
-rw-r--r--arch/i386/kernel/irq.c50
-rw-r--r--arch/i386/kernel/microcode.c97
-rw-r--r--arch/i386/kernel/pci-pc.c43
-rw-r--r--arch/i386/kernel/process.c2
-rw-r--r--arch/i386/kernel/signal.c10
-rw-r--r--arch/i386/kernel/traps.c1
10 files changed, 147 insertions, 88 deletions
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 3b7bb1258..6671bb35b 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -40,7 +40,6 @@ else
endif
endif
-ifeq ($(CONFIG_PROC_FS),y)
ifeq ($(CONFIG_MICROCODE),y)
OX_OBJS += microcode.o
else
@@ -48,7 +47,6 @@ else
MX_OBJS += microcode.o
endif
endif
-endif
ifeq ($(CONFIG_ACPI),y)
O_OBJS += acpi.o
diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
index 6228805db..b19097420 100644
--- a/arch/i386/kernel/acpi.c
+++ b/arch/i386/kernel/acpi.c
@@ -977,11 +977,9 @@ static void acpi_enter_sx(acpi_sstate_t state)
typa = ((typa << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
typb = ((typb << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK);
- if (state != ACPI_S0) {
- acpi_sleep_start = get_cmos_time();
- acpi_enter_dx(ACPI_D3);
- acpi_sleep_state = state;
- }
+ acpi_sleep_start = get_cmos_time();
+ acpi_enter_dx(ACPI_D3);
+ acpi_sleep_state = state;
// clear wake status
acpi_write_pm1_status(acpi_facp, ACPI_WAK);
@@ -996,17 +994,11 @@ static void acpi_enter_sx(acpi_sstate_t state)
outw(value | typb | ACPI_SLP_EN, acpi_facp->pm1b_cnt);
}
- if (state == ACPI_S0) {
- acpi_sleep_state = state;
- acpi_enter_dx(ACPI_D0);
- acpi_sleep_start = 0;
- }
- else if (state == ACPI_S1) {
- // wait until S1 is entered
- while (!(acpi_read_pm1_status(acpi_facp) & ACPI_WAK)) ;
- // finished sleeping, update system time
- acpi_update_clock();
- }
+ // wait until S1 is entered
+ while (!(acpi_read_pm1_status(acpi_facp) & ACPI_WAK)) ;
+ // finished sleeping, update system time
+ acpi_update_clock();
+ acpi_enter_dx(ACPI_D0);
}
}
@@ -1292,7 +1284,6 @@ static int acpi_do_sleep(ctl_table *ctl,
{
#ifdef CONFIG_ACPI_S1_SLEEP
acpi_enter_sx(ACPI_S1);
- acpi_enter_sx(ACPI_S0);
#endif
}
file->f_pos += *len;
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index ec33f2269..b14f8caf3 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -131,7 +131,7 @@ static spinlock_t i8259A_lock = SPIN_LOCK_UNLOCKED;
static void end_8259A_irq (unsigned int irq)
{
- if (!(irq_desc[irq].status & IRQ_DISABLED))
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_8259A_irq(irq);
}
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 129a587f0..02669540f 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -18,6 +18,7 @@
#include <linux/mm.h>
#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
@@ -1160,7 +1161,7 @@ static void end_level_ioapic_irq (unsigned int i)
static void mask_and_ack_level_ioapic_irq (unsigned int i) { /* nothing */ }
-static void set_ioapic_affinity (unsigned int irq, unsigned int mask)
+static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
{
unsigned long flags;
/*
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 7054249e6..4163626f4 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -32,7 +32,6 @@
#include <linux/kernel_stat.h>
#include <linux/irq.h>
#include <linux/proc_fs.h>
-#include <linux/irq.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -184,24 +183,43 @@ int get_irq_list(char *buf)
unsigned char global_irq_holder = NO_PROC_ID;
unsigned volatile int global_irq_lock;
+extern void show_stack(unsigned long* esp);
+
static void show(char * str)
{
int i;
- unsigned long *stack;
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
- printk("irq: %d [%d %d]\n",
- irqs_running(), local_irq_count(0), local_irq_count(1));
- printk("bh: %d [%d %d]\n",
- spin_is_locked(&global_bh_lock) ? 1 : 0, local_bh_count(0), local_bh_count(1));
- stack = (unsigned long *) &stack;
- for (i = 40; i ; i--) {
- unsigned long x = *++stack;
- if (x > (unsigned long) &get_option && x < (unsigned long) &vsprintf) {
- printk("<[%08lx]> ", x);
+ printk("irq: %d [",irqs_running());
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_irq_count(i));
+ printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
+ for(i=0;i < smp_num_cpus;i++)
+ printk(" %d",local_bh_count(i));
+
+ printk(" ]\nStack dumps:");
+ for(i=0;i< smp_num_cpus;i++) {
+ unsigned long esp;
+ if(i==cpu)
+ continue;
+ printk("\nCPU %d:",i);
+ esp = init_tss[i].esp0;
+ if(esp==NULL) {
+ /* tss->esp0 is set to NULL in cpu_init(),
+ * it's initialized when the cpu returns to user
+ * space. -- manfreds
+ */
+ printk(" <unknown> ");
+ continue;
}
- }
+ esp &= ~(THREAD_SIZE-1);
+ esp += sizeof(struct task_struct);
+ show_stack((void*)esp);
+ }
+ printk("\nCPU %d:",cpu);
+ show_stack(NULL);
+ printk("\n");
}
#define MAXCOUNT 100000000
@@ -874,7 +892,7 @@ static struct proc_dir_entry * root_irq_dir;
static struct proc_dir_entry * irq_dir [NR_IRQS];
static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
-unsigned int irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = 0xffffffff};
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
#define HEX_DIGITS 8
@@ -883,7 +901,7 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off,
{
if (count < HEX_DIGITS+1)
return -EINVAL;
- return sprintf (page, "%08x\n", irq_affinity[(int)data]);
+ return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
}
static unsigned int parse_hex_value (const char *buffer,
@@ -926,7 +944,7 @@ out:
static int irq_affinity_write_proc (struct file *file, const char *buffer,
unsigned long count, void *data)
{
- int irq = (int) data, full_count = count, err;
+ int irq = (long) data, full_count = count, err;
unsigned long new_value;
if (!irq_desc[irq].handler->set_affinity)
@@ -993,7 +1011,7 @@ static void register_irq_proc (unsigned int irq)
entry = create_proc_entry("smp_affinity", 0700, irq_dir[irq]);
entry->nlink = 1;
- entry->data = (void *)irq;
+ entry->data = (void *)(long)irq;
entry->read_proc = irq_affinity_read_proc;
entry->write_proc = irq_affinity_write_proc;
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 84490b40b..f858d7da9 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -23,20 +23,23 @@
* 1.02 21 February 2000, Tigran Aivazian <tigran@sco.com>
* Added 'device trimming' support. open(O_WRONLY) zeroes
* and frees the saved copy of applied microcode.
+ * 1.03 29 February 2000, Tigran Aivazian <tigran@sco.com>
+ * Made to use devfs (/dev/cpu/microcode) + cleanups.
*/
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/smp_lock.h>
-#include <linux/proc_fs.h>
+#include <linux/devfs_fs_kernel.h>
#include <asm/msr.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
-#define MICROCODE_VERSION "1.02"
+#define MICROCODE_VERSION "1.03"
MODULE_DESCRIPTION("CPU (P6) microcode update driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>");
@@ -60,9 +63,10 @@ static void do_update_one(void *);
static unsigned long microcode_status = 0;
/* the actual array of microcode blocks, each 2048 bytes */
-static struct microcode * microcode = NULL;
+static struct microcode *microcode = NULL;
static unsigned int microcode_num = 0;
static char *mc_applied = NULL; /* holds an array of applied microcode blocks */
+static unsigned int mc_fsize; /* used often, so compute once at microcode_init() */
static struct file_operations microcode_fops = {
read: microcode_read,
@@ -71,23 +75,25 @@ static struct file_operations microcode_fops = {
release: microcode_release,
};
-static struct proc_dir_entry *proc_microcode;
+static devfs_handle_t devfs_handle;
static int __init microcode_init(void)
{
- proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver);
- if (!proc_microcode) {
- printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n");
- return -ENOMEM;
- }
- proc_microcode->proc_fops = &microcode_fops;
+ devfs_handle = devfs_register(NULL, "cpu/microcode", 0, DEVFS_FL_DEFAULT, 0, 0,
+ S_IFREG | S_IRUSR | S_IWUSR, 0, 0, &microcode_fops, NULL);
+ if (!devfs_handle) {
+ printk(KERN_ERR "microcode: can't create /dev/cpu/microcode\n");
+ return -ENOMEM;
+ }
+ /* XXX assume no hotplug CPUs so smp_num_cpus does not change */
+ mc_fsize = smp_num_cpus * sizeof(struct microcode);
printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION);
return 0;
}
static void __exit microcode_exit(void)
{
- remove_proc_entry("microcode", proc_root_driver);
+ devfs_unregister(devfs_handle);
if (mc_applied)
kfree(mc_applied);
printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION);
@@ -108,25 +114,21 @@ static int microcode_open(struct inode *inode, struct file *file)
if (test_and_set_bit(MICROCODE_IS_OPEN, &microcode_status))
return -EBUSY;
- if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
- proc_microcode->size = 0;
- if (mc_applied) {
- memset(mc_applied, 0, smp_num_cpus * sizeof(struct microcode));
- kfree(mc_applied);
- mc_applied = NULL;
- }
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY && mc_applied) {
+ devfs_set_file_size(devfs_handle, 0);
+ memset(mc_applied, 0, mc_fsize);
+ kfree(mc_applied);
+ mc_applied = NULL;
}
MOD_INC_USE_COUNT;
-
return 0;
}
static int microcode_release(struct inode *inode, struct file *file)
{
- MOD_DEC_USE_COUNT;
-
clear_bit(MICROCODE_IS_OPEN, &microcode_status);
+ MOD_DEC_USE_COUNT;
return 0;
}
@@ -156,19 +158,17 @@ static int do_microcode_update(void)
memcpy(m, &microcode[update_req[i].slot], sizeof(struct microcode));
}
}
- return error ? -EIO : 0;
+ return error;
}
static void do_update_one(void *arg)
{
- struct update_req *req;
- struct cpuinfo_x86 * c;
+ int cpu_num = smp_processor_id();
+ struct cpuinfo_x86 *c = cpu_data + cpu_num;
+ struct update_req *req = (struct update_req *)arg + cpu_num;
unsigned int pf = 0, val[2], rev, sig;
- int i, cpu_num;
+ int i;
- cpu_num = smp_processor_id();
- c = cpu_data + cpu_num;
- req = (struct update_req *)arg + cpu_num;
req->err = 1; /* be pessimistic */
if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6)
@@ -210,8 +210,8 @@ static void do_update_one(void *arg)
req->err = 0;
req->slot = i;
- printk(KERN_ERR "microcode: CPU%d microcode updated "
- "from revision %d to %d, date=%08x\n",
+ printk(KERN_ERR "microcode: CPU%d updated from revision "
+ "%d to %d, date=%08x\n",
cpu_num, rev, val[1], m->date);
}
break;
@@ -220,12 +220,10 @@ static void do_update_one(void *arg)
static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
{
- size_t fsize = smp_num_cpus * sizeof(struct microcode);
-
- if (!proc_microcode->size || *ppos >= fsize)
- return 0; /* EOF */
- if (*ppos + len > fsize)
- len = fsize - *ppos;
+ if (*ppos >= mc_fsize)
+ return 0;
+ if (*ppos + len > mc_fsize)
+ len = mc_fsize - *ppos;
if (copy_to_user(buf, mc_applied + *ppos, len))
return -EFAULT;
*ppos += len;
@@ -242,33 +240,34 @@ static ssize_t microcode_write(struct file *file, const char *buf, size_t len, l
return -EINVAL;
}
if (!mc_applied) {
- int size = smp_num_cpus * sizeof(struct microcode);
- mc_applied = kmalloc(size, GFP_KERNEL);
+ mc_applied = kmalloc(mc_fsize, GFP_KERNEL);
if (!mc_applied) {
- printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n");
+ printk(KERN_ERR "microcode: out of memory for saved microcode\n");
return -ENOMEM;
}
- memset(mc_applied, 0, size);
+ memset(mc_applied, 0, mc_fsize);
}
lock_kernel();
microcode_num = len/sizeof(struct microcode);
microcode = vmalloc(len);
if (!microcode) {
- unlock_kernel();
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_unlock;
}
if (copy_from_user(microcode, buf, len)) {
- vfree(microcode);
- unlock_kernel();
- return -EFAULT;
+ ret = -EFAULT;
+ goto out_vfree;
}
- ret = do_microcode_update();
- if (!ret) {
- proc_microcode->size = smp_num_cpus * sizeof(struct microcode);
- ret = (ssize_t)len;
+ if(do_microcode_update()) {
+ ret = -EIO;
+ goto out_vfree;
}
+ devfs_set_file_size(devfs_handle, mc_fsize);
+ ret = (ssize_t)len;
+out_vfree:
vfree(microcode);
+out_unlock:
unlock_kernel();
return ret;
}
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
index d5b2b0062..a76c92d25 100644
--- a/arch/i386/kernel/pci-pc.c
+++ b/arch/i386/kernel/pci-pc.c
@@ -1044,6 +1044,45 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt)
printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
}
+static void set_level_irq(unsigned irq)
+{
+ unsigned char mask = 1 << (irq & 7);
+ unsigned int port = 0x4d0 + (irq >> 3);
+ unsigned char val = inb(port);
+
+ if (val & mask) {
+ printk("PCI irq %d was level\n", irq);
+ return;
+ }
+ printk("PCI irq %d was edge, turning into level-triggered\n", irq);
+ outb(val | mask, port);
+}
+
+static int ali_set_irq(struct pci_dev *router, unsigned pirq, unsigned irq)
+{
+ if (irq < 15) {
+ static unsigned char irqmap[16] = {
+ 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15
+ };
+ unsigned char val = irqmap[irq];
+ if (val && pirq < 8) {
+ u8 byte;
+ unsigned offset = 0x48 + (pirq >> 1);
+ unsigned shift = (pirq & 1) << 2;
+ pci_read_config_byte(router, offset, &byte);
+ printk("ALI: old %04x=%02x\n", offset, byte);
+ byte &= ~(0xf << shift);
+ byte |= val << shift;
+ printk("ALI: new %04x=%02x\n", offset, byte);
+ pci_write_config_byte(router, offset, byte);
+ set_level_irq(irq);
+ return irq;
+ }
+ }
+ return 0;
+}
+
+
/*
* In case BIOS forgets to tell us about IRQ, we try to look it up in the routing
* table, but unfortunately we have to know the interrupt router chip.
@@ -1135,6 +1174,10 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r
DBG(" -> [PIIX] sink\n");
break;
case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533):
+ newirq = ali_set_irq(router, pirq-1, newirq);
+ if (newirq)
+ msg = "ALI";
+ break;
default:
DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device);
if (newirq && mask == (1 << newirq)) {
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 19f7022a4..a043b4cfe 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -693,7 +693,6 @@ asmlinkage int sys_execve(struct pt_regs regs)
int error;
char * filename;
- lock_kernel();
filename = getname((char *) regs.ebx);
error = PTR_ERR(filename);
if (IS_ERR(filename))
@@ -703,7 +702,6 @@ asmlinkage int sys_execve(struct pt_regs regs)
current->flags &= ~PF_DTRACE;
putname(filename);
out:
- unlock_kernel();
return error;
}
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index a973746b9..d9af88d82 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -419,13 +419,19 @@ static void setup_frame(int sig, struct k_sigaction *ka,
? current->exec_domain->signal_invmap[sig]
: sig),
&frame->sig);
+ if (err)
+ goto give_sigsegv;
err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]);
+ if (err)
+ goto give_sigsegv;
if (_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
+ if (err)
+ goto give_sigsegv;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -486,6 +492,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(&frame->info, &frame->pinfo);
err |= __put_user(&frame->uc, &frame->puc);
err |= __copy_to_user(&frame->info, info, sizeof(*info));
+ if (err)
+ goto give_sigsegv;
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -497,6 +505,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ if (err)
+ goto give_sigsegv;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 7400b628b..3a7004970 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
+#include <linux/interrupt.h>
#ifdef CONFIG_MCA
#include <linux/mca.h>