From b9558d5f86c471a125abf1fb3a3882fb053b1f8c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Fri, 18 Feb 2000 00:24:27 +0000 Subject: Merge with Linux 2.3.41. --- arch/i386/kernel/Makefile | 13 ++- arch/i386/kernel/acpi.c | 256 ++++++++++++++++++++++++------------------ arch/i386/kernel/apm.c | 17 +-- arch/i386/kernel/entry.S | 3 +- arch/i386/kernel/i386_ksyms.c | 4 + arch/i386/kernel/pci-dma.c | 51 +++++++++ arch/i386/kernel/pm.c | 104 +++++++++++++++++ arch/i386/kernel/signal.c | 2 - arch/i386/kernel/sys_i386.c | 8 +- 9 files changed, 327 insertions(+), 131 deletions(-) create mode 100644 arch/i386/kernel/pci-dma.c create mode 100644 arch/i386/kernel/pm.c (limited to 'arch/i386/kernel') diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index a59e7c71b..6b7302f99 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -14,7 +14,8 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o O_OBJS := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ - ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o + ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ + pci-dma.o OX_OBJS := i386_ksyms.o MX_OBJS := @@ -39,8 +40,16 @@ else endif endif +ifdef CONFIG_ACPI +OX_OBJS += pm.o +else +ifdef CONFIG_APM +OX_OBJS += pm.o +endif +endif + ifeq ($(CONFIG_ACPI),y) - OX_OBJS += acpi.o + O_OBJS += acpi.o endif ifeq ($(CONFIG_APM),y) diff --git a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c index 3fd1704e3..5ad3106f8 100644 --- a/arch/i386/kernel/acpi.c +++ b/arch/i386/kernel/acpi.c @@ -39,24 +39,9 @@ #include #include #include +#include #include -/* - * Defines for 2.2.x - */ -#ifndef __exit -#define __exit -#endif -#ifndef module_init -#define module_init(x) int init_module(void) {return x();} -#endif -#ifndef module_exit -#define module_exit(x) void cleanup_module(void) {x();} -#endif -#ifndef DECLARE_WAIT_QUEUE_HEAD -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue * x = NULL -#endif - /* * Yes, it's unfortunate that we are relying on get_cmos_time * because it is slow (> 1 sec.) and i386 only. It might be better @@ -108,9 +93,6 @@ static volatile u32 acpi_gpe_level = 0; static volatile acpi_sstate_t acpi_event_state = ACPI_S0; static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); -static spinlock_t acpi_devs_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(acpi_devs); - /* Make it impossible to enter C2/C3 until after we've initialized */ static unsigned long acpi_enter_lvl2_lat = ACPI_INFINITE_LAT; static unsigned long acpi_enter_lvl3_lat = ACPI_INFINITE_LAT; @@ -520,21 +502,14 @@ static void acpi_destroy_tables(void) } /* - * Locate PIIX4 device and create a fake FACP + * Init PIIX4 device, create a fake FACP */ -static int __init acpi_find_piix4(void) +static int __init acpi_init_piix4(struct pci_dev *dev) { - struct pci_dev *dev; u32 base; u16 cmd; u8 pmregmisc; - dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, - NULL); - if (!dev) - return -ENODEV; - pci_read_config_word(dev, PCI_COMMAND, &cmd); if (!(cmd & PCI_COMMAND_IO)) return -ENODEV; @@ -586,6 +561,124 @@ static int __init acpi_find_piix4(void) return 0; } +/* + * Init VIA ACPI device and create a fake FACP + */ +static int __init acpi_init_via686a(struct pci_dev *dev) +{ + u32 base; + u8 tmp, irq; + + pci_read_config_byte(dev, 0x41, &tmp); + if (!(tmp & 0x80)) + return -ENODEV; + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &tmp); + tmp = (tmp & 0x10 ? 0x48 : 0x20); + + pci_read_config_dword(dev, tmp, &base); + if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) + return -ENODEV; + + base &= PCI_BASE_ADDRESS_IO_MASK; + if (!base) + return -ENODEV; + + pci_read_config_byte(dev, 0x42, &irq); + + printk(KERN_INFO "ACPI: found %s at 0x%04x\n", dev->name, base); + + acpi_facp = kmalloc(sizeof(struct acpi_facp), GFP_KERNEL); + if (!acpi_facp) + return -ENOMEM; + + acpi_fake_facp = 1; + memset(acpi_facp, 0, sizeof(struct acpi_facp)); + + acpi_facp->int_model = ACPI_VIA_INT_MODEL; + acpi_facp->sci_int = irq; + acpi_facp->smi_cmd = base + ACPI_VIA_SMI_CMD; + acpi_facp->acpi_enable = ACPI_VIA_ACPI_ENABLE; + acpi_facp->acpi_disable = ACPI_VIA_ACPI_DISABLE; + acpi_facp->pm1a_evt = base + ACPI_VIA_PM1_EVT; + acpi_facp->pm1a_cnt = base + ACPI_VIA_PM1_CNT; + acpi_facp->pm_tmr = base + ACPI_VIA_PM_TMR; + acpi_facp->gpe0 = base + ACPI_VIA_GPE0; + + acpi_facp->pm1_evt_len = ACPI_VIA_PM1_EVT_LEN; + acpi_facp->pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN; + acpi_facp->pm_tm_len = ACPI_VIA_PM_TM_LEN; + acpi_facp->gpe0_len = ACPI_VIA_GPE0_LEN; + acpi_facp->p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; + acpi_facp->p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; + + acpi_facp->duty_offset = ACPI_VIA_DUTY_OFFSET; + acpi_facp->duty_width = ACPI_VIA_DUTY_WIDTH; + + acpi_facp->day_alarm = ACPI_VIA_DAY_ALARM; + acpi_facp->mon_alarm = ACPI_VIA_MON_ALARM; + acpi_facp->century = ACPI_VIA_CENTURY; + + acpi_facp_addr = virt_to_phys(acpi_facp); + acpi_dsdt_addr = 0; + + acpi_p_blk = base + ACPI_VIA_P_BLK; + + return 0; +} + +typedef enum +{ + CH_UNKNOWN = 0, + CH_INTEL_PIIX4, + CH_VIA_686A, +} acpi_chip_t; + +/* indexed by value of each enum in acpi_chip_t */ +const static struct +{ + int (*chip_init)(struct pci_dev *dev); +} acpi_chip_info[] = +{ + {NULL,}, + {acpi_init_piix4}, + {acpi_init_via686a}, +}; + +const static struct pci_device_id acpi_pci_tbl[] = +{ + {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, + {0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A}, + {0,}, /* terminate list */ +}; + +static int __init acpi_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return acpi_chip_info[id->driver_data].chip_init(dev); +} + +static struct pci_driver acpi_driver = +{ + name: "acpi", + id_table: acpi_pci_tbl, + probe: acpi_probe, +}; +static int pci_driver_registered = 0; + +/* + * Locate a known ACPI chipset + */ +static int __init acpi_find_chipset(void) +{ + if (pci_register_driver(&acpi_driver) < 1) + return -ENODEV; + + pci_driver_registered = 1; + + return 0; +} + /* * Handle an ACPI SCI (fixed or general purpose event) */ @@ -693,7 +786,7 @@ static void wake_on_busmaster(struct acpi_facp *facp) /* The ACPI timer is just the low 24 bits */ #define TIME_BEGIN(tmr) inl(tmr) -#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff) +#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff) /* @@ -836,24 +929,11 @@ out: static int acpi_enter_dx(acpi_dstate_t state) { int status = 0; - struct list_head *i = acpi_devs.next; - - while (i != &acpi_devs) { - struct acpi_dev *dev = list_entry(i, struct acpi_dev, entry); - if (dev->state != state) { - int dev_status = 0; - if (dev->info.transition) - dev_status = dev->info.transition(dev, state); - if (!dev_status) { - // put hardware into D-state - dev->state = state; - } - if (dev_status) - status = dev_status; - } - - i = i->next; - } + + if (state == ACPI_D0) + status = pm_send_request(PM_RESUME, (void*) state); + else + status = pm_send_request(PM_SUSPEND, (void*) state); return status; } @@ -1208,6 +1288,7 @@ static int acpi_do_sleep(ctl_table *ctl, return 0; } + /* * Initialize and enable ACPI */ @@ -1218,17 +1299,17 @@ static int __init acpi_init(void) if (acpi_disabled) return -ENODEV; - if (acpi_find_tables() && acpi_find_piix4()) { - // no ACPI tables and not PIIX4 + if (acpi_find_tables() && acpi_find_chipset()) { + // no ACPI tables and not recognized chipset return -ENODEV; } - /* - * Internally we always keep latencies in timer - * ticks, which is simpler and more consistent (what is - * an uS to us?). Besides, that gives people more - * control in the /proc interfaces. - */ + /* + * Internally we always keep latencies in timer + * ticks, which is simpler and more consistent (what is + * an uS to us?). Besides, that gives people more + * control in the /proc interfaces. + */ if (acpi_facp->p_lvl2_lat && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) { acpi_p_lvl2_lat = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat); @@ -1249,7 +1330,11 @@ static int __init acpi_init(void) acpi_facp)) { printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", acpi_facp->sci_int); + + if (pci_driver_registered) + pci_unregister_driver(&acpi_driver); acpi_destroy_tables(); + return -ENODEV; } @@ -1296,8 +1381,14 @@ static void __exit acpi_exit(void) free_irq(acpi_facp->sci_int, acpi_facp); acpi_destroy_tables(); + + if (pci_driver_registered) + pci_unregister_driver(&acpi_driver); } +/* + * Parse kernel command line options + */ static int __init acpi_setup(char *str) { while (str && *str) { @@ -1314,53 +1405,6 @@ static int __init acpi_setup(char *str) __setup("acpi=", acpi_setup); -/* - * Register a device with the ACPI subsystem - */ -struct acpi_dev* acpi_register(struct acpi_dev_info *info, unsigned long adr) -{ - struct acpi_dev *dev = NULL; - if (info) { - dev = kmalloc(sizeof(struct acpi_dev), GFP_KERNEL); - if (dev) { - unsigned long flags; - - memset(dev, 0, sizeof(*dev)); - memcpy(&dev->info, info, sizeof(dev->info)); - dev->adr = adr; - - spin_lock_irqsave(&acpi_devs_lock, flags); - list_add(&dev->entry, &acpi_devs); - spin_unlock_irqrestore(&acpi_devs_lock, flags); - } - } - return dev; -} - -/* - * Unregister a device with ACPI - */ -void acpi_unregister(struct acpi_dev *dev) -{ - if (dev) { - unsigned long flags; - - spin_lock_irqsave(&acpi_devs_lock, flags); - list_del(&dev->entry); - spin_unlock_irqrestore(&acpi_devs_lock, flags); - - kfree(dev); - } -} - -/* - * Wake up a device - */ -void acpi_wakeup(struct acpi_dev *dev) -{ - // run _PS0 or tell parent bus to wake device up -} - /* * Manage idle devices */ @@ -1382,11 +1426,3 @@ static int acpi_control_thread(void *context) } __initcall(acpi_init); - -/* - * Module visible symbols - */ -EXPORT_SYMBOL(acpi_control_wait); -EXPORT_SYMBOL(acpi_register); -EXPORT_SYMBOL(acpi_unregister); -EXPORT_SYMBOL(acpi_wakeup); diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 8f3d24645..daa7226cd 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -1413,18 +1413,11 @@ static int __init apm_setup(char *str) __setup("apm=", apm_setup); static struct file_operations apm_bios_fops = { - NULL, /* lseek */ - do_read, - NULL, /* write */ - NULL, /* readdir */ - do_poll, - do_ioctl, - NULL, /* mmap */ - do_open, - NULL, /* flush */ - do_release, - NULL, /* fsync */ - NULL /* fasync */ + read: do_read, + poll: do_poll, + ioctl: do_ioctl, + open: do_open, + release: do_release, }; static struct miscdevice apm_device = { diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index e91602aba..f93765754 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -617,6 +617,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_setgid) .long SYMBOL_NAME(sys_setfsuid) /* 215 */ .long SYMBOL_NAME(sys_setfsgid) + .long SYMBOL_NAME(sys_pivot_root) /* @@ -625,6 +626,6 @@ ENTRY(sys_call_table) * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-216 + .rept NR_syscalls-217 .long SYMBOL_NAME(sys_ni_syscall) .endr diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 2df82ff21..456f4bab2 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -86,6 +87,9 @@ EXPORT_SYMBOL(__generic_copy_from_user); EXPORT_SYMBOL(__generic_copy_to_user); EXPORT_SYMBOL(strnlen_user); +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); + #ifdef CONFIG_X86_USE_3DNOW EXPORT_SYMBOL(_mmx_memcpy); EXPORT_SYMBOL(mmx_clear_page); diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c new file mode 100644 index 000000000..18b203228 --- /dev/null +++ b/arch/i386/kernel/pci-dma.c @@ -0,0 +1,51 @@ +/* + * Dynamic DMA mapping support. + * + * On i386 there is no hardware dynamic DMA address translation, + * so consistent alloc/free are merely page allocation/freeing. + * The rest of the dynamic DMA mapping interface is implemented + * in asm/pci.h. + */ + +#include +#include +#include +#include +#include + +/* Pure 2^n version of get_order */ +extern __inline__ int __get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, __get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, __get_order(size)); +} diff --git a/arch/i386/kernel/pm.c b/arch/i386/kernel/pm.c new file mode 100644 index 000000000..35ec0f489 --- /dev/null +++ b/arch/i386/kernel/pm.c @@ -0,0 +1,104 @@ +/* + * pm.c - Power management interface + * + * Copyright (C) 2000 Andrew Henroid + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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-1307 USA + */ + +#include +#include +#include +#include + +static spinlock_t pm_devs_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(pm_devs); + +/* + * Register a device with power management + */ +struct pm_dev *pm_register(pm_dev_t type, + unsigned long id, + pm_callback callback) +{ + struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); + if (dev) { + unsigned long flags; + + memset(dev, 0, sizeof(*dev)); + dev->type = type; + dev->id = id; + dev->callback = callback; + + spin_lock_irqsave(&pm_devs_lock, flags); + list_add(&dev->entry, &pm_devs); + spin_unlock_irqrestore(&pm_devs_lock, flags); + } + return dev; +} + +/* + * Unregister a device with power management + */ +void pm_unregister(struct pm_dev *dev) +{ + if (dev) { + unsigned long flags; + + spin_lock_irqsave(&pm_devs_lock, flags); + list_del(&dev->entry); + spin_unlock_irqrestore(&pm_devs_lock, flags); + + kfree(dev); + } +} + +/* + * Send a request to all devices + */ +int pm_send_request(pm_request_t rqst, void *data) +{ + struct list_head *entry = pm_devs.next; + while (entry != &pm_devs) { + struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); + if (dev->callback) { + int status = (*dev->callback)(dev, rqst, data); + if (status) + return status; + } + entry = entry->next; + } + return 0; +} + +/* + * Find a device + */ +struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from) +{ + struct list_head *entry = from ? from->entry.next:pm_devs.next; + while (entry != &pm_devs) { + struct pm_dev *dev = list_entry(entry, struct pm_dev, entry); + if (type == PM_UNKNOWN_DEV || dev->type == type) + return dev; + entry = entry->next; + } + return 0; +} + +EXPORT_SYMBOL(pm_register); +EXPORT_SYMBOL(pm_unregister); +EXPORT_SYMBOL(pm_send_request); +EXPORT_SYMBOL(pm_find); diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 18de47dd4..a973746b9 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -643,7 +642,6 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; - info.si_uid16 = high2lowuid(current->p_pptr->uid); } /* If the (new) signal is now blocked, requeue it. */ diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c index 8a0c6dbda..362ee64c0 100644 --- a/arch/i386/kernel/sys_i386.c +++ b/arch/i386/kernel/sys_i386.c @@ -218,9 +218,9 @@ asmlinkage int sys_uname(struct old_utsname * name) int err; if (!name) return -EFAULT; - down(&uts_sem); + down_read(&uts_sem); err=copy_to_user(name, &system_utsname, sizeof (*name)); - up(&uts_sem); + up_read(&uts_sem); return err?-EFAULT:0; } @@ -233,7 +233,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name) if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) return -EFAULT; - down(&uts_sem); + down_read(&uts_sem); error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); error |= __put_user(0,name->sysname+__OLD_UTS_LEN); @@ -246,7 +246,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name) error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); error |= __put_user(0,name->machine+__OLD_UTS_LEN); - up(&uts_sem); + up_read(&uts_sem); error = error ? -EFAULT : 0; -- cgit v1.2.3