diff options
Diffstat (limited to 'arch/mips')
41 files changed, 978 insertions, 2241 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 44a0224c32dd..a92ce6bd7cf1 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -8,6 +8,10 @@ mainmenu "Linux/MIPS Kernel Configuration" menu "Machine selection" +config ZONE_DMA + bool + default y + choice prompt "System type" default SGI_IP22 @@ -594,8 +598,6 @@ config SGI_IP32 select ARC select ARC32 select BOOT_ELF32 - select OWN_DMA - select DMA_IP32 select DMA_NONCOHERENT select HW_HAS_PCI select R5000_CPU_SCACHE @@ -753,6 +755,7 @@ config TOSHIBA_JMR3927 select SWAP_IO_SPACE select SYS_HAS_CPU_TX39XX select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN select TOSHIBA_BOARDS @@ -767,6 +770,7 @@ config TOSHIBA_RBTX4927 select SYS_HAS_CPU_TX49XX select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_BIG_ENDIAN select TOSHIBA_BOARDS select GENERIC_HARDIRQS_NO__DO_IRQ @@ -877,9 +881,6 @@ config DMA_NONCOHERENT config DMA_NEED_PCI_MAP_STATE bool -config OWN_DMA - bool - config EARLY_PRINTK bool @@ -934,6 +935,9 @@ config CPU_LITTLE_ENDIAN endchoice +config SYS_SUPPORTS_APM_EMULATION + bool + config SYS_SUPPORTS_BIG_ENDIAN bool @@ -1001,6 +1005,7 @@ config SOC_AU1X00 bool select SYS_HAS_CPU_MIPS32_R1 select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_APM_EMULATION config PNX8550 bool @@ -2071,35 +2076,11 @@ config BINFMT_ELF32 bool default y if MIPS32_O32 || MIPS32_N32 -config PM - bool "Power Management support (EXPERIMENTAL)" - depends on EXPERIMENTAL && SOC_AU1X00 - -config APM - tristate "Advanced Power Management Emulation" - depends on PM - ---help--- - APM is a BIOS specification for saving power using several different - techniques. This is mostly useful for battery powered systems with - APM compliant BIOSes. If you say Y here, the system time will be - reset after a RESUME operation, the /proc/apm device will provide - battery status information, and user-space programs will receive - notification of APM "events" (e.g. battery status change). - - In order to use APM, you will need supporting software. For location - and more information, read <file:Documentation/pm.txt> and the - Battery Powered Linux mini-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - This driver does not spin down disk drives (see the hdparm(8) - manpage ("man 8 hdparm") for that), and it doesn't turn off - VESA-compliant "green" monitors. - - Generally, if you don't have a battery in your machine, there isn't - much point in using this driver and you should say N. If you get - random kernel OOPSes or reboots that don't seem to be related to - anything, try disabling/enabling this option (or disabling/enabling - APM in your BIOS). +endmenu + +menu "Power management options" + +source "kernel/power/Kconfig" endmenu diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c index 7504a6364616..3901e8e04755 100644 --- a/arch/mips/au1000/common/power.c +++ b/arch/mips/au1000/common/power.c @@ -62,12 +62,6 @@ extern unsigned long save_local_and_disable(int controller); extern void restore_local_and_enable(int controller, unsigned long mask); extern void local_enable_irq(unsigned int irq_nr); -/* Quick acpi hack. This will have to change! */ -#define CTL_ACPI 9999 -#define ACPI_S1_SLP_TYP 19 -#define ACPI_SLEEP 21 - - static DEFINE_SPINLOCK(pm_lock); /* We need to save/restore a bunch of core registers that are @@ -425,15 +419,41 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file, static struct ctl_table pm_table[] = { - {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend}, - {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep}, - {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "suspend", + .data = NULL, + .maxlen = 0, + .mode = 0600, + .proc_handler = &pm_do_suspend + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sleep", + .data = NULL, + .maxlen = 0, + .mode = 0600, + .proc_handler = &pm_do_sleep + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "freq", + .data = NULL, + .maxlen = 0, + .mode = 0600, + .proc_handler = &pm_do_freq + }, + {} }; static struct ctl_table pm_dir_table[] = { - {CTL_ACPI, "pm", NULL, 0, 0555, pm_table}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "pm", + .mode = 0555, + .child = pm_table + }, + {} }; /* @@ -441,7 +461,7 @@ static struct ctl_table pm_dir_table[] = { */ static int __init pm_init(void) { - register_sysctl_table(pm_dir_table, 1); + register_sysctl_table(pm_dir_table); return 0; } diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index 96090f28373b..f21186c12d81 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -264,7 +264,7 @@ CONFIG_BINFMT_ELF=y CONFIG_MIPS32_COMPAT=y CONFIG_COMPAT=y CONFIG_MIPS32_O32=y -# CONFIG_MIPS32_N32 is not set +CONFIG_MIPS32_N32=y CONFIG_BINFMT_ELF32=y # diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile index ed181fdc3ac9..8b790c2900d5 100644 --- a/arch/mips/dec/Makefile +++ b/arch/mips/dec/Makefile @@ -6,6 +6,7 @@ obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \ kn02-irq.o kn02xa-berr.o reset.o setup.o time.o obj-$(CONFIG_PROM_CONSOLE) += promcon.o +obj-$(CONFIG_TC) += tc.o obj-$(CONFIG_CPU_HAS_WB) += wbflush.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S index b251ef864c33..00cecdcc75f2 100644 --- a/arch/mips/dec/int-handler.S +++ b/arch/mips/dec/int-handler.S @@ -264,9 +264,6 @@ srlv t3,t1,t2 handle_it: - LONG_L s0, TI_REGS($28) - LONG_S sp, TI_REGS($28) - PTR_LA ra, ret_from_irq j dec_irq_dispatch nop @@ -277,7 +274,6 @@ fpu: #endif spurious: - PTR_LA ra, _ret_from_irq j spurious_interrupt nop END(plat_irq_dispatch) diff --git a/arch/mips/dec/prom/identify.c b/arch/mips/dec/prom/identify.c index 81d5e878ddce..c4e3c1ea0d48 100644 --- a/arch/mips/dec/prom/identify.c +++ b/arch/mips/dec/prom/identify.c @@ -88,6 +88,7 @@ static inline void prom_init_kn02(void) { dec_kn_slot_base = KN02_SLOT_BASE; dec_kn_slot_size = KN02_SLOT_SIZE; + dec_tc_bus = 1; dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + KN02_RTC); } @@ -96,6 +97,7 @@ static inline void prom_init_kn02xa(void) { dec_kn_slot_base = KN02XA_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); @@ -105,6 +107,7 @@ static inline void prom_init_kn03(void) { dec_kn_slot_base = KN03_SLOT_BASE; dec_kn_slot_size = IOASIC_SLOT_SIZE; + dec_tc_bus = 1; ioasic_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_IOCTL); dec_rtc_base = (void *)CKSEG1ADDR(dec_kn_slot_base + IOASIC_TOY); diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c index 1058e2f409bb..b8a5e75ba0ab 100644 --- a/arch/mips/dec/setup.c +++ b/arch/mips/dec/setup.c @@ -53,6 +53,8 @@ unsigned long dec_kn_slot_base, dec_kn_slot_size; EXPORT_SYMBOL(dec_kn_slot_base); EXPORT_SYMBOL(dec_kn_slot_size); +int dec_tc_bus; + spinlock_t ioasic_ssr_lock; volatile u32 *ioasic_base; diff --git a/arch/mips/dec/tc.c b/arch/mips/dec/tc.c new file mode 100644 index 000000000000..732027c79834 --- /dev/null +++ b/arch/mips/dec/tc.c @@ -0,0 +1,95 @@ +/* + * TURBOchannel architecture calls. + * + * Copyright (c) Harald Koerfgen, 1998 + * Copyright (c) 2001, 2003, 2005, 2006 Maciej W. Rozycki + * Copyright (c) 2005 James Simmons + * + * This file is subject to the terms and conditions of the GNU + * General Public License. See the file "COPYING" in the main + * directory of this archive for more details. + */ +#include <linux/compiler.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/tc.h> +#include <linux/types.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/paccess.h> + +#include <asm/dec/interrupts.h> +#include <asm/dec/prom.h> +#include <asm/dec/system.h> + +/* + * Protected read byte from TURBOchannel slot space. + */ +int tc_preadb(u8 *valp, void __iomem *addr) +{ + return get_dbe(*valp, (u8 *)addr); +} + +/* + * Get TURBOchannel bus information as specified by the spec, plus + * the slot space base address and the number of slots. + */ +int __init tc_bus_get_info(struct tc_bus *tbus) +{ + if (!dec_tc_bus) + return -ENXIO; + + memcpy(&tbus->info, rex_gettcinfo(), sizeof(tbus->info)); + tbus->slot_base = CPHYSADDR((long)rex_slot_address(0)); + + switch (mips_machtype) { + case MACH_DS5000_200: + tbus->num_tcslots = 7; + break; + case MACH_DS5000_2X0: + case MACH_DS5900: + tbus->ext_slot_base = 0x20000000; + tbus->ext_slot_size = 0x20000000; + /* fall through */ + case MACH_DS5000_1XX: + tbus->num_tcslots = 3; + break; + case MACH_DS5000_XX: + tbus->num_tcslots = 2; + default: + break; + } + return 0; +} + +/* + * Get the IRQ for the specified slot. + */ +void __init tc_device_get_irq(struct tc_dev *tdev) +{ + switch (tdev->slot) { + case 0: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC0]; + break; + case 1: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC1]; + break; + case 2: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC2]; + break; + /* + * Yuck! DS5000/200 onboard devices + */ + case 5: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC5]; + break; + case 6: + tdev->interrupt = dec_interrupt[DEC_IRQ_TC6]; + break; + default: + tdev->interrupt = -1; + break; + } +} diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index bbbb8d7cb89b..1bf2c8448912 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -14,8 +14,6 @@ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o -obj-$(CONFIG_APM) += apm.o - obj-$(CONFIG_CPU_R3000) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o diff --git a/arch/mips/kernel/apm.c b/arch/mips/kernel/apm.c deleted file mode 100644 index ba16d07588cb..000000000000 --- a/arch/mips/kernel/apm.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * bios-less APM driver for MIPS Linux - * Jamey Hicks <jamey@crl.dec.com> - * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) - * - * APM 1.2 Reference: - * Intel Corporation, Microsoft Corporation. Advanced Power Management - * (APM) BIOS Interface Specification, Revision 1.2, February 1996. - * - * [This document is available from Microsoft at: - * http://www.microsoft.com/hwdev/busbios/amp_12.htm] - */ -#include <linux/module.h> -#include <linux/poll.h> -#include <linux/timer.h> -#include <linux/slab.h> -#include <linux/proc_fs.h> -#include <linux/miscdevice.h> -#include <linux/apm_bios.h> -#include <linux/capability.h> -#include <linux/sched.h> -#include <linux/pm.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/init.h> -#include <linux/completion.h> - -#include <asm/apm.h> /* apm_power_info */ -#include <asm/system.h> - -/* - * The apm_bios device is one of the misc char devices. - * This is its minor number. - */ -#define APM_MINOR_DEV 134 - -/* - * See Documentation/Config.help for the configuration options. - * - * Various options can be changed at boot time as follows: - * (We allow underscores for compatibility with the modules code) - * apm=on/off enable/disable APM - */ - -/* - * Maximum number of events stored - */ -#define APM_MAX_EVENTS 16 - -struct apm_queue { - unsigned int event_head; - unsigned int event_tail; - apm_event_t events[APM_MAX_EVENTS]; -}; - -/* - * The per-file APM data - */ -struct apm_user { - struct list_head list; - - unsigned int suser: 1; - unsigned int writer: 1; - unsigned int reader: 1; - - int suspend_result; - unsigned int suspend_state; -#define SUSPEND_NONE 0 /* no suspend pending */ -#define SUSPEND_PENDING 1 /* suspend pending read */ -#define SUSPEND_READ 2 /* suspend read, pending ack */ -#define SUSPEND_ACKED 3 /* suspend acked */ -#define SUSPEND_DONE 4 /* suspend completed */ - - struct apm_queue queue; -}; - -/* - * Local variables - */ -static int suspends_pending; -static int apm_disabled; -static int mips_apm_active; - -static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); -static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); - -/* - * This is a list of everyone who has opened /dev/apm_bios - */ -static DECLARE_RWSEM(user_list_lock); -static LIST_HEAD(apm_user_list); - -/* - * kapmd info. kapmd provides us a process context to handle - * "APM" events within - specifically necessary if we're going - * to be suspending the system. - */ -static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait); -static DECLARE_COMPLETION(kapmd_exit); -static DEFINE_SPINLOCK(kapmd_queue_lock); -static struct apm_queue kapmd_queue; - - -static const char driver_version[] = "1.13"; /* no spaces */ - - - -/* - * Compatibility cruft until the IPAQ people move over to the new - * interface. - */ -static void __apm_get_power_status(struct apm_power_info *info) -{ -} - -/* - * This allows machines to provide their own "apm get power status" function. - */ -void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status; -EXPORT_SYMBOL(apm_get_power_status); - - -/* - * APM event queue management. - */ -static inline int queue_empty(struct apm_queue *q) -{ - return q->event_head == q->event_tail; -} - -static inline apm_event_t queue_get_event(struct apm_queue *q) -{ - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - return q->events[q->event_tail]; -} - -static void queue_add_event(struct apm_queue *q, apm_event_t event) -{ - q->event_head = (q->event_head + 1) % APM_MAX_EVENTS; - if (q->event_head == q->event_tail) { - static int notified; - - if (notified++ == 0) - printk(KERN_ERR "apm: an event queue overflowed\n"); - q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS; - } - q->events[q->event_head] = event; -} - -static void queue_event_one_user(struct apm_user *as, apm_event_t event) -{ - if (as->suser && as->writer) { - switch (event) { - case APM_SYS_SUSPEND: - case APM_USER_SUSPEND: - /* - * If this user already has a suspend pending, - * don't queue another one. - */ - if (as->suspend_state != SUSPEND_NONE) - return; - - as->suspend_state = SUSPEND_PENDING; - suspends_pending++; - break; - } - } - queue_add_event(&as->queue, event); -} - -static void queue_event(apm_event_t event, struct apm_user *sender) -{ - struct apm_user *as; - - down_read(&user_list_lock); - list_for_each_entry(as, &apm_user_list, list) { - if (as != sender && as->reader) - queue_event_one_user(as, event); - } - up_read(&user_list_lock); - wake_up_interruptible(&apm_waitqueue); -} - -static void apm_suspend(void) -{ - struct apm_user *as; - int err = pm_suspend(PM_SUSPEND_MEM); - - /* - * Anyone on the APM queues will think we're still suspended. - * Send a message so everyone knows we're now awake again. - */ - queue_event(APM_NORMAL_RESUME, NULL); - - /* - * Finally, wake up anyone who is sleeping on the suspend. - */ - down_read(&user_list_lock); - list_for_each_entry(as, &apm_user_list, list) { - as->suspend_result = err; - as->suspend_state = SUSPEND_DONE; - } - up_read(&user_list_lock); - - wake_up(&apm_suspend_waitqueue); -} - -static ssize_t apm_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) -{ - struct apm_user *as = fp->private_data; - apm_event_t event; - int i = count, ret = 0; - - if (count < sizeof(apm_event_t)) - return -EINVAL; - - if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) - return -EAGAIN; - - wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); - - while ((i >= sizeof(event)) && !queue_empty(&as->queue)) { - event = queue_get_event(&as->queue); - - ret = -EFAULT; - if (copy_to_user(buf, &event, sizeof(event))) - break; - - if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND) - as->suspend_state = SUSPEND_READ; - - buf += sizeof(event); - i -= sizeof(event); - } - - if (i < count) - ret = count - i; - - return ret; -} - -static unsigned int apm_poll(struct file *fp, poll_table * wait) -{ - struct apm_user *as = fp->private_data; - - poll_wait(fp, &apm_waitqueue, wait); - return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM; -} - -/* - * apm_ioctl - handle APM ioctl - * - * APM_IOC_SUSPEND - * This IOCTL is overloaded, and performs two functions. It is used to: - * - initiate a suspend - * - acknowledge a suspend read from /dev/apm_bios. - * Only when everyone who has opened /dev/apm_bios with write permission - * has acknowledge does the actual suspend happen. - */ -static int -apm_ioctl(struct inode * inode, struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct apm_user *as = filp->private_data; - unsigned long flags; - int err = -EINVAL; - - if (!as->suser || !as->writer) - return -EPERM; - - switch (cmd) { - case APM_IOC_SUSPEND: - as->suspend_result = -EINTR; - - if (as->suspend_state == SUSPEND_READ) { - /* - * If we read a suspend command from /dev/apm_bios, - * then the corresponding APM_IOC_SUSPEND ioctl is - * interpreted as an acknowledge. - */ - as->suspend_state = SUSPEND_ACKED; - suspends_pending--; - } else { - /* - * Otherwise it is a request to suspend the system. - * Queue an event for all readers, and expect an - * acknowledge from all writers who haven't already - * acknowledged. - */ - queue_event(APM_USER_SUSPEND, as); - } - - /* - * If there are no further acknowledges required, suspend - * the system. - */ - if (suspends_pending == 0) - apm_suspend(); - - /* - * Wait for the suspend/resume to complete. If there are - * pending acknowledges, we wait here for them. - * - * Note that we need to ensure that the PM subsystem does - * not kick us out of the wait when it suspends the threads. - */ - flags = current->flags; - current->flags |= PF_NOFREEZE; - - /* - * Note: do not allow a thread which is acking the suspend - * to escape until the resume is complete. - */ - if (as->suspend_state == SUSPEND_ACKED) - wait_event(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - else - wait_event_interruptible(apm_suspend_waitqueue, - as->suspend_state == SUSPEND_DONE); - - current->flags = flags; - err = as->suspend_result; - as->suspend_state = SUSPEND_NONE; - break; - } - - return err; -} - -static int apm_release(struct inode * inode, struct file * filp) -{ - struct apm_user *as = filp->private_data; - filp->private_data = NULL; - - down_write(&user_list_lock); - list_del(&as->list); - up_write(&user_list_lock); - - /* - * We are now unhooked from the chain. As far as new - * events are concerned, we no longer exist. However, we - * need to balance suspends_pending, which means the - * possibility of sleeping. - */ - if (as->suspend_state != SUSPEND_NONE) { - suspends_pending -= 1; - if (suspends_pending == 0) - apm_suspend(); - } - - kfree(as); - return 0; -} - -static int apm_open(struct inode * inode, struct file * filp) -{ - struct apm_user *as; - - as = kzalloc(sizeof(*as), GFP_KERNEL); - if (as) { - /* - * XXX - this is a tiny bit broken, when we consider BSD - * process accounting. If the device is opened by root, we - * instantly flag that we used superuser privs. Who knows, - * we might close the device immediately without doing a - * privileged operation -- cevans - */ - as->suser = capable(CAP_SYS_ADMIN); - as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE; - as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ; - - down_write(&user_list_lock); - list_add(&as->list, &apm_user_list); - up_write(&user_list_lock); - - filp->private_data = as; - } - - return as ? 0 : -ENOMEM; -} - -static struct file_operations apm_bios_fops = { - .owner = THIS_MODULE, - .read = apm_read, - .poll = apm_poll, - .ioctl = apm_ioctl, - .open = apm_open, - .release = apm_release, -}; - -static struct miscdevice apm_device = { - .minor = APM_MINOR_DEV, - .name = "apm_bios", - .fops = &apm_bios_fops -}; - - -#ifdef CONFIG_PROC_FS -/* - * Arguments, with symbols from linux/apm_bios.h. - * - * 0) Linux driver version (this will change if format changes) - * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. - * 2) APM flags from APM Installation Check (0x00): - * bit 0: APM_16_BIT_SUPPORT - * bit 1: APM_32_BIT_SUPPORT - * bit 2: APM_IDLE_SLOWS_CLOCK - * bit 3: APM_BIOS_DISABLED - * bit 4: APM_BIOS_DISENGAGED - * 3) AC line status - * 0x00: Off-line - * 0x01: On-line - * 0x02: On backup power (BIOS >= 1.1 only) - * 0xff: Unknown - * 4) Battery status - * 0x00: High - * 0x01: Low - * 0x02: Critical - * 0x03: Charging - * 0x04: Selected battery not present (BIOS >= 1.2 only) - * 0xff: Unknown - * 5) Battery flag - * bit 0: High - * bit 1: Low - * bit 2: Critical - * bit 3: Charging - * bit 7: No system battery - * 0xff: Unknown - * 6) Remaining battery life (percentage of charge): - * 0-100: valid - * -1: Unknown - * 7) Remaining battery life (time units): - * Number of remaining minutes or seconds - * -1: Unknown - * 8) min = minutes; sec = seconds - */ -static int apm_get_info(char *buf, char **start, off_t fpos, int length) -{ - struct apm_power_info info; - char *units; - int ret; - - info.ac_line_status = 0xff; - info.battery_status = 0xff; - info.battery_flag = 0xff; - info.battery_life = -1; - info.time = -1; - info.units = -1; - - if (apm_get_power_status) - apm_get_power_status(&info); - - switch (info.units) { - default: units = "?"; break; - case 0: units = "min"; break; - case 1: units = "sec"; break; - } - - ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", - driver_version, APM_32_BIT_SUPPORT, - info.ac_line_status, info.battery_status, - info.battery_flag, info.battery_life, - info.time, units); - - return ret; -} -#endif - -static int kapmd(void *arg) -{ - daemonize("kapmd"); - current->flags |= PF_NOFREEZE; - - do { - apm_event_t event; - - wait_event_interruptible(kapmd_wait, - !queue_empty(&kapmd_queue) || !mips_apm_active); - - if (!mips_apm_active) - break; - - spin_lock_irq(&kapmd_queue_lock); - event = 0; - if (!queue_empty(&kapmd_queue)) - event = queue_get_event(&kapmd_queue); - spin_unlock_irq(&kapmd_queue_lock); - - switch (event) { - case 0: - break; - - case APM_LOW_BATTERY: - case APM_POWER_STATUS_CHANGE: - queue_event(event, NULL); - break; - - case APM_USER_SUSPEND: - case APM_SYS_SUSPEND: - queue_event(event, NULL); - if (suspends_pending == 0) - apm_suspend(); - break; - - case APM_CRITICAL_SUSPEND: - apm_suspend(); - break; - } - } while (1); - - complete_and_exit(&kapmd_exit, 0); -} - -static int __init apm_init(void) -{ - int ret; - - if (apm_disabled) { - printk(KERN_NOTICE "apm: disabled on user request.\n"); - return -ENODEV; - } - - mips_apm_active = 1; - - ret = kernel_thread(kapmd, NULL, CLONE_KERNEL); - if (ret < 0) { - mips_apm_active = 0; - return ret; - } - -#ifdef CONFIG_PROC_FS - create_proc_info_entry("apm", 0, NULL, apm_get_info); -#endif - - ret = misc_register(&apm_device); - if (ret != 0) { - remove_proc_entry("apm", NULL); - - mips_apm_active = 0; - wake_up(&kapmd_wait); - wait_for_completion(&kapmd_exit); - } - - return ret; -} - -static void __exit apm_exit(void) -{ - misc_deregister(&apm_device); - remove_proc_entry("apm", NULL); - - mips_apm_active = 0; - wake_up(&kapmd_wait); - wait_for_completion(&kapmd_exit); -} - -module_init(apm_init); -module_exit(apm_exit); - -MODULE_AUTHOR("Stephen Rothwell"); -MODULE_DESCRIPTION("Advanced Power Management"); -MODULE_LICENSE("GPL"); - -#ifndef MODULE -static int __init apm_setup(char *str) -{ - while ((str != NULL) && (*str != '\0')) { - if (strncmp(str, "off", 3) == 0) - apm_disabled = 1; - if (strncmp(str, "on", 2) == 0) - apm_disabled = 0; - str = strchr(str, ','); - if (str != NULL) - str += strspn(str, ", \t"); - } - return 1; -} - -__setup("apm=", apm_setup); -#endif - -/** - * apm_queue_event - queue an APM event for kapmd - * @event: APM event - * - * Queue an APM event for kapmd to process and ultimately take the - * appropriate action. Only a subset of events are handled: - * %APM_LOW_BATTERY - * %APM_POWER_STATUS_CHANGE - * %APM_USER_SUSPEND - * %APM_SYS_SUSPEND - * %APM_CRITICAL_SUSPEND - */ -void apm_queue_event(apm_event_t event) -{ - unsigned long flags; - - spin_lock_irqsave(&kapmd_queue_lock, flags); - queue_add_event(&kapmd_queue, event); - spin_unlock_irqrestore(&kapmd_queue_lock, flags); - - wake_up_interruptible(&kapmd_wait); -} -EXPORT_SYMBOL(apm_queue_event); diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index ea7df4b8da33..c0b089d47181 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -249,7 +249,6 @@ void output_sc_defines(void) offset("#define SC_MDHI ", struct sigcontext, sc_mdhi); offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); offset("#define SC_PC ", struct sigcontext, sc_pc); - offset("#define SC_STATUS ", struct sigcontext, sc_status); offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); offset("#define SC_HI1 ", struct sigcontext, sc_hi1); diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index f10b6a19f8bf..0b78fcbf044a 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S @@ -21,24 +21,21 @@ #endif #ifndef CONFIG_PREEMPT - .macro preempt_stop - local_irq_disable - .endm #define resume_kernel restore_all +#else +#define __ret_from_irq ret_from_exception #endif .text .align 5 -FEXPORT(ret_from_irq) - LONG_S s0, TI_REGS($28) -#ifdef CONFIG_PREEMPT -FEXPORT(ret_from_exception) -#else - b _ret_from_irq +#ifndef CONFIG_PREEMPT FEXPORT(ret_from_exception) - preempt_stop + local_irq_disable # preempt stop + b __ret_from_irq #endif -FEXPORT(_ret_from_irq) +FEXPORT(ret_from_irq) + LONG_S s0, TI_REGS($28) +FEXPORT(__ret_from_irq) LONG_L t0, PT_STATUS(sp) # returning to kernel mode? andi t0, t0, KU_USER beqz t0, resume_kernel diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 0b8ce59429a8..fc4dd6c9dd80 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -39,6 +39,7 @@ #include <net/sock.h> #include <net/scm.h> +#include <asm/compat-signal.h> #include <asm/ipc.h> #include <asm/sim.h> #include <asm/uaccess.h> @@ -193,50 +194,6 @@ sysn32_waitid(int which, compat_pid_t pid, return ret; } -struct sysinfo32 { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - u16 procs; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[8]; -}; - -asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info) -{ - struct sysinfo s; - int ret, err; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_sysinfo((struct sysinfo __user *)&s); - set_fs (old_fs); - err = put_user (s.uptime, &info->uptime); - err |= __put_user (s.loads[0], &info->loads[0]); - err |= __put_user (s.loads[1], &info->loads[1]); - err |= __put_user (s.loads[2], &info->loads[2]); - err |= __put_user (s.totalram, &info->totalram); - err |= __put_user (s.freeram, &info->freeram); - err |= __put_user (s.sharedram, &info->sharedram); - err |= __put_user (s.bufferram, &info->bufferram); - err |= __put_user (s.totalswap, &info->totalswap); - err |= __put_user (s.freeswap, &info->freeswap); - err |= __put_user (s.procs, &info->procs); - err |= __put_user (s.totalhigh, &info->totalhigh); - err |= __put_user (s.freehigh, &info->freehigh); - err |= __put_user (s.mem_unit, &info->mem_unit); - if (err) - return -EFAULT; - return ret; -} - #define RLIM_INFINITY32 0x7fffffff #define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x) @@ -780,3 +737,49 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs) return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } + +/* + * Implement the event wait interface for the eventpoll file. It is the kernel + * part of the user space epoll_pwait(2). + */ +asmlinkage long compat_sys_epoll_pwait(int epfd, + struct epoll_event __user *events, int maxevents, int timeout, + const compat_sigset_t __user *sigmask, size_t sigsetsize) +{ + int error; + sigset_t ksigmask, sigsaved; + + /* + * If the caller wants a certain signal mask to be set during the wait, + * we apply it here. + */ + if (sigmask) { + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + if (!access_ok(VERIFY_READ, sigmask, sizeof(ksigmask))) + return -EFAULT; + if (__copy_conv_sigset_from_user(&ksigmask, sigmask)) + return -EFAULT; + sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); + } + + error = sys_epoll_wait(epfd, events, maxevents, timeout); + + /* + * If we changed the signal mask, we need to restore the original one. + * In case we've got a signal while waiting, we do not restore the + * signal mask yet, and we allow do_signal() to deliver the signal on + * the way back to userspace, before the signal mask is restored. + */ + if (sigmask) { + if (error == -EINTR) { + memcpy(¤t->saved_sigmask, &sigsaved, + sizeof(sigsaved)); + set_thread_flag(TIF_RESTORE_SIGMASK); + } else + sigprocmask(SIG_SETMASK, &sigsaved, NULL); + } + + return error; +} diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index a32f6797353a..ba01800b6018 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -3,9 +3,11 @@ * Copyright (C) 2005 Mips Technologies, Inc */ +#include <linux/device.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/cpumask.h> +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/security.h> @@ -453,3 +455,20 @@ void mt_cflush_release(void) #endif /* CONFIG_MIPS_MT_SMTC */ /* FILL IN VSMP and AP/SP VERSIONS HERE */ } + +struct class *mt_class; + +static int __init mt_init(void) +{ + struct class *mtc; + + mtc = class_create(THIS_MODULE, "mt"); + if (IS_ERR(mtc)) + return PTR_ERR(mtc); + + mt_class = mtc; + + return 0; +} + +subsys_initcall(mt_init); diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 8610f4a925e9..d92c48e0d7a6 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c @@ -17,6 +17,7 @@ * */ +#include <linux/device.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/fs.h> @@ -34,6 +35,7 @@ #include <linux/sched.h> #include <linux/wait.h> #include <asm/mipsmtregs.h> +#include <asm/mips_mt.h> #include <asm/cacheflush.h> #include <asm/atomic.h> #include <asm/cpu.h> @@ -476,7 +478,7 @@ static ssize_t file_write(struct file *file, const char __user * buffer, return rtlx_write(minor, (void *)buffer, count, 1); } -static struct file_operations rtlx_fops = { +static const struct file_operations rtlx_fops = { .owner = THIS_MODULE, .open = file_open, .release = file_release, @@ -498,7 +500,8 @@ static char register_chrdev_failed[] __initdata = static int rtlx_module_init(void) { - int i; + struct device *dev; + int i, err; major = register_chrdev(0, module_name, &rtlx_fops); if (major < 0) { @@ -511,6 +514,13 @@ static int rtlx_module_init(void) init_waitqueue_head(&channel_wqs[i].rt_queue); init_waitqueue_head(&channel_wqs[i].lx_queue); channel_wqs[i].in_open = 0; + + dev = device_create(mt_class, NULL, MKDEV(major, i), + "%s%d", module_name, i); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_chrdev; + } } /* set up notifiers */ @@ -525,10 +535,21 @@ static int rtlx_module_init(void) setup_irq(rtlx_irq_num, &rtlx_irq); return 0; + +out_chrdev: + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); + + return err; } static void __exit rtlx_module_exit(void) { + int i; + + for (i = 0; i < RTLX_CHANNELS; i++) + device_destroy(mt_class, MKDEV(major, i)); + unregister_chrdev(major, module_name); } diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index e569b846e9a3..10e9a18630aa 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -470,4 +470,4 @@ sys_call_table: PTR sys_get_robust_list PTR sys_kexec_load /* 5270 */ PTR sys_getcpu - PTR sys_epoll_pwait + PTR compat_sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 39add2341aa2..2ceda4644a4d 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -217,7 +217,7 @@ EXPORT(sysn32_call_table) PTR sys32_gettimeofday PTR compat_sys_getrlimit /* 6095 */ PTR compat_sys_getrusage - PTR sys32_sysinfo + PTR compat_sys_sysinfo PTR compat_sys_times PTR sys32_ptrace PTR sys_getuid /* 6100 */ @@ -396,4 +396,4 @@ EXPORT(sysn32_call_table) PTR compat_sys_get_robust_list PTR compat_sys_kexec_load PTR sys_getcpu - PTR sys_epoll_pwait + PTR compat_sys_epoll_pwait diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index c58b8e0105ea..c5f590ca99b0 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -321,7 +321,7 @@ sys_call_table: PTR sys_ni_syscall /* sys_vm86 */ PTR compat_sys_wait4 PTR sys_swapoff /* 4115 */ - PTR sys32_sysinfo + PTR compat_sys_sysinfo PTR sys32_ipc PTR sys_fsync PTR sys32_sigreturn diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index d2e01e7167b8..394540fad769 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -452,7 +452,7 @@ static void __init arch_mem_init(char **cmdline_p) print_memory_map(); strlcpy(command_line, arcs_cmdline, sizeof(command_line)); - strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); *cmdline_p = command_line; diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index b1f09d54ebe6..fdbdbdc65b54 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -8,169 +8,27 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ +#ifndef __SIGNAL_COMMON_H +#define __SIGNAL_COMMON_H -static inline int -setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -{ - int err = 0; +/* #define DEBUG_SIG */ - err |= __put_user(regs->cp0_epc, &sc->sc_pc); +#ifdef DEBUG_SIG +# define DEBUGP(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args) +#else +# define DEBUGP(fmt, args...) +#endif -#define save_gp_reg(i) do { \ - err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); - save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); - save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); - save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); - save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); - save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); - save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); - save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); - save_gp_reg(31); -#undef save_gp_reg - - err |= __put_user(regs->hi, &sc->sc_mdhi); - err |= __put_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __put_user(mfhi1(), &sc->sc_hi1); - err |= __put_user(mflo1(), &sc->sc_lo1); - err |= __put_user(mfhi2(), &sc->sc_hi2); - err |= __put_user(mflo2(), &sc->sc_lo2); - err |= __put_user(mfhi3(), &sc->sc_hi3); - err |= __put_user(mflo3(), &sc->sc_lo3); - err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); - } - - err |= __put_user(!!used_math(), &sc->sc_used_math); - - if (!used_math()) - goto out; - - /* - * Save FPU state to signal context. Signal handler will "inherit" - * current FPU state. - */ - preempt_disable(); - - if (!is_fpu_owner()) { - own_fpu(); - restore_fp(current); - } - err |= save_fp_context(sc); - - preempt_enable(); - -out: - return err; -} - -static inline int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -{ - unsigned int used_math; - unsigned long treg; - int err = 0; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - err |= __get_user(regs->cp0_epc, &sc->sc_pc); - err |= __get_user(regs->hi, &sc->sc_mdhi); - err |= __get_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); - err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); - err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); - err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); - err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); - err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); - err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); - } - -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); - restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); - restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); - restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); - restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); - restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); - restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); - restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); - restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); - restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); - restore_gp_reg(31); -#undef restore_gp_reg - - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - preempt_disable(); - - if (used_math()) { - /* restore fpu context if we have used it before */ - own_fpu(); - err |= restore_fp_context(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(); - } - - preempt_enable(); - - return err; -} +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) /* * Determine which stack to use.. */ -static inline void __user * -get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = regs->regs[29]; - - /* - * FPU emulator may have it's own trampoline active just - * above the user stack, 16-bytes before the next lowest - * 16 byte boundary. Try to avoid trashing it. - */ - sp -= 32; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); -} - -static inline int install_sigtramp(unsigned int __user *tramp, - unsigned int syscall) -{ - int err; - - /* - * Set up the return code ... - * - * li v0, __NR__foo_sigreturn - * syscall - */ - - err = __put_user(0x24020000 + syscall, tramp + 0); - err |= __put_user(0x0000000c , tramp + 1); - if (ICACHE_REFILLS_WORKAROUND_WAR) { - err |= __put_user(0, tramp + 2); - err |= __put_user(0, tramp + 3); - err |= __put_user(0, tramp + 4); - err |= __put_user(0, tramp + 5); - err |= __put_user(0, tramp + 6); - err |= __put_user(0, tramp + 7); - } - flush_cache_sigtramp((unsigned long) tramp); +extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, + size_t frame_size); +/* + * install trampoline code to get back from the sig handler + */ +extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); - return err; -} +#endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9a44053cd9f1..b2e9ab1bb101 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -34,18 +34,192 @@ #include "signal-common.h" -#define DEBUG_SIG 0 +/* + * Horribly complicated - with the bloody RM9000 workarounds enabled + * the signal trampolines is moving to the end of the structure so we can + * increase the alignment without breaking software compatibility. + */ +#if ICACHE_REFILLS_WORKAROUND_WAR == 0 + +struct sigframe { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_code[2]; /* signal trampoline */ + struct sigcontext sf_sc; + sigset_t sf_mask; +}; + +struct rt_sigframe { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_code[2]; /* signal trampoline */ + struct siginfo rs_info; + struct ucontext rs_uc; +}; + +#else + +struct sigframe { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_pad[2]; + struct sigcontext sf_sc; /* hw context */ + sigset_t sf_mask; + u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ +}; + +struct rt_sigframe { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_pad[2]; + struct siginfo rs_info; + struct ucontext rs_uc; + u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ +}; + +#endif + +/* + * Helper routines + */ +int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +{ + int err = 0; + int i; + + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + + err |= __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; i++) + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + } + + err |= __put_user(!!used_math(), &sc->sc_used_math); + + if (used_math()) { + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); + + preempt_enable(); + } + return err; +} + +int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) +{ + unsigned int used_math; + unsigned long treg; + int err = 0; + int i; + + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + + err |= __get_user(regs->cp0_epc, &sc->sc_pc); + err |= __get_user(regs->hi, &sc->sc_mdhi); + err |= __get_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + + for (i = 1; i < 32; i++) + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); + + preempt_disable(); + + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); + + return err; +} + +void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, + size_t frame_size) +{ + unsigned long sp; + + /* Default to using normal stack */ + sp = regs->regs[29]; + + /* + * FPU emulator may have it's own trampoline active just + * above the user stack, 16-bytes before the next lowest + * 16 byte boundary. Try to avoid trashing it. + */ + sp -= 32; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); +} + +int install_sigtramp(unsigned int __user *tramp, unsigned int syscall) +{ + int err; + + /* + * Set up the return code ... + * + * li v0, __NR__foo_sigreturn + * syscall + */ + + err = __put_user(0x24020000 + syscall, tramp + 0); + err |= __put_user(0x0000000c , tramp + 1); + if (ICACHE_REFILLS_WORKAROUND_WAR) { + err |= __put_user(0, tramp + 2); + err |= __put_user(0, tramp + 3); + err |= __put_user(0, tramp + 4); + err |= __put_user(0, tramp + 5); + err |= __put_user(0, tramp + 6); + err |= __put_user(0, tramp + 7); + } + flush_cache_sigtramp((unsigned long) tramp); -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + return err; +} /* * Atomically swap in the new signal mask, and wait for a signal. */ #ifdef CONFIG_TRAD_SIGNALS -save_static_function(sys_sigsuspend); -__attribute_used__ noinline static int -_sys_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs) { sigset_t newset; sigset_t __user *uset; @@ -68,9 +242,7 @@ _sys_sigsuspend(nabi_no_regargs struct pt_regs regs) } #endif -save_static_function(sys_rt_sigsuspend); -__attribute_used__ noinline static int -_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { sigset_t newset; sigset_t __user *unewset; @@ -148,45 +320,8 @@ asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs) return do_sigaltstack(uss, uoss, usp); } -/* - * Horribly complicated - with the bloody RM9000 workarounds enabled - * the signal trampolines is moving to the end of the structure so we can - * increase the alignment without breaking software compatibility. - */ #ifdef CONFIG_TRAD_SIGNALS -struct sigframe { - u32 sf_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_pad[2]; -#else - u32 sf_code[2]; /* signal trampoline */ -#endif - struct sigcontext sf_sc; - sigset_t sf_mask; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif -}; -#endif - -struct rt_sigframe { - u32 rs_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_pad[2]; -#else - u32 rs_code[2]; /* signal trampoline */ -#endif - struct siginfo rs_info; - struct ucontext rs_uc; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif -}; - -#ifdef CONFIG_TRAD_SIGNALS -save_static_function(sys_sigreturn); -__attribute_used__ noinline static void -_sys_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) { struct sigframe __user *frame; sigset_t blocked; @@ -221,9 +356,7 @@ badframe: } #endif /* CONFIG_TRAD_SIGNALS */ -save_static_function(sys_rt_sigreturn); -__attribute_used__ noinline static void -_sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe __user *frame; sigset_t set; @@ -275,7 +408,7 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - install_sigtramp(frame->sf_code, __NR_sigreturn); + err |= install_sigtramp(frame->sf_code, __NR_sigreturn); err |= setup_sigcontext(regs, &frame->sf_sc); err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); @@ -299,11 +432,9 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, regs->regs[31] = (unsigned long) frame->sf_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, - frame, regs->cp0_epc, frame->regs[31]); -#endif + frame, regs->cp0_epc, regs->regs[31]); return 0; give_sigsegv: @@ -322,7 +453,7 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - install_sigtramp(frame->rs_code, __NR_rt_sigreturn); + err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn); /* Create siginfo. */ err |= copy_siginfo_to_user(&frame->rs_info, info); @@ -359,11 +490,10 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, regs->regs[31] = (unsigned long) frame->rs_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); -#endif + return 0; give_sigsegv: @@ -371,7 +501,7 @@ give_sigsegv: return -EFAULT; } -static inline int handle_signal(unsigned long sig, siginfo_t *info, +static int handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) { int ret; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index c86a5ddff050..c28cb21514c8 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -8,6 +8,7 @@ * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ #include <linux/cache.h> +#include <linux/compat.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> @@ -24,6 +25,7 @@ #include <asm/abi.h> #include <asm/asm.h> +#include <asm/compat-signal.h> #include <linux/bitops.h> #include <asm/cacheflush.h> #include <asm/sim.h> @@ -33,6 +35,8 @@ #include <asm/fpu.h> #include <asm/war.h> +#include "signal-common.h" + #define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) typedef struct compat_siginfo { @@ -102,10 +106,6 @@ typedef struct compat_siginfo { #define __NR_O32_rt_sigreturn 4193 #define __NR_O32_restart_syscall 4253 -#define DEBUG_SIG 0 - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - /* 32-bit compatibility types */ #define _NSIG_BPW32 32 @@ -139,6 +139,143 @@ struct ucontext32 { sigset_t32 uc_sigmask; /* mask last for extensibility */ }; +/* + * Horribly complicated - with the bloody RM9000 workarounds enabled + * the signal trampolines is moving to the end of the structure so we can + * increase the alignment without breaking software compatibility. + */ +#if ICACHE_REFILLS_WORKAROUND_WAR == 0 + +struct sigframe32 { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_code[2]; /* signal trampoline */ + struct sigcontext32 sf_sc; + sigset_t sf_mask; +}; + +struct rt_sigframe32 { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_code[2]; /* signal trampoline */ + compat_siginfo_t rs_info; + struct ucontext32 rs_uc; +}; + +#else /* ICACHE_REFILLS_WORKAROUND_WAR */ + +struct sigframe32 { + u32 sf_ass[4]; /* argument save space for o32 */ + u32 sf_pad[2]; + struct sigcontext32 sf_sc; /* hw context */ + sigset_t sf_mask; + u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ +}; + +struct rt_sigframe32 { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_pad[2]; + compat_siginfo_t rs_info; + struct ucontext32 rs_uc; + u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ +}; + +#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ + +/* + * sigcontext handlers + */ +static int setup_sigcontext32(struct pt_regs *regs, + struct sigcontext32 __user *sc) +{ + int err = 0; + int i; + + err |= __put_user(regs->cp0_epc, &sc->sc_pc); + + err |= __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; i++) + err |= __put_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __put_user(regs->hi, &sc->sc_mdhi); + err |= __put_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); + err |= __put_user(mfhi1(), &sc->sc_hi1); + err |= __put_user(mflo1(), &sc->sc_lo1); + err |= __put_user(mfhi2(), &sc->sc_hi2); + err |= __put_user(mflo2(), &sc->sc_lo2); + err |= __put_user(mfhi3(), &sc->sc_hi3); + err |= __put_user(mflo3(), &sc->sc_lo3); + } + + err |= __put_user(!!used_math(), &sc->sc_used_math); + + if (used_math()) { + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + preempt_disable(); + + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context32(sc); + + preempt_enable(); + } + return err; +} + +static int restore_sigcontext32(struct pt_regs *regs, + struct sigcontext32 __user *sc) +{ + u32 used_math; + int err = 0; + s32 treg; + int i; + + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + + err |= __get_user(regs->cp0_epc, &sc->sc_pc); + err |= __get_user(regs->hi, &sc->sc_mdhi); + err |= __get_user(regs->lo, &sc->sc_mdlo); + if (cpu_has_dsp) { + err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); + err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); + err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); + err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); + err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); + err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); + err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); + } + + for (i = 1; i < 32; i++) + err |= __get_user(regs->regs[i], &sc->sc_regs[i]); + + err |= __get_user(used_math, &sc->sc_used_math); + conditional_used_math(used_math); + + preempt_disable(); + + if (used_math()) { + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context32(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + lose_fpu(); + } + + preempt_enable(); + + return err; +} + +/* + * + */ extern void __put_sigset_unknown_nsig(void); extern void __get_sigset_unknown_nsig(void); @@ -191,9 +328,7 @@ static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) * Atomically swap in the new signal mask, and wait for a signal. */ -save_static_function(sys32_sigsuspend); -__attribute_used__ noinline static int -_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) { compat_sigset_t __user *uset; sigset_t newset; @@ -215,9 +350,7 @@ _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) return -ERESTARTNOHAND; } -save_static_function(sys32_rt_sigsuspend); -__attribute_used__ noinline static int -_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { compat_sigset_t __user *uset; sigset_t newset; @@ -326,91 +459,6 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) return ret; } -static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) -{ - u32 used_math; - int err = 0; - s32 treg; - - /* Always make any pending restarted system calls return -EINTR */ - current_thread_info()->restart_block.fn = do_no_restart_syscall; - - err |= __get_user(regs->cp0_epc, &sc->sc_pc); - err |= __get_user(regs->hi, &sc->sc_mdhi); - err |= __get_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); - err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); - err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); - err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); - err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); - err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); - err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); - } - -#define restore_gp_reg(i) do { \ - err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3); - restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6); - restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9); - restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12); - restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15); - restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18); - restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21); - restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24); - restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27); - restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30); - restore_gp_reg(31); -#undef restore_gp_reg - - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - preempt_disable(); - - if (used_math()) { - /* restore fpu context if we have used it before */ - own_fpu(); - err |= restore_fp_context32(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(); - } - - preempt_enable(); - - return err; -} - -struct sigframe { - u32 sf_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_pad[2]; -#else - u32 sf_code[2]; /* signal trampoline */ -#endif - struct sigcontext32 sf_sc; - sigset_t sf_mask; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif -}; - -struct rt_sigframe32 { - u32 rs_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_pad[2]; -#else - u32 rs_code[2]; /* signal trampoline */ -#endif - compat_siginfo_t rs_info; - struct ucontext32 rs_uc; -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */ -#endif -}; - int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) { int err; @@ -463,17 +511,15 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) return err; } -save_static_function(sys32_sigreturn); -__attribute_used__ noinline static void -_sys32_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) { - struct sigframe __user *frame; + struct sigframe32 __user *frame; sigset_t blocked; - frame = (struct sigframe __user *) regs.regs[29]; + frame = (struct sigframe32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; - if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked))) + if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) goto badframe; sigdelsetmask(&blocked, ~_BLOCKABLE); @@ -499,9 +545,7 @@ badframe: force_sig(SIGSEGV, current); } -save_static_function(sys32_rt_sigreturn); -__attribute_used__ noinline static void -_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe32 __user *frame; mm_segment_t old_fs; @@ -512,7 +556,7 @@ _sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) frame = (struct rt_sigframe32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; - if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) + if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); @@ -554,111 +598,21 @@ badframe: force_sig(SIGSEGV, current); } -static inline int setup_sigcontext32(struct pt_regs *regs, - struct sigcontext32 __user *sc) -{ - int err = 0; - - err |= __put_user(regs->cp0_epc, &sc->sc_pc); - err |= __put_user(regs->cp0_status, &sc->sc_status); - -#define save_gp_reg(i) { \ - err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \ -} while(0) - __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2); - save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6); - save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10); - save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14); - save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18); - save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22); - save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26); - save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30); - save_gp_reg(31); -#undef save_gp_reg - - err |= __put_user(regs->hi, &sc->sc_mdhi); - err |= __put_user(regs->lo, &sc->sc_mdlo); - if (cpu_has_dsp) { - err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); - err |= __put_user(mfhi1(), &sc->sc_hi1); - err |= __put_user(mflo1(), &sc->sc_lo1); - err |= __put_user(mfhi2(), &sc->sc_hi2); - err |= __put_user(mflo2(), &sc->sc_lo2); - err |= __put_user(mfhi3(), &sc->sc_hi3); - err |= __put_user(mflo3(), &sc->sc_lo3); - } - - err |= __put_user(!!used_math(), &sc->sc_used_math); - - if (!used_math()) - goto out; - - /* - * Save FPU state to signal context. Signal handler will "inherit" - * current FPU state. - */ - preempt_disable(); - - if (!is_fpu_owner()) { - own_fpu(); - restore_fp(current); - } - err |= save_fp_context32(sc); - - preempt_enable(); - -out: - return err; -} - -/* - * Determine which stack to use.. - */ -static inline void __user *get_sigframe(struct k_sigaction *ka, - struct pt_regs *regs, - size_t frame_size) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = regs->regs[29]; - - /* - * FPU emulator may have it's own trampoline active just - * above the user stack, 16-bytes before the next lowest - * 16 byte boundary. Try to avoid trashing it. - */ - sp -= 32; - - /* This is the X/Open sanctioned signal stack switching. */ - if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void __user *)((sp - frame_size) & ALMASK); -} - int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set) { - struct sigframe __user *frame; + struct sigframe32 __user *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - /* - * Set up the return code ... - * - * li v0, __NR_O32_sigreturn - * syscall - */ - err |= __put_user(0x24020000 + __NR_O32_sigreturn, frame->sf_code + 0); - err |= __put_user(0x0000000c , frame->sf_code + 1); - flush_cache_sigtramp((unsigned long) frame->sf_code); + err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn); err |= setup_sigcontext32(regs, &frame->sf_sc); - err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); + err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); + if (err) goto give_sigsegv; @@ -679,11 +633,10 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, regs->regs[31] = (unsigned long) frame->sf_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, - frame, regs->cp0_epc, frame->sf_code); -#endif + frame, regs->cp0_epc, regs->regs[31]); + return 0; give_sigsegv: @@ -702,17 +655,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; - /* Set up to return from userspace. If provided, use a stub already - in userspace. */ - /* - * Set up the return code ... - * - * li v0, __NR_O32_rt_sigreturn - * syscall - */ - err |= __put_user(0x24020000 + __NR_O32_rt_sigreturn, frame->rs_code + 0); - err |= __put_user(0x0000000c , frame->rs_code + 1); - flush_cache_sigtramp((unsigned long) frame->rs_code); + err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn); /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ err |= copy_siginfo_to_user32(&frame->rs_info, info); @@ -728,7 +671,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, err |= __put_user(current->sas_ss_size, &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); - err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); + err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); if (err) goto give_sigsegv; @@ -750,11 +693,10 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs, regs->regs[31] = (unsigned long) frame->rs_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, - frame, regs->cp0_epc, frame->rs_code); -#endif + frame, regs->cp0_epc, regs->regs[31]); + return 0; give_sigsegv: diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index b28646b3ceae..7ca2a078841f 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -31,6 +31,7 @@ #include <asm/asm.h> #include <asm/cacheflush.h> +#include <asm/compat-signal.h> #include <asm/sim.h> #include <asm/uaccess.h> #include <asm/ucontext.h> @@ -47,9 +48,9 @@ #define __NR_N32_rt_sigreturn 6211 #define __NR_N32_restart_syscall 6214 -#define DEBUG_SIG 0 +extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); +extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) /* IRIX compatible stack_t */ typedef struct sigaltstack32 { @@ -63,28 +64,33 @@ struct ucontextn32 { s32 uc_link; stack32_t uc_stack; struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ + compat_sigset_t uc_sigmask; /* mask last for extensibility */ }; +#if ICACHE_REFILLS_WORKAROUND_WAR == 0 + struct rt_sigframe_n32 { u32 rs_ass[4]; /* argument save space for o32 */ -#if ICACHE_REFILLS_WORKAROUND_WAR - u32 rs_pad[2]; -#else u32 rs_code[2]; /* signal trampoline */ -#endif struct siginfo rs_info; struct ucontextn32 rs_uc; -#if ICACHE_REFILLS_WORKAROUND_WAR +}; + +#else /* ICACHE_REFILLS_WORKAROUND_WAR */ + +struct rt_sigframe_n32 { + u32 rs_ass[4]; /* argument save space for o32 */ + u32 rs_pad[2]; + struct siginfo rs_info; + struct ucontextn32 rs_uc; u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ -#endif }; +#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */ + extern void sigset_from_compat (sigset_t *set, compat_sigset_t *compat); -save_static_function(sysn32_rt_sigsuspend); -__attribute_used__ noinline static int -_sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) +asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) { compat_sigset_t __user *unewset; compat_sigset_t uset; @@ -114,9 +120,7 @@ _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) return -ERESTARTNOHAND; } -save_static_function(sysn32_rt_sigreturn); -__attribute_used__ noinline static void -_sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) +asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) { struct rt_sigframe_n32 __user *frame; sigset_t set; @@ -126,7 +130,7 @@ _sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) frame = (struct rt_sigframe_n32 __user *) regs.regs[29]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; - if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set))) + if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); @@ -192,7 +196,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka, err |= __put_user(current->sas_ss_size, &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); - err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); + err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); if (err) goto give_sigsegv; @@ -214,11 +218,10 @@ int setup_rt_frame_n32(struct k_sigaction * ka, regs->regs[31] = (unsigned long) frame->rs_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; -#if DEBUG_SIG - printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", + DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]); -#endif + return 0; give_sigsegv: diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index 8aa544f73a5e..e5e56bd498db 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -307,7 +307,7 @@ static unsigned int __init calibrate_hpt(void) struct clocksource clocksource_mips = { .name = "MIPS", .mask = 0xffffffff, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static void __init init_mips_clocksource(void) @@ -455,8 +455,3 @@ EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL(to_tm); EXPORT_SYMBOL(rtc_mips_set_time); EXPORT_SYMBOL(rtc_mips_get_time); - -unsigned long long sched_clock(void) -{ - return (unsigned long long)jiffies*(1000000000/HZ); -} diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index cecff24cc972..c76b793310c2 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S @@ -113,10 +113,12 @@ SECTIONS references from .rodata */ .exit.text : { *(.exit.text) } .exit.data : { *(.exit.data) } +#if defined(CONFIG_BLK_DEV_INITRD) . = ALIGN(_PAGE_SIZE); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; +#endif . = ALIGN(32); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 459624969c99..9aca871a307f 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -29,6 +29,7 @@ */ #include <linux/kernel.h> +#include <linux/device.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> @@ -48,6 +49,7 @@ #include <asm/cacheflush.h> #include <asm/atomic.h> #include <asm/cpu.h> +#include <asm/mips_mt.h> #include <asm/processor.h> #include <asm/system.h> #include <asm/vpe.h> @@ -64,6 +66,7 @@ typedef void *vpe_handle; static char module_name[] = "vpe"; static int major; +static const int minor = 1; /* fixed for now */ #ifdef CONFIG_MIPS_APSP_KSPD static struct kspd_notifications kspd_events; @@ -1205,7 +1208,7 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer, return ret; } -static struct file_operations vpe_fops = { +static const struct file_operations vpe_fops = { .owner = THIS_MODULE, .open = vpe_open, .release = vpe_release, @@ -1365,12 +1368,15 @@ static void kspd_sp_exit( int sp_id) } #endif +static struct device *vpe_dev; + static int __init vpe_module_init(void) { struct vpe *v = NULL; + struct device *dev; struct tc *t; unsigned long val; - int i; + int i, err; if (!cpu_has_mipsmt) { printk("VPE loader: not a MIPS MT capable processor\n"); @@ -1383,6 +1389,14 @@ static int __init vpe_module_init(void) return major; } + dev = device_create(mt_class, NULL, MKDEV(major, minor), + "tc%d", minor); + if (IS_ERR(dev)) { + err = PTR_ERR(dev); + goto out_chrdev; + } + vpe_dev = dev; + dmt(); dvpe(); @@ -1478,6 +1492,11 @@ static int __init vpe_module_init(void) kspd_events.kspd_sp_exit = kspd_sp_exit; #endif return 0; + +out_chrdev: + unregister_chrdev(major, module_name); + + return err; } static void __exit vpe_module_exit(void) @@ -1490,6 +1509,7 @@ static void __exit vpe_module_exit(void) } } + device_destroy(mt_class, MKDEV(major, minor)); unregister_chrdev(major, module_name); } diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c index 12878359f2c8..699ab1886ceb 100644 --- a/arch/mips/lasat/sysctl.c +++ b/arch/mips/lasat/sysctl.c @@ -302,42 +302,129 @@ extern int lasat_boot_to_service; #ifdef CONFIG_SYSCTL static ctl_table lasat_table[] = { - {LASAT_CPU_HZ, "cpu-hz", &lasat_board_info.li_cpu_hz, sizeof(int), - 0444, NULL, &proc_dointvec, &sysctl_intvec}, - {LASAT_BUS_HZ, "bus-hz", &lasat_board_info.li_bus_hz, sizeof(int), - 0444, NULL, &proc_dointvec, &sysctl_intvec}, - {LASAT_MODEL, "bmid", &lasat_board_info.li_bmid, sizeof(int), - 0444, NULL, &proc_dointvec, &sysctl_intvec}, - {LASAT_PRID, "prid", &lasat_board_info.li_prid, sizeof(int), - 0644, NULL, &proc_lasat_eeprom_value, &sysctl_lasat_eeprom_value}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "cpu-hz", + .data = &lasat_board_info.li_cpu_hz, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bus-hz", + .data = &lasat_board_info.li_bus_hz, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bmid", + .data = &lasat_board_info.li_bmid, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "prid", + .data = &lasat_board_info.li_prid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_eeprom_value, + .strategy = &sysctl_lasat_eeprom_value + }, #ifdef CONFIG_INET - {LASAT_IPADDR, "ipaddr", &lasat_board_info.li_eeprom_info.ipaddr, sizeof(int), - 0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec}, - {LASAT_NETMASK, "netmask", &lasat_board_info.li_eeprom_info.netmask, sizeof(int), - 0644, NULL, &proc_lasat_ip, &sysctl_lasat_intvec}, - {LASAT_BCAST, "bcastaddr", &lasat_bcastaddr, - sizeof(lasat_bcastaddr), 0600, NULL, - &proc_dostring, &sysctl_string}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "ipaddr", + .data = &lasat_board_info.li_eeprom_info.ipaddr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_ip, + .strategy = &sysctl_lasat_intvec + }, + { + .ctl_name = LASAT_NETMASK, + .procname = "netmask", + .data = &lasat_board_info.li_eeprom_info.netmask, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_lasat_ip, + .strategy = &sysctl_lasat_intvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "bcastaddr", + .data = &lasat_bcastaddr, + .maxlen = sizeof(lasat_bcastaddr), + .mode = 0600, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, #endif - {LASAT_PASSWORD, "passwd_hash", &lasat_board_info.li_eeprom_info.passwd_hash, sizeof(lasat_board_info.li_eeprom_info.passwd_hash), - 0600, NULL, &proc_dolasatstring, &sysctl_lasatstring}, - {LASAT_SBOOT, "boot-service", &lasat_boot_to_service, sizeof(int), - 0644, NULL, &proc_dointvec, &sysctl_intvec}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "passwd_hash", + .data = &lasat_board_info.li_eeprom_info.passwd_hash, + .maxlen = sizeof(lasat_board_info.li_eeprom_info.passwd_hash), + .mode = 0600, + .proc_handler = &proc_dolasatstring, + .strategy = &sysctl_lasatstring + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "boot-service", + .data = &lasat_boot_to_service, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + .strategy = &sysctl_intvec + }, #ifdef CONFIG_DS1603 - {LASAT_RTC, "rtc", &rtctmp, sizeof(int), - 0644, NULL, &proc_dolasatrtc, &sysctl_lasat_rtc}, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "rtc", + .data = &rtctmp, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dolasatrtc, + .strategy = &sysctl_lasat_rtc + }, #endif - {LASAT_NAMESTR, "namestr", &lasat_board_info.li_namestr, sizeof(lasat_board_info.li_namestr), - 0444, NULL, &proc_dostring, &sysctl_string}, - {LASAT_TYPESTR, "typestr", &lasat_board_info.li_typestr, sizeof(lasat_board_info.li_typestr), - 0444, NULL, &proc_dostring, &sysctl_string}, - {0} + { + .ctl_name = CTL_UNNUMBERED, + .procname = "namestr", + .data = &lasat_board_info.li_namestr, + .maxlen = sizeof(lasat_board_info.li_namestr), + .mode = 0444, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "typestr", + .data = &lasat_board_info.li_typestr, + .maxlen = sizeof(lasat_board_info.li_typestr), + .mode = 0444, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string + }, + {} }; -#define CTL_LASAT 1 // CTL_ANY ??? static ctl_table lasat_root_table[] = { - { CTL_LASAT, "lasat", NULL, 0, 0555, lasat_table }, - { 0 } + { + .ctl_name = CTL_UNNUMBERED, + .procname = "lasat", + .mode = 0555, + .child = lasat_table + }, + {} }; static int __init lasat_register_sysctl(void) @@ -345,7 +432,7 @@ static int __init lasat_register_sysctl(void) struct ctl_table_header *lasat_table_header; lasat_table_header = - register_sysctl_table(lasat_root_table, 0); + register_sysctl_table(lasat_root_table); return 0; } diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index 19e41fd186c4..de5727385bc6 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -2,8 +2,8 @@ # Makefile for the Linux/MIPS-specific parts of the memory manager. # -obj-y += cache.o extable.o fault.o init.o pgtable.o \ - tlbex.o tlbex-fault.o +obj-y += cache.o dma-default.o extable.o fault.o \ + init.o pgtable.o tlbex.o tlbex-fault.o obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o obj-$(CONFIG_64BIT) += pgtable-64.o @@ -32,14 +32,4 @@ obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o -# -# Choose one DMA coherency model -# -ifndef CONFIG_OWN_DMA -obj-$(CONFIG_DMA_COHERENT) += dma-coherent.o -obj-$(CONFIG_DMA_NONCOHERENT) += dma-noncoherent.o -endif -obj-$(CONFIG_DMA_IP27) += dma-ip27.o -obj-$(CONFIG_DMA_IP32) += dma-ip32.o - EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c index 3a8afd47feaa..9ea460b16bda 100644 --- a/arch/mips/mm/c-sb1.c +++ b/arch/mips/mm/c-sb1.c @@ -259,6 +259,12 @@ static void sb1_flush_cache_data_page(unsigned long addr) on_each_cpu(sb1_flush_cache_data_page_ipi, (void *) addr, 1, 1); } #else + +static void local_sb1_flush_cache_data_page(unsigned long addr) +{ + __sb1_writeback_inv_dcache_range(addr, addr + PAGE_SIZE); +} + void sb1_flush_cache_data_page(unsigned long) __attribute__((alias("local_sb1_flush_cache_data_page"))); #endif diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 1f954a238a63..31819c58bffa 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -107,8 +107,6 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address, } } -#define __weak __attribute__((weak)) - static char cache_panic[] __initdata = "Yeee, unsupported cache architecture."; void __init cpu_cache_init(void) diff --git a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c deleted file mode 100644 index 5697c6e250a3..000000000000 --- a/arch/mips/mm/dma-coherent.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include <linux/types.h> -#include <linux/dma-mapping.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/string.h> - -#include <asm/cache.h> -#include <asm/io.h> - -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (dev->coherent_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_phys(ret); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_noncoherent); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) - __attribute__((alias("dma_alloc_noncoherent"))); - -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long addr = (unsigned long) vaddr; - - free_pages(addr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_noncoherent); - -void dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent"))); - -EXPORT_SYMBOL(dma_free_coherent); - -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return __pa(ptr); -} - -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_single); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - sg->dma_address = (dma_addr_t)page_to_phys(sg->page) + sg->offset; - } - - return nents; -} - -EXPORT_SYMBOL(dma_map_sg); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return page_to_phys(page) + offset; -} - -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_page); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_sg); - -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_cpu); - -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_device); - -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_cpu); - -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(dma_addr_t dma_addr) -{ - return 0; -} - -EXPORT_SYMBOL(dma_mapping_error); - -int dma_supported(struct device *dev, u64 mask) -{ - /* - * we fall back to GFP_DMA when the mask isn't all 1s, - * so we can't guarantee allocations that must be - * within a tighter range than GFP_DMA.. - */ - if (mask < 0x00ffffff) - return 0; - - return 1; -} - -EXPORT_SYMBOL(dma_supported); - -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - -EXPORT_SYMBOL(dma_is_consistent); - -void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_cache_sync); - -/* The DAC routines are a PCIism.. */ - -#ifdef CONFIG_PCI - -#include <linux/pci.h> - -dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, - struct page *page, unsigned long offset, int direction) -{ - return (dma64_addr_t)page_to_phys(page) + offset; -} - -EXPORT_SYMBOL(pci_dac_page_to_dma); - -struct page *pci_dac_dma_to_page(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return mem_map + (dma_addr >> PAGE_SHIFT); -} - -EXPORT_SYMBOL(pci_dac_dma_to_page); - -unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return dma_addr & ~PAGE_MASK; -} - -EXPORT_SYMBOL(pci_dac_dma_to_offset); - -void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); - -void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); - -#endif /* CONFIG_PCI */ diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-default.c index 8cecef0957c3..4a32e939698f 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-default.c @@ -4,28 +4,39 @@ * for more details. * * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> + * Copyright (C) 2000, 2001, 06 Ralf Baechle <ralf@linux-mips.org> * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. */ + #include <linux/types.h> +#include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/string.h> -#include <linux/dma-mapping.h> #include <asm/cache.h> #include <asm/io.h> +#include <dma-coherence.h> + /* * Warning on the terminology - Linux calls an uncached area coherent; * MIPS terminology calls memory areas with hardware maintained coherency * coherent. */ +static inline int cpu_is_noncoherent_r10000(struct device *dev) +{ + return !plat_device_is_coherent(dev) && + (current_cpu_data.cputype == CPU_R10000 && + current_cpu_data.cputype == CPU_R12000); +} + void *dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t * dma_handle, gfp_t gfp) { void *ret; + /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); @@ -35,7 +46,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, if (ret != NULL) { memset(ret, 0, size); - *dma_handle = virt_to_phys(ret); + *dma_handle = plat_map_dma_mem(dev, ret, size); } return ret; @@ -48,10 +59,21 @@ void *dma_alloc_coherent(struct device *dev, size_t size, { void *ret; - ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp); + /* ignore region specifiers */ + gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); + + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) + gfp |= GFP_DMA; + ret = (void *) __get_free_pages(gfp, get_order(size)); + if (ret) { - dma_cache_wback_inv((unsigned long) ret, size); - ret = UNCAC_ADDR(ret); + memset(ret, 0, size); + *dma_handle = plat_map_dma_mem(dev, ret, size); + + if (!plat_device_is_coherent(dev)) { + dma_cache_wback_inv((unsigned long) ret, size); + ret = UNCAC_ADDR(ret); + } } return ret; @@ -72,7 +94,9 @@ void dma_free_coherent(struct device *dev, size_t size, void *vaddr, { unsigned long addr = (unsigned long) vaddr; - addr = CAC_ADDR(addr); + if (!plat_device_is_coherent(dev)) + addr = CAC_ADDR(addr); + free_pages(addr, get_order(size)); } @@ -104,9 +128,10 @@ dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, { unsigned long addr = (unsigned long) ptr; - __dma_sync(addr, size, direction); + if (!plat_device_is_coherent(dev)) + __dma_sync(addr, size, direction); - return virt_to_phys(ptr); + return plat_map_dma_mem(dev, ptr, size); } EXPORT_SYMBOL(dma_map_single); @@ -114,10 +139,11 @@ EXPORT_SYMBOL(dma_map_single); void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, enum dma_data_direction direction) { - unsigned long addr; - addr = dma_addr + PAGE_OFFSET; + if (cpu_is_noncoherent_r10000(dev)) + __dma_sync(plat_dma_addr_to_phys(dma_addr) + PAGE_OFFSET, size, + direction); - //__dma_sync(addr, size, direction); + plat_unmap_dma_mem(dma_addr); } EXPORT_SYMBOL(dma_unmap_single); @@ -133,11 +159,10 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, unsigned long addr; addr = (unsigned long) page_address(sg->page); - if (addr) { + if (!plat_device_is_coherent(dev) && addr) __dma_sync(addr + sg->offset, sg->length, direction); - sg->dma_address = (dma_addr_t)page_to_phys(sg->page) - + sg->offset; - } + sg->dma_address = plat_map_dma_mem_page(dev, sg->page) + + sg->offset; } return nents; @@ -148,14 +173,16 @@ EXPORT_SYMBOL(dma_map_sg); dma_addr_t dma_map_page(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction) { - unsigned long addr; - BUG_ON(direction == DMA_NONE); - addr = (unsigned long) page_address(page) + offset; - dma_cache_wback_inv(addr, size); + if (!plat_device_is_coherent(dev)) { + unsigned long addr; + + addr = (unsigned long) page_address(page) + offset; + dma_cache_wback_inv(addr, size); + } - return page_to_phys(page) + offset; + return plat_map_dma_mem_page(dev, page) + offset; } EXPORT_SYMBOL(dma_map_page); @@ -165,12 +192,14 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, { BUG_ON(direction == DMA_NONE); - if (direction != DMA_TO_DEVICE) { + if (!plat_device_is_coherent(dev) && direction != DMA_TO_DEVICE) { unsigned long addr; - addr = dma_address + PAGE_OFFSET; + addr = plat_dma_addr_to_phys(dma_address); dma_cache_wback_inv(addr, size); } + + plat_unmap_dma_mem(dma_address); } EXPORT_SYMBOL(dma_unmap_page); @@ -183,13 +212,15 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, BUG_ON(direction == DMA_NONE); - if (direction == DMA_TO_DEVICE) - return; - for (i = 0; i < nhwentries; i++, sg++) { - addr = (unsigned long) page_address(sg->page); - if (addr) - __dma_sync(addr + sg->offset, sg->length, direction); + if (!plat_device_is_coherent(dev) && + direction != DMA_TO_DEVICE) { + addr = (unsigned long) page_address(sg->page); + if (addr) + __dma_sync(addr + sg->offset, sg->length, + direction); + } + plat_unmap_dma_mem(sg->dma_address); } } @@ -198,12 +229,14 @@ EXPORT_SYMBOL(dma_unmap_sg); void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - unsigned long addr; - BUG_ON(direction == DMA_NONE); - addr = dma_handle + PAGE_OFFSET; - __dma_sync(addr, size, direction); + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr, size, direction); + } } EXPORT_SYMBOL(dma_sync_single_for_cpu); @@ -211,12 +244,14 @@ EXPORT_SYMBOL(dma_sync_single_for_cpu); void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - unsigned long addr; - BUG_ON(direction == DMA_NONE); - addr = dma_handle + PAGE_OFFSET; - __dma_sync(addr, size, direction); + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr, size, direction); + } } EXPORT_SYMBOL(dma_sync_single_for_device); @@ -224,12 +259,14 @@ EXPORT_SYMBOL(dma_sync_single_for_device); void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) { - unsigned long addr; - BUG_ON(direction == DMA_NONE); - addr = dma_handle + offset + PAGE_OFFSET; - __dma_sync(addr, size, direction); + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr + offset, size, direction); + } } EXPORT_SYMBOL(dma_sync_single_range_for_cpu); @@ -237,12 +274,14 @@ EXPORT_SYMBOL(dma_sync_single_range_for_cpu); void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) { - unsigned long addr; - BUG_ON(direction == DMA_NONE); - addr = dma_handle + offset + PAGE_OFFSET; - __dma_sync(addr, size, direction); + if (cpu_is_noncoherent_r10000(dev)) { + unsigned long addr; + + addr = PAGE_OFFSET + plat_dma_addr_to_phys(dma_handle); + __dma_sync(addr + offset, size, direction); + } } EXPORT_SYMBOL(dma_sync_single_range_for_device); @@ -255,9 +294,12 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, BUG_ON(direction == DMA_NONE); /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); + for (i = 0; i < nelems; i++, sg++) { + if (!plat_device_is_coherent(dev)) + __dma_sync((unsigned long)page_address(sg->page), + sg->length, direction); + plat_unmap_dma_mem(sg->dma_address); + } } EXPORT_SYMBOL(dma_sync_sg_for_cpu); @@ -270,9 +312,12 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nele BUG_ON(direction == DMA_NONE); /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); + for (i = 0; i < nelems; i++, sg++) { + if (!plat_device_is_coherent(dev)) + __dma_sync((unsigned long)page_address(sg->page), + sg->length, direction); + plat_unmap_dma_mem(sg->dma_address); + } } EXPORT_SYMBOL(dma_sync_sg_for_device); @@ -301,70 +346,18 @@ EXPORT_SYMBOL(dma_supported); int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) { - return 1; + return plat_device_is_coherent(dev); } EXPORT_SYMBOL(dma_is_consistent); void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) + enum dma_data_direction direction) { - if (direction == DMA_NONE) - return; + BUG_ON(direction == DMA_NONE); - dma_cache_wback_inv((unsigned long)vaddr, size); + if (!plat_device_is_coherent(dev)) + dma_cache_wback_inv((unsigned long)vaddr, size); } EXPORT_SYMBOL(dma_cache_sync); - -/* The DAC routines are a PCIism.. */ - -#ifdef CONFIG_PCI - -#include <linux/pci.h> - -dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, - struct page *page, unsigned long offset, int direction) -{ - return (dma64_addr_t)page_to_phys(page) + offset; -} - -EXPORT_SYMBOL(pci_dac_page_to_dma); - -struct page *pci_dac_dma_to_page(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return mem_map + (dma_addr >> PAGE_SHIFT); -} - -EXPORT_SYMBOL(pci_dac_dma_to_page); - -unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return dma_addr & ~PAGE_MASK; -} - -EXPORT_SYMBOL(pci_dac_dma_to_offset); - -void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); - - dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); - -void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); - - dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); - -#endif /* CONFIG_PCI */ diff --git a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c deleted file mode 100644 index f088344db465..000000000000 --- a/arch/mips/mm/dma-ip27.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - */ -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/pci.h> - -#include <asm/cache.h> -#include <asm/pci/bridge.h> - -#define pdev_to_baddr(pdev, addr) \ - (BRIDGE_CONTROLLER(pdev->bus)->baddr + (addr)) -#define dev_to_baddr(dev, addr) \ - pdev_to_baddr(to_pci_dev(dev), (addr)) - -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = dev_to_baddr(dev, virt_to_phys(ret)); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_noncoherent); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) - __attribute__((alias("dma_alloc_noncoherent"))); - -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long addr = (unsigned long) vaddr; - - free_pages(addr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_noncoherent); - -void dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) __attribute__((alias("dma_free_noncoherent"))); - -EXPORT_SYMBOL(dma_free_coherent); - -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return dev_to_baddr(dev, __pa(ptr)); -} - -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_single); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - sg->dma_address = (dma_addr_t) dev_to_baddr(dev, - page_to_phys(sg->page) + sg->offset); - } - - return nents; -} - -EXPORT_SYMBOL(dma_map_sg); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - return dev_to_baddr(dev, page_to_phys(page) + offset); -} - -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_page); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_unmap_sg); - -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_cpu); - -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_for_device); - -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_cpu); - -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(dma_addr_t dma_addr) -{ - return 0; -} - -EXPORT_SYMBOL(dma_mapping_error); - -int dma_supported(struct device *dev, u64 mask) -{ - /* - * we fall back to GFP_DMA when the mask isn't all 1s, - * so we can't guarantee allocations that must be - * within a tighter range than GFP_DMA.. - */ - if (mask < 0x00ffffff) - return 0; - - return 1; -} - -EXPORT_SYMBOL(dma_supported); - -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - -EXPORT_SYMBOL(dma_is_consistent); - -void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); -} - -EXPORT_SYMBOL(dma_cache_sync); - -dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, - struct page *page, unsigned long offset, int direction) -{ - dma64_addr_t addr = page_to_phys(page) + offset; - - return (dma64_addr_t) pdev_to_baddr(pdev, addr); -} - -EXPORT_SYMBOL(pci_dac_page_to_dma); - -struct page *pci_dac_dma_to_page(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus); - - return pfn_to_page((dma_addr - bc->baddr) >> PAGE_SHIFT); -} - -EXPORT_SYMBOL(pci_dac_dma_to_page); - -unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, - dma64_addr_t dma_addr) -{ - return dma_addr & ~PAGE_MASK; -} - -EXPORT_SYMBOL(pci_dac_dma_to_offset); - -void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); - -void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, - dma64_addr_t dma_addr, size_t len, int direction) -{ - BUG_ON(direction == PCI_DMA_NONE); -} - -EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); diff --git a/arch/mips/mm/dma-ip32.c b/arch/mips/mm/dma-ip32.c deleted file mode 100644 index b42b6f7456e6..000000000000 --- a/arch/mips/mm/dma-ip32.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> - * Copyright (C) 2000, 2001 Ralf Baechle <ralf@gnu.org> - * Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com> - * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. - * IP32 changes by Ilya. - */ -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/dma-mapping.h> - -#include <asm/cache.h> -#include <asm/io.h> -#include <asm/ip32/crime.h> - -/* - * Warning on the terminology - Linux calls an uncached area coherent; - * MIPS terminology calls memory areas with hardware maintained coherency - * coherent. - */ - -/* - * Few notes. - * 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M - * 2. PCI sees memory as one big chunk @0x0 (or we could use 0x40000000 for native-endian) - * 3. All other devices see memory as one big chunk at 0x40000000 - * 4. Non-PCI devices will pass NULL as struct device* - * Thus we translate differently, depending on device. - */ - -#define RAM_OFFSET_MASK 0x3fffffff - -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *) __get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - unsigned long addr = virt_to_phys(ret)&RAM_OFFSET_MASK; - memset(ret, 0, size); - if(dev==NULL) - addr+= CRIME_HI_MEM_BASE; - *dma_handle = addr; - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_noncoherent); - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t * dma_handle, gfp_t gfp) -{ - void *ret; - - ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp); - if (ret) { - dma_cache_wback_inv((unsigned long) ret, size); - ret = UNCAC_ADDR(ret); - } - - return ret; -} - -EXPORT_SYMBOL(dma_alloc_coherent); - -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - free_pages((unsigned long) vaddr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_noncoherent); - -void dma_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - unsigned long addr = (unsigned long) vaddr; - - addr = CAC_ADDR(addr); - free_pages(addr, get_order(size)); -} - -EXPORT_SYMBOL(dma_free_coherent); - -static inline void __dma_sync(unsigned long addr, size_t size, - enum dma_data_direction direction) -{ - switch (direction) { - case DMA_TO_DEVICE: - dma_cache_wback(addr, size); - break; - - case DMA_FROM_DEVICE: - dma_cache_inv(addr, size); - break; - - case DMA_BIDIRECTIONAL: - dma_cache_wback_inv(addr, size); - break; - - default: - BUG(); - } -} - -dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size, - enum dma_data_direction direction) -{ - unsigned long addr = (unsigned long) ptr; - - switch (direction) { - case DMA_TO_DEVICE: - dma_cache_wback(addr, size); - break; - - case DMA_FROM_DEVICE: - dma_cache_inv(addr, size); - break; - - case DMA_BIDIRECTIONAL: - dma_cache_wback_inv(addr, size); - break; - - default: - BUG(); - } - - addr = virt_to_phys(ptr)&RAM_OFFSET_MASK; - if(dev == NULL) - addr+=CRIME_HI_MEM_BASE; - return (dma_addr_t)addr; -} - -EXPORT_SYMBOL(dma_map_single); - -void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - switch (direction) { - case DMA_TO_DEVICE: - break; - - case DMA_FROM_DEVICE: - break; - - case DMA_BIDIRECTIONAL: - break; - - default: - BUG(); - } -} - -EXPORT_SYMBOL(dma_unmap_single); - -int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - for (i = 0; i < nents; i++, sg++) { - unsigned long addr; - - addr = (unsigned long) page_address(sg->page)+sg->offset; - if (addr) - __dma_sync(addr, sg->length, direction); - addr = __pa(addr)&RAM_OFFSET_MASK; - if(dev == NULL) - addr += CRIME_HI_MEM_BASE; - sg->dma_address = (dma_addr_t)addr; - } - - return nents; -} - -EXPORT_SYMBOL(dma_map_sg); - -dma_addr_t dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - addr = (unsigned long) page_address(page) + offset; - dma_cache_wback_inv(addr, size); - addr = __pa(addr)&RAM_OFFSET_MASK; - if(dev == NULL) - addr += CRIME_HI_MEM_BASE; - - return (dma_addr_t)addr; -} - -EXPORT_SYMBOL(dma_map_page); - -void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - if (direction != DMA_TO_DEVICE) { - unsigned long addr; - - dma_address&=RAM_OFFSET_MASK; - addr = dma_address + PAGE_OFFSET; - if(dma_address>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - dma_cache_wback_inv(addr, size); - } -} - -EXPORT_SYMBOL(dma_unmap_page); - -void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - unsigned long addr; - int i; - - BUG_ON(direction == DMA_NONE); - - if (direction == DMA_TO_DEVICE) - return; - - for (i = 0; i < nhwentries; i++, sg++) { - addr = (unsigned long) page_address(sg->page); - if (!addr) - continue; - dma_cache_wback_inv(addr + sg->offset, sg->length); - } -} - -EXPORT_SYMBOL(dma_unmap_sg); - -void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_for_cpu); - -void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_for_device); - -void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + offset + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_cpu); - -void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, enum dma_data_direction direction) -{ - unsigned long addr; - - BUG_ON(direction == DMA_NONE); - - dma_handle&=RAM_OFFSET_MASK; - addr = dma_handle + offset + PAGE_OFFSET; - if(dma_handle>=256*1024*1024) - addr+=CRIME_HI_MEM_BASE; - __dma_sync(addr, size, direction); -} - -EXPORT_SYMBOL(dma_sync_single_range_for_device); - -void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); -} - -EXPORT_SYMBOL(dma_sync_sg_for_cpu); - -void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - int i; - - BUG_ON(direction == DMA_NONE); - - /* Make sure that gcc doesn't leave the empty loop body. */ - for (i = 0; i < nelems; i++, sg++) - __dma_sync((unsigned long)page_address(sg->page), - sg->length, direction); -} - -EXPORT_SYMBOL(dma_sync_sg_for_device); - -int dma_mapping_error(dma_addr_t dma_addr) -{ - return 0; -} - -EXPORT_SYMBOL(dma_mapping_error); - -int dma_supported(struct device *dev, u64 mask) -{ - /* - * we fall back to GFP_DMA when the mask isn't all 1s, - * so we can't guarantee allocations that must be - * within a tighter range than GFP_DMA.. - */ - if (mask < 0x00ffffff) - return 0; - - return 1; -} - -EXPORT_SYMBOL(dma_supported); - -int dma_is_consistent(struct device *dev, dma_addr_t dma_addr) -{ - return 1; -} - -EXPORT_SYMBOL(dma_is_consistent); - -void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - if (direction == DMA_NONE) - return; - - dma_cache_wback_inv((unsigned long)vaddr, size); -} - -EXPORT_SYMBOL(dma_cache_sync); - diff --git a/arch/mips/momentum/jaguar_atx/platform.c b/arch/mips/momentum/jaguar_atx/platform.c index 035ea5137c71..81037709ba0d 100644 --- a/arch/mips/momentum/jaguar_atx/platform.c +++ b/arch/mips/momentum/jaguar_atx/platform.c @@ -129,7 +129,7 @@ static struct mv643xx_eth_platform_data eth2_pd = { static struct platform_device eth2_device = { .name = MV643XX_ETH_NAME, - .id = 1, + .id = 2, .num_resources = ARRAY_SIZE(mv64x60_eth2_resources), .resource = mv64x60_eth2_resources, .dev = { diff --git a/arch/mips/momentum/ocelot_3/platform.c b/arch/mips/momentum/ocelot_3/platform.c index eefe5841fbb2..57cfe5c6e4a8 100644 --- a/arch/mips/momentum/ocelot_3/platform.c +++ b/arch/mips/momentum/ocelot_3/platform.c @@ -129,7 +129,7 @@ static struct mv643xx_eth_platform_data eth2_pd = { static struct platform_device eth2_device = { .name = MV643XX_ETH_NAME, - .id = 1, + .id = 2, .num_resources = ARRAY_SIZE(mv64x60_eth2_resources), .resource = mv64x60_eth2_resources, .dev = { diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 82b20c28bef8..bf85995ca042 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -2,7 +2,7 @@ # Makefile for the PCI specific kernel interface routines under Linux. # -obj-y += pci.o +obj-y += pci.o pci-dac.o # # PCI bus host bridge specific code diff --git a/arch/mips/pci/pci-dac.c b/arch/mips/pci/pci-dac.c new file mode 100644 index 000000000000..0f0ea1b7d4dd --- /dev/null +++ b/arch/mips/pci/pci-dac.c @@ -0,0 +1,79 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> + * Copyright (C) 2000, 2001, 06 Ralf Baechle <ralf@linux-mips.org> + * swiped from i386, and cloned for MIPS by Geert, polished by Ralf. + */ + +#include <linux/types.h> +#include <linux/dma-mapping.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/string.h> + +#include <asm/cache.h> +#include <asm/io.h> + +#include <dma-coherence.h> + +#include <linux/pci.h> + +dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, + struct page *page, unsigned long offset, int direction) +{ + struct device *dev = &pdev->dev; + + BUG_ON(direction == DMA_NONE); + + if (!plat_device_is_coherent(dev)) { + unsigned long addr; + + addr = (unsigned long) page_address(page) + offset; + dma_cache_wback_inv(addr, PAGE_SIZE); + } + + return plat_map_dma_mem_page(dev, page) + offset; +} + +EXPORT_SYMBOL(pci_dac_page_to_dma); + +struct page *pci_dac_dma_to_page(struct pci_dev *pdev, + dma64_addr_t dma_addr) +{ + return pfn_to_page(plat_dma_addr_to_phys(dma_addr) >> PAGE_SHIFT); +} + +EXPORT_SYMBOL(pci_dac_dma_to_page); + +unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, + dma64_addr_t dma_addr) +{ + return dma_addr & ~PAGE_MASK; +} + +EXPORT_SYMBOL(pci_dac_dma_to_offset); + +void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + if (!plat_device_is_coherent(&pdev->dev)) + dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); + +void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + if (!plat_device_is_coherent(&pdev->dev)) + dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); diff --git a/arch/mips/philips/pnx8550/common/proc.c b/arch/mips/philips/pnx8550/common/proc.c index 72a016767e09..3f097558ef13 100644 --- a/arch/mips/philips/pnx8550/common/proc.c +++ b/arch/mips/philips/pnx8550/common/proc.c @@ -79,10 +79,7 @@ static int pnx8550_proc_init( void ) // Create /proc/pnx8550 pnx8550_dir = create_proc_entry("pnx8550", S_IFDIR|S_IRUGO, NULL); - if (pnx8550_dir){ - pnx8550_dir->nlink = 1; - } - else { + if (!pnx8550_dir) { printk(KERN_ERR "Can't create pnx8550 proc dir\n"); return -1; } @@ -90,7 +87,6 @@ static int pnx8550_proc_init( void ) // Create /proc/pnx8550/timers pnx8550_timers = create_proc_entry("timers", S_IFREG|S_IRUGO, pnx8550_dir ); if (pnx8550_timers){ - pnx8550_timers->nlink = 1; pnx8550_timers->read_proc = pnx8550_timers_read; } else { @@ -100,7 +96,6 @@ static int pnx8550_proc_init( void ) // Create /proc/pnx8550/registers pnx8550_registers = create_proc_entry("registers", S_IFREG|S_IRUGO, pnx8550_dir ); if (pnx8550_registers){ - pnx8550_registers->nlink = 1; pnx8550_registers->read_proc = pnx8550_registers_read; } else { diff --git a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c index d1a906e683b2..212547c57310 100644 --- a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c +++ b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c @@ -374,7 +374,7 @@ static long sbprof_tb_ioctl(struct file *filp, return error; } -static struct file_operations sbprof_tb_fops = { +static const struct file_operations sbprof_tb_fops = { .owner = THIS_MODULE, .open = sbprof_tb_open, .release = sbprof_tb_release, diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c index 735cb8778f4c..7316a78fdd68 100644 --- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c +++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c @@ -137,6 +137,8 @@ int tx4927_using_backplane = 0; extern void gt64120_time_init(void); extern void toshiba_rbtx4927_irq_setup(void); +char *prom_getcmdline(void); + #ifdef CONFIG_PCI #define CONFIG_TX4927BUG_WORKAROUND #undef TX4927_SUPPORT_COMMAND_IO |