diff options
Diffstat (limited to 'arch')
257 files changed, 4615 insertions, 2208 deletions
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 770f717bd25..79c6e5a2445 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -83,22 +83,20 @@ choice check out the Linux/Alpha FAQ, accessible on the WWW from <http://www.alphalinux.org/>. In summary: - Alcor/Alpha-XLT AS 600 + Alcor/Alpha-XLT AS 600, AS 500, XL-300, XL-366 Alpha-XL XL-233, XL-266 AlphaBook1 Alpha laptop Avanti AS 200, AS 205, AS 250, AS 255, AS 300, AS 400 Cabriolet AlphaPC64, AlphaPCI64 - DP264 DP264 + DP264 DP264 / DS20 / ES40 / DS10 / DS10L EB164 EB164 21164 evaluation board EB64+ EB64+ 21064 evaluation board EB66 EB66 21066 evaluation board EB66+ EB66+ 21066 evaluation board - Jensen DECpc 150, DEC 2000 model 300, - DEC 2000 model 500 + Jensen DECpc 150, DEC 2000 models 300, 500 LX164 AlphaPC164-LX Lynx AS 2100A - Miata Personal Workstation 433a, 433au, 500a, - 500au, 600a, or 600au + Miata Personal Workstation 433/500/600 a/au Marvel AlphaServer ES47 / ES80 / GS1280 Mikasa AS 1000 Noname AXPpci33, UDB (Multia) @@ -108,9 +106,9 @@ choice Ruffian RPX164-2, AlphaPC164-UX, AlphaPC164-BX SX164 AlphaPC164-SX Sable AS 2000, AS 2100 - Shark DS 20L - Takara Takara - Titan AlphaServer ES45 / DS25 + Shark DS 20L + Takara Takara (OEM) + Titan AlphaServer ES45 / DS25 / DS15 Wildfire AlphaServer GS 40/80/160/320 If you don't know what to do, choose "generic". @@ -481,6 +479,15 @@ config ALPHA_BROKEN_IRQ_MASK depends on ALPHA_GENERIC || ALPHA_PC164 default y +config VGA_HOSE + bool + depends on ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL || ALPHA_TSUNAMI + default y + help + Support VGA on an arbitrary hose; needed for several platforms + which always have multiple hoses, and whose consoles support it. + + config ALPHA_SRM bool "Use SRM as bootloader" if ALPHA_CABRIOLET || ALPHA_AVANTI_CH || ALPHA_EB64P || ALPHA_PC164 || ALPHA_TAKARA || ALPHA_EB164 || ALPHA_ALCOR || ALPHA_MIATA || ALPHA_LX164 || ALPHA_SX164 || ALPHA_NAUTILUS || ALPHA_NONAME default y if ALPHA_JENSEN || ALPHA_MIKASA || ALPHA_SABLE || ALPHA_LYNX || ALPHA_NORITAKE || ALPHA_DP264 || ALPHA_RAWHIDE || ALPHA_EIGER || ALPHA_WILDFIRE || ALPHA_TITAN || ALPHA_SHARK || ALPHA_MARVEL @@ -537,10 +544,14 @@ config HAVE_DEC_LOCK default y config NR_CPUS - int "Maximum number of CPUs (2-64)" - range 2 64 + int "Maximum number of CPUs (2-32)" + range 2 32 depends on SMP - default "64" + default "32" if ALPHA_GENERIC || ALPHA_MARVEL + default "4" if !ALPHA_GENERIC && !ALPHA_MARVEL + help + MARVEL support can handle a maximum of 32 CPUs, all the others + with working support have a maximum of 4 CPUs. config ARCH_DISCONTIGMEM_ENABLE bool "Discontiguous Memory Support (EXPERIMENTAL)" @@ -644,6 +655,13 @@ source "arch/alpha/oprofile/Kconfig" source "arch/alpha/Kconfig.debug" +# DUMMY_CONSOLE may be defined in drivers/video/console/Kconfig +# but we also need it if VGA_HOSE is set +config DUMMY_CONSOLE + bool + depends on VGA_HOSE + default y + source "security/Kconfig" source "crypto/Kconfig" diff --git a/arch/alpha/boot/tools/mkbb.c b/arch/alpha/boot/tools/mkbb.c index 23c7190b047..632a7fd6d7d 100644 --- a/arch/alpha/boot/tools/mkbb.c +++ b/arch/alpha/boot/tools/mkbb.c @@ -81,7 +81,7 @@ typedef union __bootblock { #define bootblock_label __u1.__label #define bootblock_checksum __u2.__checksum -main(int argc, char ** argv) +int main(int argc, char ** argv) { bootblock bootblock_from_disk; bootblock bootloader_image; diff --git a/arch/alpha/kernel/console.c b/arch/alpha/kernel/console.c index f313b34939b..da711e37fc9 100644 --- a/arch/alpha/kernel/console.c +++ b/arch/alpha/kernel/console.c @@ -9,16 +9,20 @@ #include <linux/init.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/vt.h> #include <asm/vga.h> #include <asm/machvec.h> +#include "pci_impl.h" + #ifdef CONFIG_VGA_HOSE -/* - * Externally-visible vga hose bases - */ -unsigned long __vga_hose_io_base = 0; /* base for default hose */ -unsigned long __vga_hose_mem_base = 0; /* base for default hose */ +struct pci_controller *pci_vga_hose; +static struct resource alpha_vga = { + .name = "alpha-vga+", + .start = 0x3C0, + .end = 0x3DF +}; static struct pci_controller * __init default_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2) @@ -30,36 +34,58 @@ default_vga_hose_select(struct pci_controller *h1, struct pci_controller *h2) } void __init -set_vga_hose(struct pci_controller *hose) -{ - if (hose) { - __vga_hose_io_base = hose->io_space->start; - __vga_hose_mem_base = hose->mem_space->start; - } -} - -void __init locate_and_init_vga(void *(*sel_func)(void *, void *)) { struct pci_controller *hose = NULL; struct pci_dev *dev = NULL; + /* Default the select function */ if (!sel_func) sel_func = (void *)default_vga_hose_select; + /* Find the console VGA device */ for(dev=NULL; (dev=pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, dev));) { - if (!hose) hose = dev->sysdata; - else hose = sel_func(hose, dev->sysdata); + if (!hose) + hose = dev->sysdata; + else + hose = sel_func(hose, dev->sysdata); } - /* Did we already inititialize the correct one? */ - if (conswitchp == &vga_con && - __vga_hose_io_base == hose->io_space->start && - __vga_hose_mem_base == hose->mem_space->start) + /* Did we already initialize the correct one? Is there one? */ + if (!hose || (conswitchp == &vga_con && pci_vga_hose == hose)) return; - /* Set the VGA hose and init the new console */ - set_vga_hose(hose); + /* Create a new VGA ioport resource WRT the hose it is on. */ + alpha_vga.start += hose->io_space->start; + alpha_vga.end += hose->io_space->start; + request_resource(hose->io_space, &alpha_vga); + + /* Set the VGA hose and init the new console. */ + pci_vga_hose = hose; take_over_console(&vga_con, 0, MAX_NR_CONSOLES-1, 1); } +void __init +find_console_vga_hose(void) +{ + u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset); + + if (pu64[7] == 3) { /* TERM_TYPE == graphics */ + struct pci_controller *hose; + int h = (pu64[30] >> 24) & 0xff; /* console hose # */ + + /* + * Our hose numbering DOES match the console's, so find + * the right one... + */ + for (hose = hose_head; hose; hose = hose->next) { + if (hose->index == h) break; + } + + if (hose) { + printk("Console graphics on hose %d\n", h); + pci_vga_hose = hose; + } + } +} + #endif diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c index 7f6a98455e7..f10d2eddd2c 100644 --- a/arch/alpha/kernel/core_marvel.c +++ b/arch/alpha/kernel/core_marvel.c @@ -25,6 +25,7 @@ #include <asm/pgalloc.h> #include <asm/tlbflush.h> #include <asm/rtc.h> +#include <asm/vga.h> #include "proto.h" #include "pci_impl.h" @@ -367,9 +368,8 @@ marvel_io7_present(gct6_node *node) } static void __init -marvel_init_vga_hose(void) +marvel_find_console_vga_hose(void) { -#ifdef CONFIG_VGA_HOSE u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset); if (pu64[7] == 3) { /* TERM_TYPE == graphics */ @@ -403,7 +403,6 @@ marvel_init_vga_hose(void) pci_vga_hose = hose; } } -#endif /* CONFIG_VGA_HOSE */ } gct6_search_struct gct_wanted_node_list[] = { @@ -459,7 +458,7 @@ marvel_init_arch(void) marvel_init_io7(io7); /* Check for graphic console location (if any). */ - marvel_init_vga_hose(); + marvel_find_console_vga_hose(); } void @@ -684,9 +683,6 @@ __marvel_rtc_io(u8 b, unsigned long addr, int write) /* * IO map support. */ - -#define __marvel_is_mem_vga(a) (((a) >= 0xa0000) && ((a) <= 0xc0000)) - void __iomem * marvel_ioremap(unsigned long addr, unsigned long size) { @@ -698,13 +694,9 @@ marvel_ioremap(unsigned long addr, unsigned long size) unsigned long pfn; /* - * Adjust the addr. + * Adjust the address. */ -#ifdef CONFIG_VGA_HOSE - if (pci_vga_hose && __marvel_is_mem_vga(addr)) { - addr += pci_vga_hose->mem_space->start; - } -#endif + FIXUP_MEMADDR_VGA(addr); /* * Find the hose. @@ -781,7 +773,9 @@ marvel_ioremap(unsigned long addr, unsigned long size) return (void __iomem *) vaddr; } - return NULL; + /* Assume it was already a reasonable address */ + vaddr = baddr + hose->mem_space->start; + return (void __iomem *) vaddr; } void @@ -803,21 +797,12 @@ marvel_is_mmio(const volatile void __iomem *xaddr) return (addr & 0xFF000000UL) == 0; } -#define __marvel_is_port_vga(a) \ - (((a) >= 0x3b0) && ((a) < 0x3e0) && ((a) != 0x3b3) && ((a) != 0x3d3)) #define __marvel_is_port_kbd(a) (((a) == 0x60) || ((a) == 0x64)) #define __marvel_is_port_rtc(a) (((a) == 0x70) || ((a) == 0x71)) void __iomem *marvel_ioportmap (unsigned long addr) { - if (__marvel_is_port_rtc (addr) || __marvel_is_port_kbd(addr)) - ; -#ifdef CONFIG_VGA_HOSE - else if (__marvel_is_port_vga (addr) && pci_vga_hose) - addr += pci_vga_hose->io_space->start; -#endif - else - return NULL; + FIXUP_IOADDR_VGA(addr); return (void __iomem *)addr; } @@ -829,8 +814,14 @@ marvel_ioread8(void __iomem *xaddr) return 0; else if (__marvel_is_port_rtc(addr)) return __marvel_rtc_io(0, addr, 0); - else + else if (marvel_is_ioaddr(addr)) return __kernel_ldbu(*(vucp)addr); + else + /* this should catch other legacy addresses + that would normally fail on MARVEL, + because there really is nothing there... + */ + return ~0; } void @@ -841,7 +832,7 @@ marvel_iowrite8(u8 b, void __iomem *xaddr) return; else if (__marvel_is_port_rtc(addr)) __marvel_rtc_io(b, addr, 1); - else + else if (marvel_is_ioaddr(addr)) __kernel_stb(b, *(vucp)addr); } diff --git a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c index 3662fef7db9..819326627b9 100644 --- a/arch/alpha/kernel/core_titan.c +++ b/arch/alpha/kernel/core_titan.c @@ -21,6 +21,7 @@ #include <asm/smp.h> #include <asm/pgalloc.h> #include <asm/tlbflush.h> +#include <asm/vga.h> #include "proto.h" #include "pci_impl.h" @@ -35,6 +36,11 @@ struct } saved_config[4] __attribute__((common)); /* + * Is PChip 1 present? No need to query it more than once. + */ +static int titan_pchip1_present; + +/* * BIOS32-style PCI interface: */ @@ -344,43 +350,17 @@ titan_init_one_pachip_port(titan_pachip_port *port, int index) static void __init titan_init_pachips(titan_pachip *pachip0, titan_pachip *pachip1) { - int pchip1_present = TITAN_cchip->csc.csr & 1L<<14; + titan_pchip1_present = TITAN_cchip->csc.csr & 1L<<14; /* Init the ports in hose order... */ titan_init_one_pachip_port(&pachip0->g_port, 0); /* hose 0 */ - if (pchip1_present) + if (titan_pchip1_present) titan_init_one_pachip_port(&pachip1->g_port, 1);/* hose 1 */ titan_init_one_pachip_port(&pachip0->a_port, 2); /* hose 2 */ - if (pchip1_present) + if (titan_pchip1_present) titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */ } -static void __init -titan_init_vga_hose(void) -{ -#ifdef CONFIG_VGA_HOSE - u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset); - - if (pu64[7] == 3) { /* TERM_TYPE == graphics */ - struct pci_controller *hose; - int h = (pu64[30] >> 24) & 0xff; /* console hose # */ - - /* - * Our hose numbering matches the console's, so just find - * the right one... - */ - for (hose = hose_head; hose; hose = hose->next) { - if (hose->index == h) break; - } - - if (hose) { - printk("Console graphics on hose %d\n", hose->index); - pci_vga_hose = hose; - } - } -#endif /* CONFIG_VGA_HOSE */ -} - void __init titan_init_arch(void) { @@ -406,6 +386,7 @@ titan_init_arch(void) /* With multiple PCI busses, we play with I/O as physical addrs. */ ioport_resource.end = ~0UL; + iomem_resource.end = ~0UL; /* PCI DMA Direct Mapping is 1GB at 2GB. */ __direct_map_base = 0x80000000; @@ -415,7 +396,7 @@ titan_init_arch(void) titan_init_pachips(TITAN_pachip0, TITAN_pachip1); /* Check for graphic console location (if any). */ - titan_init_vga_hose(); + find_console_vga_hose(); } static void @@ -441,9 +422,7 @@ titan_kill_one_pachip_port(titan_pachip_port *port, int index) static void titan_kill_pachips(titan_pachip *pachip0, titan_pachip *pachip1) { - int pchip1_present = TITAN_cchip->csc.csr & 1L<<14; - - if (pchip1_present) { + if (titan_pchip1_present) { titan_kill_one_pachip_port(&pachip1->g_port, 1); titan_kill_one_pachip_port(&pachip1->a_port, 3); } @@ -463,6 +442,14 @@ titan_kill_arch(int mode) */ void __iomem * +titan_ioportmap(unsigned long addr) +{ + FIXUP_IOADDR_VGA(addr); + return (void __iomem *)(addr + TITAN_IO_BIAS); +} + + +void __iomem * titan_ioremap(unsigned long addr, unsigned long size) { int h = (addr & TITAN_HOSE_MASK) >> TITAN_HOSE_SHIFT; @@ -475,14 +462,12 @@ titan_ioremap(unsigned long addr, unsigned long size) unsigned long pfn; /* - * Adjust the addr. + * Adjust the address and hose, if necessary. */ -#ifdef CONFIG_VGA_HOSE - if (pci_vga_hose && __titan_is_mem_vga(addr)) { + if (pci_vga_hose && __is_mem_vga(addr)) { h = pci_vga_hose->index; addr += pci_vga_hose->mem_space->start; } -#endif /* * Find the hose. @@ -521,8 +506,10 @@ titan_ioremap(unsigned long addr, unsigned long size) * Map it */ area = get_vm_area(size, VM_IOREMAP); - if (!area) + if (!area) { + printk("ioremap failed... no vm_area...\n"); return NULL; + } ptes = hose->sg_pci->ptes; for (vaddr = (unsigned long)area->addr; @@ -539,7 +526,7 @@ titan_ioremap(unsigned long addr, unsigned long size) if (__alpha_remap_area_pages(vaddr, pfn << PAGE_SHIFT, PAGE_SIZE, 0)) { - printk("FAILED to map...\n"); + printk("FAILED to remap_area_pages...\n"); vfree(area->addr); return NULL; } @@ -551,7 +538,8 @@ titan_ioremap(unsigned long addr, unsigned long size) return (void __iomem *) vaddr; } - return NULL; + /* Assume a legacy (read: VGA) address, and return appropriately. */ + return (void __iomem *)(addr + TITAN_MEM_BIAS); } void @@ -574,6 +562,7 @@ titan_is_mmio(const volatile void __iomem *xaddr) } #ifndef CONFIG_ALPHA_GENERIC +EXPORT_SYMBOL(titan_ioportmap); EXPORT_SYMBOL(titan_ioremap); EXPORT_SYMBOL(titan_iounmap); EXPORT_SYMBOL(titan_is_mmio); @@ -750,6 +739,7 @@ titan_agp_info(void) if (titan_query_agp(port)) hosenum = 2; if (hosenum < 0 && + titan_pchip1_present && titan_query_agp(port = &TITAN_pachip1->a_port)) hosenum = 3; diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c index ce623c6e55e..ef91e09590d 100644 --- a/arch/alpha/kernel/core_tsunami.c +++ b/arch/alpha/kernel/core_tsunami.c @@ -19,6 +19,7 @@ #include <asm/ptrace.h> #include <asm/smp.h> +#include <asm/vga.h> #include "proto.h" #include "pci_impl.h" @@ -349,6 +350,26 @@ tsunami_init_one_pchip(tsunami_pchip *pchip, int index) tsunami_pci_tbi(hose, 0, -1); } + +void __iomem * +tsunami_ioportmap(unsigned long addr) +{ + FIXUP_IOADDR_VGA(addr); + return (void __iomem *)(addr + TSUNAMI_IO_BIAS); +} + +void __iomem * +tsunami_ioremap(unsigned long addr, unsigned long size) +{ + FIXUP_MEMADDR_VGA(addr); + return (void __iomem *)(addr + TSUNAMI_MEM_BIAS); +} + +#ifndef CONFIG_ALPHA_GENERIC +EXPORT_SYMBOL(tsunami_ioportmap); +EXPORT_SYMBOL(tsunami_ioremap); +#endif + void __init tsunami_init_arch(void) { @@ -393,6 +414,9 @@ tsunami_init_arch(void) tsunami_init_one_pchip(TSUNAMI_pchip0, 0); if (TSUNAMI_cchip->csc.csr & 1L<<14) tsunami_init_one_pchip(TSUNAMI_pchip1, 1); + + /* Check for graphic console location (if any). */ + find_console_vga_hose(); } static void diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index c95e95e1ab0..debc8f03886 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -391,11 +391,10 @@ $work_resched: bne $2, $work_resched $work_notifysig: - mov $sp, $17 + mov $sp, $16 br $1, do_switch_stack - mov $5, $21 - mov $sp, $18 - mov $31, $16 + mov $sp, $17 + mov $5, $18 jsr $26, do_notify_resume bsr $1, undo_switch_stack br restore_all diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index 6e7d1fe6e93..28c84e55feb 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -7,6 +7,7 @@ #include <linux/pci.h> #include <linux/slab.h> #include <linux/bootmem.h> +#include <linux/log2.h> #include <asm/io.h> #include <asm/hwrpb.h> @@ -53,7 +54,7 @@ size_for_memory(unsigned long max) { unsigned long mem = max_low_pfn << PAGE_SHIFT; if (mem < max) - max = 1UL << ceil_log2(mem); + max = roundup_pow_of_two(mem); return max; } diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h index 95912ecc65e..708d5ca8778 100644 --- a/arch/alpha/kernel/proto.h +++ b/arch/alpha/kernel/proto.h @@ -108,6 +108,15 @@ extern int wildfire_cpuid_to_nid(int); extern unsigned long wildfire_node_mem_start(int); extern unsigned long wildfire_node_mem_size(int); +/* console.c */ +#ifdef CONFIG_VGA_HOSE +extern void find_console_vga_hose(void); +extern void locate_and_init_vga(void *(*)(void *, void *)); +#else +static inline void find_console_vga_hose(void) { } +static inline void locate_and_init_vga(void *(*sel_func)(void *, void *)) { } +#endif + /* setup.c */ extern unsigned long srm_hae; extern int boot_cpuid; diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 915f26345c4..bd5e68cd61e 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -43,6 +43,7 @@ #include <linux/notifier.h> #include <asm/setup.h> #include <asm/io.h> +#include <linux/log2.h> extern struct atomic_notifier_head panic_notifier_list; static int alpha_panic_event(struct notifier_block *, unsigned long, void *); @@ -1303,7 +1304,7 @@ external_cache_probe(int minsize, int width) long size = minsize, maxsize = MAX_BCACHE_SIZE * 2; if (maxsize > (max_low_pfn + 1) << PAGE_SHIFT) - maxsize = 1 << (floor_log2(max_low_pfn + 1) + PAGE_SHIFT); + maxsize = 1 << (ilog2(max_low_pfn + 1) + PAGE_SHIFT); /* Get the first block cached. */ read_mem_block(__va(0), stride, size); diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 7f64aa767d5..410af4f3140 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -32,8 +32,8 @@ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage void ret_from_sys_call(void); -static int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *, - unsigned long, unsigned long); +static void do_signal(struct pt_regs *, struct switch_stack *, + unsigned long, unsigned long); /* @@ -146,11 +146,9 @@ sys_rt_sigaction(int sig, const struct sigaction __user *act, asmlinkage int do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) { - sigset_t oldset; - mask &= _BLOCKABLE; spin_lock_irq(¤t->sighand->siglock); - oldset = current->blocked; + current->saved_sigmask = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); @@ -160,19 +158,17 @@ do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) regs->r0 = EINTR; regs->r19 = 1; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&oldset, regs, sw, 0, 0)) - return -EINTR; - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } asmlinkage int do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, struct pt_regs *regs, struct switch_stack *sw) { - sigset_t oldset, set; + sigset_t set; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) @@ -182,7 +178,7 @@ do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); - oldset = current->blocked; + current->saved_sigmask = current->blocked; current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); @@ -192,12 +188,10 @@ do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, regs->r0 = EINTR; regs->r19 = 1; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(&oldset, regs, sw, 0, 0)) - return -EINTR; - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } asmlinkage int @@ -436,7 +430,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, return err; } -static void +static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) { @@ -481,13 +475,14 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, current->comm, current->pid, frame, regs->pc, regs->r26); #endif - return; + return 0; give_sigsegv: force_sigsegv(sig, current); + return -EFAULT; } -static void +static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) { @@ -543,34 +538,38 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, current->comm, current->pid, frame, regs->pc, regs->r26); #endif - return; + return 0; give_sigsegv: force_sigsegv(sig, current); + return -EFAULT; } /* * OK, we're invoking a handler. */ -static inline void +static inline int handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw) { + int ret; + if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(sig, ka, info, oldset, regs, sw); + ret = setup_rt_frame(sig, ka, info, oldset, regs, sw); else - setup_frame(sig, ka, oldset, regs, sw); + ret = setup_frame(sig, ka, oldset, regs, sw); - if (ka->sa.sa_flags & SA_RESETHAND) - ka->sa.sa_handler = SIG_DFL; + if (ret == 0) { + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked,sig); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + } - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked,sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + return ret; } static inline void @@ -611,30 +610,42 @@ syscall_restart(unsigned long r0, unsigned long r19, * restart. "r0" is also used as an indicator whether we can restart at * all (if we get here from anything but a syscall return, it will be 0) */ -static int -do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, +static void +do_signal(struct pt_regs * regs, struct switch_stack * sw, unsigned long r0, unsigned long r19) { siginfo_t info; int signr; unsigned long single_stepping = ptrace_cancel_bpt(current); struct k_sigaction ka; + sigset_t *oldset; - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; /* This lets the debugger run, ... */ signr = get_signal_to_deliver(&info, &ka, regs, NULL); + /* ... so re-check the single stepping. */ single_stepping |= ptrace_cancel_bpt(current); if (signr > 0) { /* Whee! Actually deliver the signal. */ - if (r0) syscall_restart(r0, r19, regs, &ka); - handle_signal(signr, &ka, &info, oldset, regs, sw); + if (r0) + syscall_restart(r0, r19, regs, &ka); + if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) { + /* A signal was successfully delivered, and the + saved sigmask was stored on the signal frame, + and will be restored by sigreturn. So we can + simply clear the restore sigmask flag. */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } if (single_stepping) ptrace_set_bpt(current); /* re-set bpt */ - return 1; + return; } if (r0) { @@ -654,17 +665,22 @@ do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, break; } } + + /* If there's no signal to deliver, we just restore the saved mask. */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); + } + if (single_stepping) ptrace_set_bpt(current); /* re-set breakpoint */ - - return 0; } void -do_notify_resume(sigset_t *oldset, struct pt_regs *regs, - struct switch_stack *sw, unsigned long r0, - unsigned long r19, unsigned long thread_info_flags) +do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, + unsigned long thread_info_flags, + unsigned long r0, unsigned long r19) { - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(oldset, regs, sw, r0, r19); + if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) + do_signal(regs, sw, r0, r19); } diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index 85d2f933dd0..c71b0fd7a61 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -543,6 +543,7 @@ dp264_init_pci(void) { common_init_pci(); SMC669_Init(0); + locate_and_init_vga(NULL); } static void __init @@ -551,6 +552,14 @@ monet_init_pci(void) common_init_pci(); SMC669_Init(1); es1888_init(); + locate_and_init_vga(NULL); +} + +static void __init +clipper_init_pci(void) +{ + common_init_pci(); + locate_and_init_vga(NULL); } static void __init @@ -655,7 +664,7 @@ struct alpha_machine_vector clipper_mv __initmv = { .init_arch = tsunami_init_arch, .init_irq = clipper_init_irq, .init_rtc = common_init_rtc, - .init_pci = common_init_pci, + .init_pci = clipper_init_pci, .kill_arch = tsunami_kill_arch, .pci_map_irq = clipper_map_irq, .pci_swizzle = common_swizzle, diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c index e349f03b830..0bcb968cb60 100644 --- a/arch/alpha/kernel/sys_marvel.c +++ b/arch/alpha/kernel/sys_marvel.c @@ -22,6 +22,7 @@ #include <asm/core_marvel.h> #include <asm/hwrpb.h> #include <asm/tlbflush.h> +#include <asm/vga.h> #include "proto.h" #include "err_impl.h" @@ -412,10 +413,7 @@ marvel_init_pci(void) pci_probe_only = 1; common_init_pci(); - -#ifdef CONFIG_VGA_HOSE locate_and_init_vga(NULL); -#endif /* Clear any io7 errors. */ for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c index f009b7bc094..1d3c1398c42 100644 --- a/arch/alpha/kernel/sys_titan.c +++ b/arch/alpha/kernel/sys_titan.c @@ -331,9 +331,7 @@ titan_init_pci(void) pci_probe_only = 1; common_init_pci(); SMC669_Init(0); -#ifdef CONFIG_VGA_HOSE locate_and_init_vga(NULL); -#endif } diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S index f6cfe8ce3f9..79de99e32c3 100644 --- a/arch/alpha/kernel/systbls.S +++ b/arch/alpha/kernel/systbls.S @@ -465,6 +465,38 @@ sys_call_table: .quad sys_inotify_init .quad sys_inotify_add_watch /* 445 */ .quad sys_inotify_rm_watch + .quad sys_fdatasync + .quad sys_kexec_load + .quad sys_migrate_pages + .quad sys_openat /* 450 */ + .quad sys_mkdirat + .quad sys_mknodat + .quad sys_fchownat + .quad sys_futimesat + .quad sys_fstatat64 /* 455 */ + .quad sys_unlinkat + .quad sys_renameat + .quad sys_linkat + .quad sys_symlinkat + .quad sys_readlinkat /* 460 */ + .quad sys_fchmodat + .quad sys_faccessat + .quad sys_pselect6 + .quad sys_ppoll + .quad sys_unshare /* 465 */ + .quad sys_set_robust_list + .quad sys_get_robust_list + .quad sys_splice + .quad sys_sync_file_range + .quad sys_tee /* 470 */ + .quad sys_vmsplice + .quad sys_move_pages + .quad sys_getcpu + .quad sys_epoll_pwait + .quad sys_utimensat /* 475 */ + .quad sys_signalfd + .quad sys_timerfd + .quad sys_eventfd .size sys_call_table, . - sys_call_table .type sys_call_table, @object diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index ea098f3b629..266f78e1307 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -37,7 +37,8 @@ lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \ $(ev6-y)clear_page.o \ $(ev6-y)copy_page.o \ fpreg.o \ - callback_srm.o srm_puts.o srm_printk.o + callback_srm.o srm_puts.o srm_printk.o \ + fls.o lib-$(CONFIG_SMP) += dec_and_lock.o diff --git a/arch/alpha/lib/fls.c b/arch/alpha/lib/fls.c new file mode 100644 index 00000000000..7ad84ea0acf --- /dev/null +++ b/arch/alpha/lib/fls.c @@ -0,0 +1,38 @@ +/* + * arch/alpha/lib/fls.c + */ + +#include <linux/module.h> +#include <asm/bitops.h> + +/* This is fls(x)-1, except zero is held to zero. This allows most + efficent input into extbl, plus it allows easy handling of fls(0)=0. */ + +const unsigned char __flsm1_tab[256] = +{ + 0, + 0, + 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +}; + +EXPORT_SYMBOL(__flsm1_tab); diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 2568d311be2..23348e9561b 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -247,7 +247,7 @@ not_relocated: mov r0, #0 mov r3, r7 bl decompress_kernel - add r0, r0, #127 + add r0, r0, #127 + 128 @ alignment + stack bic r0, r0, #127 @ align the kernel length /* * r0 = decompressed kernel length @@ -269,6 +269,7 @@ not_relocated: mov r0, #0 stmia r1!, {r9 - r14} cmp r2, r3 blo 1b + add sp, r1, #128 @ relocate the stack bl cache_clean_flush add pc, r5, r0 @ call relocation code @@ -476,6 +477,7 @@ __common_mmu_cache_on: */ .align 5 reloc_start: add r9, r5, r0 + sub r9, r9, #128 @ do not copy the stack debug_reloc_start mov r1, r4 1: @@ -486,6 +488,7 @@ reloc_start: add r9, r5, r0 cmp r5, r9 blo 1b + add sp, r1, #128 @ relocate the stack debug_reloc_end call_kernel: bl cache_clean_flush diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 9179e822031..f73d62e8ab6 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -57,7 +57,7 @@ extern void fp_enter(void); #define EXPORT_SYMBOL_ALIAS(sym,orig) \ EXPORT_CRC_ALIAS(sym) \ static const struct kernel_symbol __ksymtab_##sym \ - __attribute_used__ __attribute__((section("__ksymtab"))) = \ + __used __attribute__((section("__ksymtab"))) = \ { (unsigned long)&orig, #sym }; /* diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c index 8b63ad89d0a..ae31deb2d06 100644 --- a/arch/arm/kernel/stacktrace.c +++ b/arch/arm/kernel/stacktrace.c @@ -13,7 +13,7 @@ int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, /* * Check current frame pointer is within bounds */ - if ((fp - 12) < low || fp + 4 >= high) + if (fp < (low + 12) || fp + 4 >= high) break; frame = (struct stackframe *)(fp - 12); diff --git a/arch/arm/mach-at91/board-dk.c b/arch/arm/mach-at91/board-dk.c index 6043c38c0a9..af497896a96 100644 --- a/arch/arm/mach-at91/board-dk.c +++ b/arch/arm/mach-at91/board-dk.c @@ -132,7 +132,7 @@ static struct mtd_partition __initdata dk_nand_partition[] = { }, }; -static struct mtd_partition *nand_partitions(int size, int *num_partitions) +static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) { *num_partitions = ARRAY_SIZE(dk_nand_partition); return dk_nand_partition; diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c index 76f6e1e553e..7d9b1a278fd 100644 --- a/arch/arm/mach-at91/board-kb9202.c +++ b/arch/arm/mach-at91/board-kb9202.c @@ -96,7 +96,7 @@ static struct mtd_partition __initdata kb9202_nand_partition[] = { }, }; -static struct mtd_partition *nand_partitions(int size, int *num_partitions) +static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) { *num_partitions = ARRAY_SIZE(kb9202_nand_partition); return kb9202_nand_partition; diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index 1f0c8a400b3..26ca8ab3f62 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -178,7 +178,7 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition *nand_partitions(int size, int *num_partitions) +static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) { *num_partitions = ARRAY_SIZE(ek_nand_partition); return ek_nand_partition; diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index f57458559fb..c164c8e58ae 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -180,7 +180,7 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition *nand_partitions(int size, int *num_partitions) +static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) { *num_partitions = ARRAY_SIZE(ek_nand_partition); return ek_nand_partition; diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c index 30c79aca84d..9b61320f295 100644 --- a/arch/arm/mach-at91/board-sam9rlek.c +++ b/arch/arm/mach-at91/board-sam9rlek.c @@ -87,7 +87,7 @@ static struct mtd_partition __initdata ek_nand_partition[] = { }, }; -static struct mtd_partition *nand_partitions(int size, int *num_partitions) +static struct mtd_partition * __init nand_partitions(int size, int *num_partitions) { *num_partitions = ARRAY_SIZE(ek_nand_partition); return ek_nand_partition; diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 06c9a0507d0..848efb2a4eb 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -364,19 +364,14 @@ static int at91_clk_show(struct seq_file *s, void *unused) { u32 scsr, pcsr, sr; struct clk *clk; - unsigned i; seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR)); seq_printf(s, "PCSR = %8x\n", pcsr = at91_sys_read(AT91_PMC_PCSR)); - seq_printf(s, "MOR = %8x\n", at91_sys_read(AT91_CKGR_MOR)); seq_printf(s, "MCFR = %8x\n", at91_sys_read(AT91_CKGR_MCFR)); seq_printf(s, "PLLA = %8x\n", at91_sys_read(AT91_CKGR_PLLAR)); seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR)); - seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR)); - for (i = 0; i < 4; i++) - seq_printf(s, "PCK%d = %8x\n", i, at91_sys_read(AT91_PMC_PCKR(i))); seq_printf(s, "SR = %8x\n", sr = at91_sys_read(AT91_PMC_SR)); seq_printf(s, "\n"); diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index ff8db29e989..47ff676aca5 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -76,12 +76,11 @@ static int at91_pm_verify_clocks(void) pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n"); return 0; } - } else if (cpu_is_at91sam9260()) { -#warning "Check SAM9260 USB clocks" - } else if (cpu_is_at91sam9261()) { -#warning "Check SAM9261 USB clocks" - } else if (cpu_is_at91sam9263()) { -#warning "Check SAM9263 USB clocks" + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()) { + if ((scsr & (AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP)) != 0) { + pr_debug("AT91: PM - Suspend-to-RAM with USB still active\n"); + return 0; + } } #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS diff --git a/arch/arm/mach-footbridge/cats-pci.c b/arch/arm/mach-footbridge/cats-pci.c index 4f984fde737..35eb232a649 100644 --- a/arch/arm/mach-footbridge/cats-pci.c +++ b/arch/arm/mach-footbridge/cats-pci.c @@ -45,7 +45,7 @@ static struct hw_pci cats_pci __initdata = { .postinit = dc21285_postinit, }; -static int cats_pci_init(void) +static int __init cats_pci_init(void) { if (machine_is_cats()) pci_common_init(&cats_pci); diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 7a7fa51ec62..1c474cf709c 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -201,7 +201,6 @@ void __init imx_set_mmc_info(struct imxmmc_platform_data *info) { imx_mmc_device.dev.platform_data = info; } -EXPORT_SYMBOL(imx_set_mmc_info); static struct imxfb_mach_info imx_fb_info; diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c index 0fdd03ab36e..ce7c15c7300 100644 --- a/arch/arm/mach-ixp2000/ixdp2400.c +++ b/arch/arm/mach-ixp2000/ixdp2400.c @@ -164,7 +164,7 @@ int __init ixdp2400_pci_init(void) subsys_initcall(ixdp2400_pci_init); -void ixdp2400_init_irq(void) +void __init ixdp2400_init_irq(void) { ixdp2x00_init_irq(IXDP2400_CPLD_INT_STAT, IXDP2400_CPLD_INT_MASK, IXDP2400_NR_IRQS); } diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c index 70d247f09a7..14f09b80ab7 100644 --- a/arch/arm/mach-ixp2000/ixdp2800.c +++ b/arch/arm/mach-ixp2000/ixdp2800.c @@ -279,7 +279,7 @@ int __init ixdp2800_pci_init(void) subsys_initcall(ixdp2800_pci_init); -void ixdp2800_init_irq(void) +void __init ixdp2800_init_irq(void) { ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2800_NR_IRQS); } diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 011065b967b..73c651e83d9 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c @@ -145,7 +145,7 @@ static struct irq_chip ixdp2x00_cpld_irq_chip = { .unmask = ixdp2x00_irq_unmask }; -void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs) +void __init ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs) { unsigned int irq; diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c index 7a86a2516ea..c41a6b5a0ac 100644 --- a/arch/arm/mach-ixp23xx/ixdp2351.c +++ b/arch/arm/mach-ixp23xx/ixdp2351.c @@ -124,7 +124,7 @@ static struct irq_chip ixdp2351_intb_chip = { .unmask = ixdp2351_intb_unmask }; -void ixdp2351_init_irq(void) +void __init ixdp2351_init_irq(void) { int irq; diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c index ac7d43d23c2..227f808dc0e 100644 --- a/arch/arm/mach-ixp23xx/pci.c +++ b/arch/arm/mach-ixp23xx/pci.c @@ -284,7 +284,7 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys) return 1; } -void ixp23xx_pci_slave_init(void) +void __init ixp23xx_pci_slave_init(void) { ixp23xx_pci_common_init(); } diff --git a/arch/arm/mach-ixp23xx/roadrunner.c b/arch/arm/mach-ixp23xx/roadrunner.c index d06e21b70de..e35644961aa 100644 --- a/arch/arm/mach-ixp23xx/roadrunner.c +++ b/arch/arm/mach-ixp23xx/roadrunner.c @@ -110,7 +110,7 @@ static int __init roadrunner_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) return NO_IRQ; } -static void roadrunner_pci_preinit(void) +static void __init roadrunner_pci_preinit(void) { set_irq_type(IRQ_ROADRUNNER_PCI_INTC, IRQT_LOW); set_irq_type(IRQ_ROADRUNNER_PCI_INTD, IRQT_LOW); diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig index 9715ef506c2..060909870b5 100644 --- a/arch/arm/mach-ixp4xx/Kconfig +++ b/arch/arm/mach-ixp4xx/Kconfig @@ -104,9 +104,6 @@ config MACH_DSMG600 DSM-G600 RevA device. For more information on this platform, see http://www.nslu2-linux.org/wiki/DSMG600/HomePage -# -# Avila and IXDP share the same source for now. Will change in future -# config ARCH_IXDP4XX bool depends on ARCH_IXDP425 || MACH_IXDP465 || MACH_KIXRP435 diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 64685da1462..8112f726ffa 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -283,7 +283,7 @@ static struct irqaction ixp4xx_timer_irq = { .handler = ixp4xx_timer_interrupt, }; -static void __init ixp4xx_timer_init(void) +void __init ixp4xx_timer_init(void) { /* Reset/disable counter */ *IXP4XX_OSRT1 = 0; diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c index 7bc94f3def1..ad2e5b97966 100644 --- a/arch/arm/mach-ixp4xx/coyote-pci.c +++ b/arch/arm/mach-ixp4xx/coyote-pci.c @@ -25,10 +25,6 @@ #include <asm/mach/pci.h> -extern void ixp4xx_pci_preinit(void); -extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); -extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys); - void __init coyote_pci_preinit(void) { set_irq_type(IRQ_COYOTE_PCI_SLOT0, IRQT_LOW); diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c index 1caff65e22c..1e75e105c4f 100644 --- a/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -18,6 +18,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> +#include <asm/mach/time.h> static struct flash_platform_data dsmg600_flash_data = { .map_name = "cfi_probe", @@ -128,6 +129,19 @@ static void dsmg600_power_off(void) gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH); } +static void __init dsmg600_timer_init(void) +{ + /* The xtal on this machine is non-standard. */ + ixp4xx_timer_freq = DSMG600_FREQ; + + /* Call standard timer_init function. */ + ixp4xx_timer_init(); +} + +static struct sys_timer dsmg600_timer = { + .init = dsmg600_timer_init, +}; + static void __init dsmg600_init(void) { ixp4xx_sys_init(); @@ -155,21 +169,13 @@ static void __init dsmg600_init(void) #endif } -static void __init dsmg600_fixup(struct machine_desc *desc, - struct tag *tags, char **cmdline, struct meminfo *mi) -{ - /* The xtal on this machine is non-standard. */ - ixp4xx_timer_freq = DSMG600_FREQ; -} - MACHINE_START(DSMG600, "D-Link DSM-G600 RevA") /* Maintainer: www.nslu2-linux.org */ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC, .boot_params = 0x00000100, - .fixup = dsmg600_fixup, .map_io = ixp4xx_map_io, .init_irq = ixp4xx_init_irq, - .timer = &ixp4xx_timer, + .timer = &dsmg600_timer, .init_machine = dsmg600_init, MACHINE_END diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c index 509a95a692a..d1e75b7dc3b 100644 --- a/arch/arm/mach-ixp4xx/ixdpg425-pci.c +++ b/arch/arm/mach-ixp4xx/ixdpg425-pci.c @@ -23,10 +23,6 @@ #include <asm/mach/pci.h> -extern void ixp4xx_pci_preinit(void); -extern int ixp4xx_setup(int nr, struct pci_sys_data *sys); -extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys); - void __init ixdpg425_pci_preinit(void) { set_irq_type(IRQ_IXP4XX_GPIO6, IRQT_LOW); diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 9a31444d921..78a17413cec 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -155,7 +155,8 @@ static void __init nas100d_init(void) pm_power_off = nas100d_power_off; - /* This is only useful on a modified machine, but it is valuable + /* + * This is only useful on a modified machine, but it is valuable * to have it first in order to see debug messages, and so that * it does *not* get removed if platform_add_devices fails! */ diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index 162c266e5f8..9bf8ccbcacc 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -22,6 +22,7 @@ #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/flash.h> +#include <asm/mach/time.h> static struct flash_platform_data nslu2_flash_data = { .map_name = "cfi_probe", @@ -49,26 +50,26 @@ static struct ixp4xx_i2c_pins nslu2_i2c_gpio_pins = { static struct resource nslu2_led_resources[] = { { .name = "ready", /* green led */ - .start = NSLU2_LED_GRN, - .end = NSLU2_LED_GRN, + .start = NSLU2_LED_GRN_GPIO, + .end = NSLU2_LED_GRN_GPIO, .flags = IXP4XX_GPIO_HIGH, }, { .name = "status", /* red led */ - .start = NSLU2_LED_RED, - .end = NSLU2_LED_RED, + .start = NSLU2_LED_RED_GPIO, + .end = NSLU2_LED_RED_GPIO, .flags = IXP4XX_GPIO_HIGH, }, { .name = "disk-1", - .start = NSLU2_LED_DISK1, - .end = NSLU2_LED_DISK1, + .start = NSLU2_LED_DISK1_GPIO, + .end = NSLU2_LED_DISK1_GPIO, .flags = IXP4XX_GPIO_LOW, }, { .name = "disk-2", - .start = NSLU2_LED_DISK2, - .end = NSLU2_LED_DISK2, + .start = NSLU2_LED_DISK2_GPIO, + .end = NSLU2_LED_DISK2_GPIO, .flags = IXP4XX_GPIO_LOW, }, }; @@ -157,10 +158,21 @@ static void nslu2_power_off(void) gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH); } -static void __init nslu2_init(void) +static void __init nslu2_timer_init(void) { - ixp4xx_timer_freq = NSLU2_FREQ; + /* The xtal on this machine is non-standard. */ + ixp4xx_timer_freq = NSLU2_FREQ; + + /* Call standard timer_init function. */ + ixp4xx_timer_init(); +} +static struct sys_timer nslu2_timer = { + .init = nslu2_timer_init, +}; + +static void __init nslu2_init(void) +{ ixp4xx_sys_init(); nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0); @@ -169,7 +181,8 @@ static void __init nslu2_init(void) pm_power_off = nslu2_power_off; - /* This is only useful on a modified machine, but it is valuable + /* + * This is only useful on a modified machine, but it is valuable * to have it first in order to see debug messages, and so that * it does *not* get removed if platform_add_devices fails! */ @@ -185,6 +198,6 @@ MACHINE_START(NSLU2, "Linksys NSLU2") .boot_params = 0x00000100, .map_io = ixp4xx_map_io, .init_irq = ixp4xx_init_irq, - .timer = &ixp4xx_timer, + .timer = &nslu2_timer, .init_machine = nslu2_init, MACHINE_END diff --git a/arch/arm/mach-s3c2410/bast.h b/arch/arm/mach-s3c2410/bast.h deleted file mode 100644 index e98543742eb..00000000000 --- a/arch/arm/mach-s3c2410/bast.h +++ /dev/null @@ -1,2 +0,0 @@ -/* linux/arch/arm/mach-s3c2410/bast.h -extern void bast_init_irq(void); diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c index bc308ceb91c..435adcce648 100644 --- a/arch/arm/mach-s3c2410/mach-amlm5900.c +++ b/arch/arm/mach-s3c2410/mach-amlm5900.c @@ -160,7 +160,7 @@ static struct platform_device *amlm5900_devices[] __initdata = { #endif }; -void __init amlm5900_map_io(void) +static void __init amlm5900_map_io(void) { s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc)); s3c24xx_init_clocks(0); diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c index c602aa39f9c..782b5814ced 100644 --- a/arch/arm/mach-s3c2412/s3c2412.c +++ b/arch/arm/mach-s3c2412/s3c2412.c @@ -16,6 +16,7 @@ #include <linux/list.h> #include <linux/timer.h> #include <linux/init.h> +#include <linux/delay.h> #include <linux/sysdev.h> #include <linux/serial_core.h> #include <linux/platform_device.h> @@ -29,6 +30,7 @@ #include <asm/io.h> #include <asm/irq.h> +#include <asm/arch/reset.h> #include <asm/arch/idle.h> #include <asm/arch/regs-clock.h> @@ -38,6 +40,7 @@ #include <asm/arch/regs-gpioj.h> #include <asm/arch/regs-dsc.h> #include <asm/arch/regs-spi.h> +#include <asm/arch/regs-s3c2412.h> #include <asm/plat-s3c24xx/s3c2412.h> #include <asm/plat-s3c24xx/cpu.h> @@ -106,6 +109,23 @@ static void s3c2412_idle(void) cpu_do_idle(); } +static void s3c2412_hard_reset(void) +{ + /* errata "Watch-dog/Software Reset Problem" specifies that + * this reset must be done with the SYSCLK sourced from + * EXTCLK instead of FOUT to avoid a glitch in the reset + * mechanism. + * + * See the watchdog section of the S3C2412 manual for more + * information on this fix. + */ + + __raw_writel(0x00, S3C2412_CLKSRC); + __raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST); + + mdelay(1); +} + /* s3c2412_map_io * * register the standard cpu IO areas, and any passed in from the @@ -122,6 +142,10 @@ void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size) s3c24xx_idle = s3c2412_idle; + /* set custom reset hook */ + + s3c24xx_reset_hook = s3c2412_hard_reset; + /* register our io-tables */ iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc)); diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c index b5d387ef37e..bff7ddd06a5 100644 --- a/arch/arm/mach-s3c2440/mach-anubis.c +++ b/arch/arm/mach-s3c2440/mach-anubis.c @@ -76,8 +76,8 @@ static struct map_desc anubis_iodesc[] __initdata = { .length = SZ_4K, .type = MT_DEVICE, }, { - .virtual = (u32)ANUBIS_VA_CTRL2, - .pfn = __phys_to_pfn(ANUBIS_PA_CTRL2), + .virtual = (u32)ANUBIS_VA_IDREG, + .pfn = __phys_to_pfn(ANUBIS_PA_IDREG), .length = SZ_4K, .type = MT_DEVICE, }, diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c index 4d6c7a574c1..15811601f03 100644 --- a/arch/arm/mach-s3c2440/mach-osiris.c +++ b/arch/arm/mach-s3c2440/mach-osiris.c @@ -16,6 +16,7 @@ #include <linux/timer.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/sysdev.h> #include <linux/serial_core.h> #include <asm/mach/arch.h> @@ -65,6 +66,11 @@ static struct map_desc osiris_iodesc[] __initdata = { /* CPLD control registers */ { + .virtual = (u32)OSIRIS_VA_CTRL0, + .pfn = __phys_to_pfn(OSIRIS_PA_CTRL0), + .length = SZ_16K, + .type = MT_DEVICE, + }, { .virtual = (u32)OSIRIS_VA_CTRL1, .pfn = __phys_to_pfn(OSIRIS_PA_CTRL1), .length = SZ_16K, @@ -74,6 +80,11 @@ static struct map_desc osiris_iodesc[] __initdata = { .pfn = __phys_to_pfn(OSIRIS_PA_CTRL2), .length = SZ_16K, .type = MT_DEVICE, + }, { + .virtual = (u32)OSIRIS_VA_IDREG, + .pfn = __phys_to_pfn(OSIRIS_PA_IDREG), + .length = SZ_16K, + .type = MT_DEVICE, }, }; @@ -195,13 +206,13 @@ static void osiris_nand_select(struct s3c2410_nand_set *set, int slot) pr_debug("osiris_nand: selecting slot %d (set %p,%p)\n", slot, set, set->nr_map); - tmp = __raw_readb(OSIRIS_VA_CTRL1); - tmp &= ~OSIRIS_CTRL1_NANDSEL; + tmp = __raw_readb(OSIRIS_VA_CTRL0); + tmp &= ~OSIRIS_CTRL0_NANDSEL; tmp |= slot; - pr_debug("osiris_nand: ctrl1 now %02x\n", tmp); + pr_debug("osiris_nand: ctrl0 now %02x\n", tmp); - __raw_writeb(tmp, OSIRIS_VA_CTRL1); + __raw_writeb(tmp, OSIRIS_VA_CTRL0); } static struct s3c2410_platform_nand osiris_nand_info = { @@ -235,10 +246,45 @@ static struct platform_device osiris_pcmcia = { .resource = osiris_pcmcia_resource, }; +/* Osiris power management device */ + +#ifdef CONFIG_PM +static unsigned char pm_osiris_ctrl0; + +static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state) +{ + pm_osiris_ctrl0 = __raw_readb(OSIRIS_VA_CTRL0); + return 0; +} + +static int osiris_pm_resume(struct sys_device *sd) +{ + if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8) + __raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1); + + return 0; +} + +#else +#define osiris_pm_suspend NULL +#define osiris_pm_resume NULL +#endif + +static struct sysdev_class osiris_pm_sysclass = { + set_kset_name("mach-osiris"), + .suspend = osiris_pm_suspend, + .resume = osiris_pm_resume, +}; + +static struct sys_device osiris_pm_sysdev = { + .cls = &osiris_pm_sysclass, +}; + /* Standard Osiris devices */ static struct platform_device *osiris_devices[] __initdata = { &s3c_device_i2c, + &s3c_device_wdt, &s3c_device_nand, &osiris_pcmcia, }; @@ -288,6 +334,9 @@ static void __init osiris_map_io(void) static void __init osiris_init(void) { + sysdev_class_register(&osiris_pm_sysclass); + sysdev_register(&osiris_pm_sysdev); + platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices)); }; @@ -299,5 +348,6 @@ MACHINE_START(OSIRIS, "Simtec-OSIRIS") .map_io = osiris_map_io, .init_machine = osiris_init, .init_irq = s3c24xx_init_irq, + .init_machine = osiris_init, .timer = &s3c24xx_timer, MACHINE_END diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c index 5955efb5de8..58402948c47 100644 --- a/arch/arm/mach-s3c2443/clock.c +++ b/arch/arm/mach-s3c2443/clock.c @@ -394,7 +394,7 @@ static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate) return 0; } -struct clk clk_usb_bus_host = { +static struct clk clk_usb_bus_host = { .name = "usb-bus-host-parent", .id = -1, .parent = &clk_esysclk, @@ -758,7 +758,6 @@ static struct clk init_clocks[] = { .parent = &clk_h, .enable = s3c2443_clkcon_enable_h, .ctrlbit = S3C2443_HCLKCON_CFC, - .ctrlbit = S3C2443_HCLKCON_HSMMC, }, { .name = "ssmc", .id = -1, diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index d7c038a0256..4cbf9468f65 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -139,12 +139,12 @@ static u_int neponset_get_mctrl(struct uart_port *port) return ret; } -static struct sa1100_port_fns neponset_port_fns __initdata = { +static struct sa1100_port_fns neponset_port_fns __devinitdata = { .set_mctrl = neponset_set_mctrl, .get_mctrl = neponset_get_mctrl, }; -static int neponset_probe(struct platform_device *dev) +static int __devinit neponset_probe(struct platform_device *dev) { sa1100_register_uart_fns(&neponset_port_fns); diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 5f472a8b406..e7904bc92c7 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -379,7 +379,7 @@ config CPU_V7 select CPU_CP15_MMU select CPU_HAS_ASID select CPU_COPY_V6 if MMU - select CPU_TLB_V6 if MMU + select CPU_TLB_V7 if MMU # Figure out what processor architecture version we should be using. # This defines the compiler instruction set which depends on the machine type. @@ -498,6 +498,9 @@ config CPU_TLB_V4WBI config CPU_TLB_V6 bool +config CPU_TLB_V7 + bool + endif config CPU_HAS_ASID diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index b5bd335ff14..762702765fc 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_CPU_TLB_V4WT) += tlb-v4.o obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o +obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 36440c89958..074b7cb0774 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c @@ -630,7 +630,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) fs = get_fs(); set_fs(KERNEL_DS); - if thumb_mode(regs) { + if (thumb_mode(regs)) { fault = __get_user(tinstr, (u16 *)(instrptr & ~1)); if (!(fault)) instr = thumb2arm(tinstr); diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index dd823dd4a37..718f4782ee8 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -256,7 +256,7 @@ __v7_proc_info: .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP .long cpu_v7_name .long v7_processor_functions - .long v6wbi_tlb_fns + .long v7wbi_tlb_fns .long v6_user_fns .long v7_cache_fns .size __v7_proc_info, . - __v7_proc_info diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S new file mode 100644 index 00000000000..b56dda8052f --- /dev/null +++ b/arch/arm/mm/tlb-v7.S @@ -0,0 +1,88 @@ +/* + * linux/arch/arm/mm/tlb-v7.S + * + * Copyright (C) 1997-2002 Russell King + * Modified for ARMv7 by Catalin Marinas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM architecture version 6 TLB handling functions. + * These assume a split I/D TLB. + */ +#include <linux/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/page.h> +#include <asm/tlbflush.h> +#include "proc-macros.S" + +/* + * v7wbi_flush_user_tlb_range(start, end, vma) + * + * Invalidate a range of TLB entries in the specified address space. + * + * - start - start address (may not be aligned) + * - end - end address (exclusive, may not be aligned) + * - vma - vma_struct describing address range + * + * It is assumed that: + * - the "Invalidate single entry" instruction will invalidate + * both the I and the D TLBs on Harvard-style TLBs + */ +ENTRY(v7wbi_flush_user_tlb_range) + vma_vm_mm r3, r2 @ get vma->vm_mm + mmid r3, r3 @ get vm_mm->context.id + dsb + mov r0, r0, lsr #PAGE_SHIFT @ align address + mov r1, r1, lsr #PAGE_SHIFT + asid r3, r3 @ mask ASID + orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA + mov r1, r1, lsl #PAGE_SHIFT + vma_vm_flags r2, r2 @ get vma->vm_flags +1: + mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA (was 1) + tst r2, #VM_EXEC @ Executable area ? + mcrne p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA (was 1) + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + mov ip, #0 + mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB + dsb + mov pc, lr + +/* + * v7wbi_flush_kern_tlb_range(start,end) + * + * Invalidate a range of kernel TLB entries + * + * - start - start address (may not be aligned) + * - end - end address (exclusive, may not be aligned) + */ +ENTRY(v7wbi_flush_kern_tlb_range) + dsb + mov r0, r0, lsr #PAGE_SHIFT @ align address + mov r1, r1, lsr #PAGE_SHIFT + mov r0, r0, lsl #PAGE_SHIFT + mov r1, r1, lsl #PAGE_SHIFT +1: + mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA + mcr p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA + add r0, r0, #PAGE_SZ + cmp r0, r1 + blo 1b + mov r2, #0 + mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB + dsb + isb + mov pc, lr + + .section ".text.init", #alloc, #execinstr + + .type v7wbi_tlb_fns, #object +ENTRY(v7wbi_tlb_fns) + .long v7wbi_flush_user_tlb_range + .long v7wbi_flush_kern_tlb_range + .long v6wbi_tlb_flags + .size v7wbi_tlb_fns, . - v7wbi_tlb_fns diff --git a/arch/arm/nwfpe/softfloat.h b/arch/arm/nwfpe/softfloat.h index 0a3067452cd..260fe29d73f 100644 --- a/arch/arm/nwfpe/softfloat.h +++ b/arch/arm/nwfpe/softfloat.h @@ -273,4 +273,7 @@ static inline flag float64_lt_nocheck(float64 a, float64 b) extern flag float32_is_nan( float32 a ); extern flag float64_is_nan( float64 a ); +extern int32 float64_to_uint32( struct roundingData *roundData, float64 a ); +extern int32 float64_to_uint32_round_to_zero( float64 a ); + #endif diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c index 89850071824..75bae067922 100644 --- a/arch/arm/oprofile/op_model_mpcore.c +++ b/arch/arm/oprofile/op_model_mpcore.c @@ -200,8 +200,10 @@ static int em_call_function(int (*fn)(void)) data.fn = fn; data.ret = 0; + preempt_disable(); smp_call_function(em_func, &data, 1, 1); em_func(&data); + preempt_enable(); return data.ret; } @@ -257,8 +259,13 @@ static void em_stop(void) */ static void em_route_irq(int irq, unsigned int cpu) { - irq_desc[irq].affinity = cpumask_of_cpu(cpu); - irq_desc[irq].chip->set_affinity(irq, cpumask_of_cpu(cpu)); + struct irq_desc *desc = irq_desc + irq; + cpumask_t mask = cpumask_of_cpu(cpu); + + spin_lock_irq(&desc->lock); + desc->affinity = mask; + desc->chip->set_affinity(irq, mask); + spin_unlock_irq(&desc->lock); } static int em_setup(void) diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index ca2a5ad19ea..806ce26d524 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -29,6 +29,10 @@ do_vfp: add r10, r10, #TI_VFPSTATE @ r10 = workspace ldr pc, [r4] @ call VFP entry point +ENTRY(vfp_null_entry) + mov pc, lr +ENDPROC(vfp_null_entry) + .LCvfp: .word vfp_vector diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index f1e5951dc72..1106b5f9cf1 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -26,8 +26,9 @@ */ void vfp_testing_entry(void); void vfp_support_entry(void); +void vfp_null_entry(void); -void (*vfp_vector)(void) = vfp_testing_entry; +void (*vfp_vector)(void) = vfp_null_entry; union vfp_state *last_VFP_context[NR_CPUS]; /* @@ -321,8 +322,10 @@ static int __init vfp_init(void) * The handler is already setup to just log calls, so * we just need to read the VFPSID register. */ + vfp_vector = vfp_testing_entry; vfpsid = fmrx(FPSID); barrier(); + vfp_vector = vfp_null_entry; printk(KERN_INFO "VFP support v0.3: "); if (VFP_arch) { diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c index 11ba75a0522..de7688cfd57 100644 --- a/arch/h8300/kernel/sys_h8300.c +++ b/arch/h8300/kernel/sys_h8300.c @@ -288,9 +288,9 @@ asmlinkage void syscall_print(void *dummy,...) int kernel_execve(const char *filename, char *const argv[], char *const envp[]) { register long res __asm__("er0"); + register char *const *_c __asm__("er3") = envp; + register char *const *_b __asm__("er2") = argv; register const char * _a __asm__("er1") = filename; - register void *_b __asm__("er2") = argv; - register void *_c __asm__("er3") = envp; __asm__ __volatile__ ("mov.l %1,er0\n\t" "trapa #0\n\t" : "=r" (res) diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c index 300e3279ca5..f97183011c2 100644 --- a/arch/h8300/kernel/traps.c +++ b/arch/h8300/kernel/traps.c @@ -136,7 +136,7 @@ void show_stack(struct task_struct *task, unsigned long *esp) printk("\nCall Trace:"); i = 0; stack = esp; - while (((unsigned long)stack & (THREAD_SIZE - 1)) == 0) { + while (((unsigned long)stack & (THREAD_SIZE - 1)) != 0) { addr = *stack++; /* * If the address is either in the text segment of the diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index c2d54b80223..8770a5d0b14 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -891,7 +891,7 @@ config PHYSICAL_ALIGN Don't change this unless you know what you are doing. config HOTPLUG_CPU - bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + bool "Support for suspend on SMP and hot-pluggable CPUs (EXPERIMENTAL)" depends on SMP && HOTPLUG && EXPERIMENTAL && !X86_VOYAGER ---help--- Say Y here to experiment with turning CPUs off and on, and to diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index 1cf466df330..7202b98aac4 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c @@ -734,10 +734,13 @@ void mtrr_ap_init(void) */ void mtrr_save_state(void) { - if (smp_processor_id() == 0) + int cpu = get_cpu(); + + if (cpu == 0) mtrr_save_fixed_ranges(NULL); else smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1, 1); + put_cpu(); } static int __init mtrr_init_finialize(void) diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index 83f825f2e2d..d865d041bea 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -478,7 +478,7 @@ static int __init microcode_dev_init (void) return 0; } -static void __exit microcode_dev_exit (void) +static void microcode_dev_exit (void) { misc_deregister(µcode_dev); } diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index 50dfc65319c..5513f8d5b5b 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c @@ -89,6 +89,14 @@ static int __init set_bios_reboot(struct dmi_system_id *d) } static struct dmi_system_id __initdata reboot_dmi_table[] = { + { /* Handle problems with rebooting on Dell E520's */ + .callback = set_bios_reboot, + .ident = "Dell E520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"), + }, + }, { /* Handle problems with rebooting on Dell 1300's */ .callback = set_bios_reboot, .ident = "Dell PowerEdge 1300", diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 08f07a74a9d..88baed1e7e8 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -943,10 +943,9 @@ exit: static void smp_tune_scheduling(void) { - unsigned long cachesize; /* kB */ - if (cpu_khz) { - cachesize = boot_cpu_data.x86_cache_size; + /* cache size in kB */ + long cachesize = boot_cpu_data.x86_cache_size; if (cachesize > 0) max_cache_size = cachesize * 1024; diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c index c8726c424b3..c12720d7cbc 100644 --- a/arch/i386/kernel/vmi.c +++ b/arch/i386/kernel/vmi.c @@ -27,6 +27,7 @@ #include <linux/bootmem.h> #include <linux/mm.h> #include <linux/highmem.h> +#include <linux/sched.h> #include <asm/vmi.h> #include <asm/io.h> #include <asm/fixmap.h> diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c index e932d3485ae..58a477baec3 100644 --- a/arch/i386/mach-generic/bigsmp.c +++ b/arch/i386/mach-generic/bigsmp.c @@ -21,7 +21,7 @@ static int dmi_bigsmp; /* can be set by dmi scanners */ -static __init int hp_ht_bigsmp(struct dmi_system_id *d) +static int hp_ht_bigsmp(struct dmi_system_id *d) { #ifdef CONFIG_X86_GENERICARCH printk(KERN_NOTICE "%s detected: force use of apic=bigsmp\n", d->ident); @@ -31,7 +31,7 @@ static __init int hp_ht_bigsmp(struct dmi_system_id *d) } -static struct dmi_system_id __initdata bigsmp_dmi_table[] = { +static struct dmi_system_id bigsmp_dmi_table[] = { { hp_ht_bigsmp, "HP ProLiant DL760 G2", { DMI_MATCH(DMI_BIOS_VENDOR, "HP"), DMI_MATCH(DMI_BIOS_VERSION, "P44-"), @@ -45,7 +45,7 @@ static struct dmi_system_id __initdata bigsmp_dmi_table[] = { }; -static int __init probe_bigsmp(void) +static int probe_bigsmp(void) { if (def_to_bigsmp) dmi_bigsmp = 1; diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c index ddf8fa3bbd0..1853524c8b5 100644 --- a/arch/i386/math-emu/fpu_entry.c +++ b/arch/i386/math-emu/fpu_entry.c @@ -754,7 +754,7 @@ int save_i387_soft(void *s387, struct _fpstate __user * buf) return -1; if ( offset ) if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset)) - return -1 + return -1; RE_ENTRANT_CHECK_ON; return 1; diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 29d7d61543a..1ecb3e43b52 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -458,6 +458,11 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { + /* + * It's possible to have interrupts off here. + */ + local_irq_enable(); + /* * Valid to do another page fault here because this one came * from user space. diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c index a7c0783b269..11b7a51566a 100644 --- a/arch/i386/oprofile/nmi_int.c +++ b/arch/i386/oprofile/nmi_int.c @@ -154,7 +154,7 @@ static int allocate_msrs(void) size_t counters_size = sizeof(struct op_msr) * model->num_counters; int i; - for_each_online_cpu(i) { + for_each_possible_cpu(i) { cpu_msrs[i].counters = kmalloc(counters_size, GFP_KERNEL); if (!cpu_msrs[i].counters) { success = 0; @@ -211,8 +211,14 @@ static int nmi_setup(void) /* Assume saved/restored counters are the same on all CPUs */ model->fill_in_addresses(&cpu_msrs[0]); for_each_possible_cpu (cpu) { - if (cpu != 0) - cpu_msrs[cpu] = cpu_msrs[0]; + if (cpu != 0) { + memcpy(cpu_msrs[cpu].counters, cpu_msrs[0].counters, + sizeof(struct op_msr) * model->num_counters); + + memcpy(cpu_msrs[cpu].controls, cpu_msrs[0].controls, + sizeof(struct op_msr) * model->num_controls); + } + } on_each_cpu(nmi_save_registers, NULL, 0, 1); on_each_cpu(nmi_cpu_setup, NULL, 0, 1); diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index b62eafb997b..b95b42950ed 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c @@ -436,3 +436,14 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, pci_early_fixup_cyrix_5530); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, pci_early_fixup_cyrix_5530); + +/* + * Siemens Nixdorf AG FSC Multiprocessor Interrupt Controller: + * prevent update of the BAR0, which doesn't look like a normal BAR. + */ +static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) +{ + dev->resource[0].flags |= IORESOURCE_PCI_FIXED; +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, + pci_siemens_interrupt_controller); diff --git a/arch/ia64/kernel/acpi-processor.c b/arch/ia64/kernel/acpi-processor.c index 4d4993a47e5..5a216c01992 100644 --- a/arch/ia64/kernel/acpi-processor.c +++ b/arch/ia64/kernel/acpi-processor.c @@ -44,7 +44,7 @@ static void init_intel_pdc(struct acpi_processor *pr) buf[0] = ACPI_PDC_REVISION_ID; buf[1] = 1; - buf[2] |= ACPI_PDC_EST_CAPABILITY_SMP; + buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; obj->type = ACPI_TYPE_BUFFER; obj->buffer.length = 12; diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index c4784494970..103dd8edda7 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -67,7 +67,8 @@ EXPORT_SYMBOL(pm_power_off); unsigned int acpi_cpei_override; unsigned int acpi_cpei_phys_cpuid; -const char *acpi_get_sysname(void) +const char __init * +acpi_get_sysname(void) { #ifdef CONFIG_IA64_GENERIC unsigned long rsdp_phys; diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index d1c3ed9943e..af73b8dfde2 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -763,6 +763,9 @@ get_wchan (struct task_struct *p) unsigned long ip; int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + /* * Note: p may not be a blocked task (it could be current or * another process running on some other CPU. Rather than @@ -773,6 +776,8 @@ get_wchan (struct task_struct *p) */ unw_init_from_blocked_task(&info, p); do { + if (p->state == TASK_RUNNING) + return 0; if (unw_unwind(&info) < 0) return 0; unw_get_ip(&info, &ip); diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 542958079f1..3c9d8e6089c 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -370,7 +370,7 @@ smp_setup_percpu_timer (void) { } -static void __devinit +static void __cpuinit smp_callin (void) { int cpuid, phys_id, itc_master; @@ -456,7 +456,7 @@ smp_callin (void) /* * Activate a secondary processor. head.S calls this. */ -int __devinit +int __cpuinit start_secondary (void *unused) { /* Early console may use I/O ports */ diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 7d3dd6cdafa..b0b08b5f3ec 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -1860,7 +1860,7 @@ int unw_unwind (struct unw_frame_info *info) { unsigned long prev_ip, prev_sp, prev_bsp; - unsigned long ip, pr, num_regs; + unsigned long ip, pr, num_regs, rp_loc, pfs_loc; STAT(unsigned long start, flags;) int retval; @@ -1870,14 +1870,16 @@ unw_unwind (struct unw_frame_info *info) prev_sp = info->sp; prev_bsp = info->bsp; - /* restore the ip */ - if (!info->rp_loc) { + /* validate the return IP pointer */ + rp_loc = (unsigned long) info->rp_loc; + if ((rp_loc < info->regstk.limit) || (rp_loc > info->regstk.top)) { /* FIXME: should really be level 0 but it occurs too often. KAO */ UNW_DPRINT(1, "unwind.%s: failed to locate return link (ip=0x%lx)!\n", __FUNCTION__, info->ip); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } + /* restore the ip */ ip = info->ip = *info->rp_loc; if (ip < GATE_ADDR) { UNW_DPRINT(2, "unwind.%s: reached user-space (ip=0x%lx)\n", __FUNCTION__, ip); @@ -1885,12 +1887,14 @@ unw_unwind (struct unw_frame_info *info) return -1; } - /* restore the cfm: */ - if (!info->pfs_loc) { + /* validate the previous stack frame pointer */ + pfs_loc = (unsigned long) info->pfs_loc; + if ((pfs_loc < info->regstk.limit) || (pfs_loc > info->regstk.top)) { UNW_DPRINT(0, "unwind.%s: failed to locate ar.pfs!\n", __FUNCTION__); STAT(unw.stat.api.unwind_time += ia64_get_itc() - start; local_irq_restore(flags)); return -1; } + /* restore the cfm: */ info->cfm_loc = info->pfs_loc; /* restore the bsp: */ @@ -1992,13 +1996,16 @@ init_frame_info (struct unw_frame_info *info, struct task_struct *t, memset(info, 0, sizeof(*info)); rbslimit = (unsigned long) t + IA64_RBS_OFFSET; + stklimit = (unsigned long) t + IA64_STK_OFFSET; + rbstop = sw->ar_bspstore; - if (rbstop - (unsigned long) t >= IA64_STK_OFFSET) + if (rbstop > stklimit || rbstop < rbslimit) rbstop = rbslimit; - stklimit = (unsigned long) t + IA64_STK_OFFSET; if (stktop <= rbstop) stktop = rbstop; + if (stktop > stklimit) + stktop = stklimit; info->regstk.limit = rbslimit; info->regstk.top = rbstop; diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 3549f3b4259..73696b4a2ee 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -354,10 +354,13 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus) acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window, &windows); - controller->window = kmalloc_node(sizeof(*controller->window) * windows, - GFP_KERNEL, controller->node); - if (!controller->window) - goto out2; + if (windows) { + controller->window = + kmalloc_node(sizeof(*controller->window) * windows, + GFP_KERNEL, controller->node); + if (!controller->window) + goto out2; + } name = kmalloc(16, GFP_KERNEL); if (!name) diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index a574fcd163d..684b1c984a4 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -194,7 +194,7 @@ void __init early_sn_setup(void) } extern int platform_intr_list[]; -static int __initdata shub_1_1_found; +static int __cpuinitdata shub_1_1_found; /* * sn_check_for_wars diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index b8536c7c087..85cdd23b044 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -355,8 +355,9 @@ config RMW_INSNS adventurous. config SINGLE_MEMORY_CHUNK - bool "Use one physical chunk of memory only" - depends on ADVANCED && !SUN3 + bool "Use one physical chunk of memory only" if ADVANCED && !SUN3 + default y if SUN3 + select NEED_MULTIPLE_NODES help Ignore all but the first contiguous chunk of physical memory for VM purposes. This will save a few bytes kernel size and may speed up @@ -377,6 +378,14 @@ config 060_WRITETHROUGH is hardwired on. The 53c710 SCSI driver is known to suffer from this problem. +config ARCH_DISCONTIGMEM_ENABLE + def_bool !SINGLE_MEMORY_CHUNK + +config NODES_SHIFT + int + default "3" + depends on !SINGLE_MEMORY_CHUNK + source "mm/Kconfig" endmenu diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index c20831a7e1a..aa383a5ea7a 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -19,6 +19,7 @@ COMPILE_ARCH = $(shell uname -m) # override top level makefile AS += -m68020 LDFLAGS := -m m68kelf +LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries CROSS_COMPILE = m68k-linux-gnu- diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 0b68ab8d63d..a806208c7fb 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile @@ -9,13 +9,12 @@ else endif extra-y += vmlinux.lds -obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ +obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \ sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o devres-y = ../../../kernel/irq/devres.o obj-$(CONFIG_PCI) += bios32.o -obj-$(CONFIG_MODULES) += module.o obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo EXTRA_AFLAGS := -traditional diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c index 3b1a2ff61dd..774862bc697 100644 --- a/arch/m68k/kernel/module.c +++ b/arch/m68k/kernel/module.c @@ -1,3 +1,9 @@ +/* + * 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/moduleloader.h> #include <linux/elf.h> #include <linux/vmalloc.h> @@ -11,6 +17,8 @@ #define DEBUGP(fmt...) #endif +#ifdef CONFIG_MODULES + void *module_alloc(unsigned long size) { if (size == 0) @@ -118,11 +126,32 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, - struct module *me) + struct module *mod) { + module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end); + return 0; } void module_arch_cleanup(struct module *mod) { } + +#endif /* CONFIG_MODULES */ + +void module_fixup(struct module *mod, struct m68k_fixup_info *start, + struct m68k_fixup_info *end) +{ + struct m68k_fixup_info *fixup; + + for (fixup = start; fixup < end; fixup++) { + switch (fixup->type) { + case m68k_fixup_memoffset: + *(u32 *)fixup->addr = m68k_memoffset; + break; + case m68k_fixup_vnode_shift: + *(u16 *)fixup->addr += m68k_virt_to_node_shift; + break; + } + } +} diff --git a/arch/m68k/kernel/module.lds b/arch/m68k/kernel/module.lds new file mode 100644 index 00000000000..fda94fa3824 --- /dev/null +++ b/arch/m68k/kernel/module.lds @@ -0,0 +1,7 @@ +SECTIONS { + .m68k_fixup : { + __start_fixup = .; + *(.m68k_fixup) + __stop_fixup = .; + } +} diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 61031935669..215c7bd4392 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -60,14 +60,12 @@ extern unsigned long availmem; int m68k_num_memory; int m68k_realnum_memory; EXPORT_SYMBOL(m68k_realnum_memory); -#ifdef CONFIG_SINGLE_MEMORY_CHUNK unsigned long m68k_memoffset; EXPORT_SYMBOL(m68k_memoffset); -#endif struct mem_info m68k_memory[NUM_MEMINFO]; EXPORT_SYMBOL(m68k_memory); -static struct mem_info m68k_ramdisk; +struct mem_info m68k_ramdisk; static char m68k_command_line[CL_SIZE]; @@ -208,9 +206,6 @@ static void __init m68k_parse_bootinfo(const struct bi_record *record) void __init setup_arch(char **cmdline_p) { extern int _etext, _edata, _end; -#ifndef CONFIG_SUN3 - unsigned long endmem, startmem; -#endif int i; /* The bootinfo is located right after the kernel bss */ @@ -320,30 +315,16 @@ void __init setup_arch(char **cmdline_p) panic("No configuration setup"); } -#ifndef CONFIG_SUN3 - startmem= m68k_memory[0].addr; - endmem = startmem + m68k_memory[0].size; - high_memory = (void *)PAGE_OFFSET; - for (i = 0; i < m68k_num_memory; i++) { - m68k_memory[i].size &= MASK_256K; - if (m68k_memory[i].addr < startmem) - startmem = m68k_memory[i].addr; - if (m68k_memory[i].addr+m68k_memory[i].size > endmem) - endmem = m68k_memory[i].addr+m68k_memory[i].size; - high_memory += m68k_memory[i].size; - } - - availmem += init_bootmem_node(NODE_DATA(0), availmem >> PAGE_SHIFT, - startmem >> PAGE_SHIFT, endmem >> PAGE_SHIFT); - - for (i = 0; i < m68k_num_memory; i++) - free_bootmem(m68k_memory[i].addr, m68k_memory[i].size); - - reserve_bootmem(m68k_memory[0].addr, availmem - m68k_memory[0].addr); + paging_init(); +#ifndef CONFIG_SUN3 + for (i = 1; i < m68k_num_memory; i++) + free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr, + m68k_memory[i].size); #ifdef CONFIG_BLK_DEV_INITRD if (m68k_ramdisk.size) { - reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size); + reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)), + m68k_ramdisk.addr, m68k_ramdisk.size); initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); initrd_end = initrd_start + m68k_ramdisk.size; printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); @@ -362,8 +343,6 @@ void __init setup_arch(char **cmdline_p) #endif /* !CONFIG_SUN3 */ - paging_init(); - /* set ISA defs early as possible */ #if defined(CONFIG_ISA) && defined(MULTI_ISA) #if defined(CONFIG_Q40) diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds index 78f139226a1..40f02b128f2 100644 --- a/arch/m68k/kernel/vmlinux-std.lds +++ b/arch/m68k/kernel/vmlinux-std.lds @@ -60,6 +60,11 @@ SECTIONS __con_initcall_start = .; .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; + .m68k_fixup : { + __start_fixup = .; + *(.m68k_fixup) + __stop_fixup = .; + } SECURITY_INIT #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds index c8999b2db23..f06425b6d20 100644 --- a/arch/m68k/kernel/vmlinux-sun3.lds +++ b/arch/m68k/kernel/vmlinux-sun3.lds @@ -54,6 +54,11 @@ __init_begin = .; __con_initcall_start = .; .con_initcall.init : { *(.con_initcall.init) } __con_initcall_end = .; + .m68k_fixup : { + __start_fixup = .; + *(.m68k_fixup) + __stop_fixup = .; + } SECURITY_INIT #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(8192); diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c index 7a5bed5bdc5..e8a57138b4a 100644 --- a/arch/m68k/mac/debug.c +++ b/arch/m68k/mac/debug.c @@ -71,7 +71,7 @@ void mac_debugging_short(int pos, short num) /* calculate current offset */ pengoffset = (unsigned char *)mac_videobase + - (150+line*2) * mac_rowbytes) + 80 * peng; + (150+line*2) * mac_rowbytes + 80 * peng; pptr = pengoffset; diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index ab90213e5c5..f1de19e1dde 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -7,6 +7,7 @@ * to motorola.c and sun3mmu.c */ +#include <linux/module.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/mm.h> @@ -31,6 +32,37 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); +static bootmem_data_t __initdata bootmem_data[MAX_NUMNODES]; + +pg_data_t pg_data_map[MAX_NUMNODES]; +EXPORT_SYMBOL(pg_data_map); + +int m68k_virt_to_node_shift; + +#ifndef CONFIG_SINGLE_MEMORY_CHUNK +pg_data_t *pg_data_table[65]; +EXPORT_SYMBOL(pg_data_table); +#endif + +void m68k_setup_node(int node) +{ +#ifndef CONFIG_SINGLE_MEMORY_CHUNK + struct mem_info *info = m68k_memory + node; + int i, end; + + i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift(); + end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift(); + for (; i <= end; i++) { + if (pg_data_table[i]) + printk("overlap at %u for chunk %u\n", i, node); + pg_data_table[i] = pg_data_map + node; + } +#endif + pg_data_map[node].bdata = bootmem_data + node; + node_set_online(node); +} + + /* * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. @@ -40,52 +72,51 @@ void *empty_zero_page; void show_mem(void) { - unsigned long i; - int free = 0, total = 0, reserved = 0, shared = 0; - int cached = 0; - - printk("\nMem-info:\n"); - show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - i = max_mapnr; - while (i-- > 0) { - total++; - if (PageReserved(mem_map+i)) - reserved++; - else if (PageSwapCache(mem_map+i)) - cached++; - else if (!page_count(mem_map+i)) - free++; - else - shared += page_count(mem_map+i) - 1; - } - printk("%d pages of RAM\n",total); - printk("%d free pages\n",free); - printk("%d reserved pages\n",reserved); - printk("%d pages shared\n",shared); - printk("%d pages swap cached\n",cached); + pg_data_t *pgdat; + int free = 0, total = 0, reserved = 0, shared = 0; + int cached = 0; + int i; + + printk("\nMem-info:\n"); + show_free_areas(); + printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); + for_each_online_pgdat(pgdat) { + for (i = 0; i < pgdat->node_spanned_pages; i++) { + struct page *page = pgdat->node_mem_map + i; + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (!page_count(page)) + free++; + else + shared += page_count(page) - 1; + } + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); } extern void init_pointer_table(unsigned long ptable); /* References to section boundaries */ -extern char _text, _etext, _edata, __bss_start, _end; -extern char __init_begin, __init_end; +extern char _text[], _etext[]; +extern char __init_begin[], __init_end[]; extern pmd_t *zero_pgtable; void __init mem_init(void) { + pg_data_t *pgdat; int codepages = 0; int datapages = 0; int initpages = 0; - unsigned long tmp; -#ifndef CONFIG_SUN3 int i; -#endif - - max_mapnr = num_physpages = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT); #ifdef CONFIG_ATARI if (MACH_IS_ATARI) @@ -93,19 +124,25 @@ void __init mem_init(void) #endif /* this will put all memory onto the freelists */ - totalram_pages = free_all_bootmem(); - - for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) { - if (PageReserved(virt_to_page(tmp))) { - if (tmp >= (unsigned long)&_text - && tmp < (unsigned long)&_etext) + totalram_pages = num_physpages = 0; + for_each_online_pgdat(pgdat) { + num_physpages += pgdat->node_present_pages; + + totalram_pages += free_all_bootmem_node(pgdat); + for (i = 0; i < pgdat->node_spanned_pages; i++) { + struct page *page = pgdat->node_mem_map + i; + char *addr = page_to_virt(page); + + if (!PageReserved(page)) + continue; + if (addr >= _text && + addr < _etext) codepages++; - else if (tmp >= (unsigned long) &__init_begin - && tmp < (unsigned long) &__init_end) + else if (addr >= __init_begin && + addr < __init_end) initpages++; else datapages++; - continue; } } @@ -124,7 +161,7 @@ void __init mem_init(void) printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n", (unsigned long)nr_free_pages() << (PAGE_SHIFT-10), - max_mapnr << (PAGE_SHIFT-10), + totalram_pages << (PAGE_SHIFT-10), codepages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10)); diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index 13c0b4ad01e..b7473525b43 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -127,67 +127,6 @@ int free_pointer_table (pmd_t *ptable) return 0; } -#ifdef DEBUG_INVALID_PTOV -int mm_inv_cnt = 5; -#endif - -#ifndef CONFIG_SINGLE_MEMORY_CHUNK -/* - * The following two routines map from a physical address to a kernel - * virtual address and vice versa. - */ -unsigned long mm_vtop(unsigned long vaddr) -{ - int i=0; - unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET; - - do { - if (voff < m68k_memory[i].size) { -#ifdef DEBUGPV - printk ("VTOP(%p)=%lx\n", vaddr, - m68k_memory[i].addr + voff); -#endif - return m68k_memory[i].addr + voff; - } - voff -= m68k_memory[i].size; - } while (++i < m68k_num_memory); - - /* As a special case allow `__pa(high_memory)'. */ - if (voff == 0) - return m68k_memory[i-1].addr + m68k_memory[i-1].size; - - return -1; -} -EXPORT_SYMBOL(mm_vtop); - -unsigned long mm_ptov (unsigned long paddr) -{ - int i = 0; - unsigned long poff, voff = PAGE_OFFSET; - - do { - poff = paddr - m68k_memory[i].addr; - if (poff < m68k_memory[i].size) { -#ifdef DEBUGPV - printk ("PTOV(%lx)=%lx\n", paddr, poff + voff); -#endif - return poff + voff; - } - voff += m68k_memory[i].size; - } while (++i < m68k_num_memory); - -#ifdef DEBUG_INVALID_PTOV - if (mm_inv_cnt > 0) { - mm_inv_cnt--; - printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!\n", - paddr, __builtin_return_address(0)); - } -#endif - return -1; -} -EXPORT_SYMBOL(mm_ptov); -#endif - /* invalidate page in both caches */ static inline void clear040(unsigned long paddr) { @@ -354,15 +293,3 @@ void cache_push (unsigned long paddr, int len) } EXPORT_SYMBOL(cache_push); -#ifndef CONFIG_SINGLE_MEMORY_CHUNK -int mm_end_of_chunk (unsigned long addr, int len) -{ - int i; - - for (i = 0; i < m68k_num_memory; i++) - if (m68k_memory[i].addr + m68k_memory[i].size == addr + len) - return 1; - return 0; -} -EXPORT_SYMBOL(mm_end_of_chunk); -#endif diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index afcccdc6ad4..7d571a2b44d 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -43,6 +43,11 @@ unsigned long mm_cachebits; EXPORT_SYMBOL(mm_cachebits); #endif +/* size of memory already mapped in head.S */ +#define INIT_MAPPED_SIZE (4UL<<20) + +extern unsigned long availmem; + static pte_t * __init kernel_page_table(void) { pte_t *ptablep; @@ -98,19 +103,20 @@ static pmd_t * __init kernel_ptr_table(void) return last_pgtable; } -static unsigned long __init -map_chunk (unsigned long addr, long size) +static void __init map_node(int node) { #define PTRTREESIZE (256*1024) #define ROOTTREESIZE (32*1024*1024) - static unsigned long virtaddr = PAGE_OFFSET; - unsigned long physaddr; + unsigned long physaddr, virtaddr, size; pgd_t *pgd_dir; pmd_t *pmd_dir; pte_t *pte_dir; - physaddr = (addr | m68k_supervisor_cachemode | - _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY); + size = m68k_memory[node].size; + physaddr = m68k_memory[node].addr; + virtaddr = (unsigned long)phys_to_virt(physaddr); + physaddr |= m68k_supervisor_cachemode | + _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY; if (CPU_IS_040_OR_060) physaddr |= _PAGE_GLOBAL040; @@ -190,8 +196,6 @@ map_chunk (unsigned long addr, long size) #ifdef DEBUG printk("\n"); #endif - - return virtaddr; } /* @@ -200,15 +204,16 @@ map_chunk (unsigned long addr, long size) */ void __init paging_init(void) { - int chunk; - unsigned long mem_avail = 0; unsigned long zones_size[MAX_NR_ZONES] = { 0, }; + unsigned long min_addr, max_addr; + unsigned long addr, size, end; + int i; #ifdef DEBUG { extern unsigned long availmem; - printk ("start of paging_init (%p, %lx, %lx, %lx)\n", - kernel_pg_dir, availmem, start_mem, end_mem); + printk ("start of paging_init (%p, %lx)\n", + kernel_pg_dir, availmem); } #endif @@ -222,24 +227,62 @@ void __init paging_init(void) pgprot_val(protection_map[i]) |= _PAGE_CACHE040; } + min_addr = m68k_memory[0].addr; + max_addr = min_addr + m68k_memory[0].size; + for (i = 1; i < m68k_num_memory;) { + if (m68k_memory[i].addr < min_addr) { + printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n", + m68k_memory[i].addr, m68k_memory[i].size); + printk("Fix your bootloader or use a memfile to make use of this area!\n"); + m68k_num_memory--; + memmove(m68k_memory + i, m68k_memory + i + 1, + (m68k_num_memory - i) * sizeof(struct mem_info)); + continue; + } + addr = m68k_memory[i].addr + m68k_memory[i].size; + if (addr > max_addr) + max_addr = addr; + i++; + } + m68k_memoffset = min_addr - PAGE_OFFSET; + m68k_virt_to_node_shift = fls(max_addr - min_addr - 1) - 6; + + module_fixup(NULL, __start_fixup, __stop_fixup); + flush_icache(); + + high_memory = phys_to_virt(max_addr); + + min_low_pfn = availmem >> PAGE_SHIFT; + max_low_pfn = max_addr >> PAGE_SHIFT; + + for (i = 0; i < m68k_num_memory; i++) { + addr = m68k_memory[i].addr; + end = addr + m68k_memory[i].size; + m68k_setup_node(i); + availmem = PAGE_ALIGN(availmem); + availmem += init_bootmem_node(NODE_DATA(i), + availmem >> PAGE_SHIFT, + addr >> PAGE_SHIFT, + end >> PAGE_SHIFT); + } + /* * Map the physical memory available into the kernel virtual - * address space. It may allocate some memory for page - * tables and thus modify availmem. + * address space. First initialize the bootmem allocator with + * the memory we already mapped, so map_node() has something + * to allocate. */ + addr = m68k_memory[0].addr; + size = m68k_memory[0].size; + free_bootmem_node(NODE_DATA(0), availmem, min(INIT_MAPPED_SIZE, size) - (availmem - addr)); + map_node(0); + if (size > INIT_MAPPED_SIZE) + free_bootmem_node(NODE_DATA(0), addr + INIT_MAPPED_SIZE, size - INIT_MAPPED_SIZE); - for (chunk = 0; chunk < m68k_num_memory; chunk++) { - mem_avail = map_chunk (m68k_memory[chunk].addr, - m68k_memory[chunk].size); - - } + for (i = 1; i < m68k_num_memory; i++) + map_node(i); flush_tlb_all(); -#ifdef DEBUG - printk ("memory available is %ldKB\n", mem_avail >> 10); - printk ("start_mem is %#lx\nvirtual_end is %#lx\n", - start_mem, end_mem); -#endif /* * initialize the bad page table and bad page to point @@ -256,14 +299,11 @@ void __init paging_init(void) #ifdef DEBUG printk ("before free_area_init\n"); #endif - zones_size[ZONE_DMA] = (mach_max_dma_address < (unsigned long)high_memory ? - (mach_max_dma_address+1) : (unsigned long)high_memory); - zones_size[ZONE_NORMAL] = (unsigned long)high_memory - zones_size[0]; - - zones_size[ZONE_DMA] = (zones_size[ZONE_DMA] - PAGE_OFFSET) >> PAGE_SHIFT; - zones_size[ZONE_NORMAL] >>= PAGE_SHIFT; - - free_area_init(zones_size); + for (i = 0; i < m68k_num_memory; i++) { + zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT; + free_area_init_node(i, pg_data_map + i, zones_size, + m68k_memory[i].addr >> PAGE_SHIFT, NULL); + } } extern char __init_begin, __init_end; diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c index 4851b8437a8..c0fbd278fbb 100644 --- a/arch/m68k/sun3/config.c +++ b/arch/m68k/sun3/config.c @@ -21,6 +21,7 @@ #include <asm/contregs.h> #include <asm/movs.h> #include <asm/pgtable.h> +#include <asm/pgalloc.h> #include <asm/sun3-head.h> #include <asm/sun3mmu.h> #include <asm/rtc.h> @@ -127,6 +128,7 @@ void __init sun3_bootmem_alloc(unsigned long memory_start, unsigned long memory_ high_memory = (void *)memory_end; availmem = memory_start; + m68k_setup_node(0); availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages); availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK; diff --git a/arch/m68knommu/platform/5307/timers.c b/arch/m68knommu/platform/5307/timers.c index 92e58070b01..fb66eadd589 100644 --- a/arch/m68knommu/platform/5307/timers.c +++ b/arch/m68knommu/platform/5307/timers.c @@ -62,10 +62,13 @@ void coldfire_tick(void) /***************************************************************************/ +static int ticks_per_intr; + void coldfire_timer_init(irq_handler_t handler) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); - __raw_writetrr(((MCF_BUSCLK / 16) / HZ), TA(MCFTIMER_TRR)); + ticks_per_intr = (MCF_BUSCLK / 16) / HZ; + __raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); @@ -81,11 +84,10 @@ void coldfire_timer_init(irq_handler_t handler) unsigned long coldfire_timer_offset(void) { - unsigned long trr, tcn, offset; + unsigned long tcn, offset; tcn = __raw_readw(TA(MCFTIMER_TCN)); - trr = __raw_readtrr(TA(MCFTIMER_TRR)); - offset = (tcn * (1000000 / HZ)) / trr; + offset = ((tcn + 1) * (1000000 / HZ)) / ticks_per_intr; /* Check if we just wrapped the counters and maybe missed a tick */ if ((offset < (1000000 / HZ / 2)) && mcf_timerirqpending(1)) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 0f09412e1b7..9528ee90640 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -747,9 +747,9 @@ config EARLY_PRINTK to print messages very early in the bootup process. This is useful for kernel debugging when your machine crashes very - early before the console code is initialized. For normal operation - it is not recommended because it looks on some machines ugly and - oesn't cooperate with an X server. You should normally N here, + early before the console code is initialized. For normal operation, + it is not recommended because it looks ugly on some machines and + doesn't cooperate with an X server. You should normally say N here, unless you want to debug such a crash. config SYS_HAS_EARLY_PRINTK diff --git a/arch/mips/emma2rh/markeins/setup.c b/arch/mips/emma2rh/markeins/setup.c index b29a4473923..2f060e1ed36 100644 --- a/arch/mips/emma2rh/markeins/setup.c +++ b/arch/mips/emma2rh/markeins/setup.c @@ -115,30 +115,6 @@ extern void markeins_irq_setup(void); static void inline __init markeins_sio_setup(void) { -#ifdef CONFIG_KGDB_8250 - struct uart_port emma_port; - - memset(&emma_port, 0, sizeof(emma_port)); - - emma_port.flags = - UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; - emma_port.iotype = UPIO_MEM; - emma_port.regshift = 4; /* I/O addresses are every 8 bytes */ - emma_port.uartclk = 18544000; /* Clock rate of the chip */ - - emma_port.line = 0; - emma_port.mapbase = KSEG1ADDR(EMMA2RH_PFUR0_BASE + 3); - emma_port.membase = (u8*)emma_port.mapbase; - early_serial_setup(&emma_port); - - emma_port.line = 1; - emma_port.mapbase = KSEG1ADDR(EMMA2RH_PFUR1_BASE + 3); - emma_port.membase = (u8*)emma_port.mapbase; - early_serial_setup(&emma_port); - - emma_port.irq = EMMA2RH_IRQ_PFUR1; - kgdb8250_add_port(1, &emma_port); -#endif } void __init plat_mem_setup(void) diff --git a/arch/mips/jmr3927/rbhma3100/kgdb_io.c b/arch/mips/jmr3927/rbhma3100/kgdb_io.c index 2604f2c9a96..342579cfdc0 100644 --- a/arch/mips/jmr3927/rbhma3100/kgdb_io.c +++ b/arch/mips/jmr3927/rbhma3100/kgdb_io.c @@ -36,7 +36,7 @@ #define TIMEOUT 0xffffff static int remoteDebugInitialized = 0; -static void debugInit(int baud) +static void debugInit(int baud); int putDebugChar(unsigned char c) { diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 37849edd064..06e04da211d 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -556,6 +556,16 @@ asmlinkage long sys32_sync_file_range(int fd, int __pad, flags); } +asmlinkage long sys32_fadvise64_64(int fd, int __pad, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + int flags) +{ + return sys_fadvise64_64(fd, + merge_64(a2, a3), merge_64(a4, a5), + flags); +} + save_static_function(sys32_clone); __attribute_used__ noinline static int _sys32_clone(nabi_no_regargs struct pt_regs regs) diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index cc566cf1224..06729596812 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -174,7 +174,7 @@ LEAF(_init_fpu) or t0, t1 mtc0 t0, CP0_STATUS #endif /* CONFIG_MIPS_MT_SMTC */ - fpu_enable_hazard + enable_fpu_hazard li t1, FPU_DEFAULT ctc1 t1, fcr31 diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index 0c9a9ff8cd2..ae985d1fcca 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S @@ -657,7 +657,11 @@ einval: li v0, -EINVAL sys sys_getcpu 3 sys sys_epoll_pwait 6 sys sys_ioprio_set 3 - sys sys_ioprio_get 2 + sys sys_ioprio_get 2 /* 4315 */ + sys sys_utimensat 4 + sys sys_signalfd 3 + sys sys_timerfd 4 + sys sys_eventfd 1 .endm /* We pre-compute the number of _instruction_ bytes needed to diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 23f3b118f71..7bcd5a1a85f 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S @@ -473,4 +473,8 @@ sys_call_table: PTR sys_epoll_pwait PTR sys_ioprio_set PTR sys_ioprio_get + PTR sys_utimensat /* 5275 */ + PTR sys_signalfd + PTR sys_timerfd + PTR sys_eventfd .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 6eac2833742..532a2f3b42f 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S @@ -299,7 +299,7 @@ EXPORT(sysn32_call_table) PTR sys_ni_syscall /* res. for afs_syscall */ PTR sys_ni_syscall /* res. for security */ PTR sys_gettid - PTR sys32_readahead + PTR sys_readahead PTR sys_setxattr /* 6180 */ PTR sys_lsetxattr PTR sys_fsetxattr @@ -399,4 +399,8 @@ EXPORT(sysn32_call_table) PTR compat_sys_epoll_pwait PTR sys_ioprio_set PTR sys_ioprio_get + PTR compat_sys_utimensat + PTR compat_sys_signalfd /* 5280 */ + PTR compat_sys_timerfd + PTR sys_eventfd .size sysn32_call_table,.-sysn32_call_table diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 7e74b412a78..6bbe0f4ed8b 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S @@ -459,7 +459,7 @@ sys_call_table: PTR sys_remap_file_pages PTR sys_set_tid_address PTR sys_restart_syscall - PTR sys_fadvise64_64 + PTR sys32_fadvise64_64 PTR compat_sys_statfs64 /* 4255 */ PTR compat_sys_fstatfs64 PTR compat_sys_timer_create @@ -521,4 +521,8 @@ sys_call_table: PTR compat_sys_epoll_pwait PTR sys_ioprio_set PTR sys_ioprio_get /* 4315 */ + PTR compat_sys_utimensat + PTR compat_sys_signalfd + PTR compat_sys_timerfd + PTR sys_eventfd .size sys_call_table,.-sys_call_table diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index c46e479c992..67edfa7ed93 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -68,7 +68,7 @@ extern ATTRIB_NORET void cpu_idle(void); * First C code run on the secondary CPUs after being started up by * the master. */ -asmlinkage void start_secondary(void) +asmlinkage __cpuinit void start_secondary(void) { unsigned int cpu; diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S index 921207c4a83..20938a4cb52 100644 --- a/arch/mips/kernel/smtc-asm.S +++ b/arch/mips/kernel/smtc-asm.S @@ -121,10 +121,7 @@ LEAF(self_ipi) subu t1,sp,PT_SIZE sw ra,PT_EPC(t1) sw a0,PT_PADSLOT4(t1) - LONG_L s0, TI_REGS($28) - LONG_S sp, TI_REGS($28) la t2,ipi_decode - LONG_S s0, TI_REGS($28) sw t2,PT_PADSLOT5(t1) /* Save pre-disable value of TCStatus */ sw t0,PT_TCSTATUS(t1) diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index b361edb83dc..21eb5993a19 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c @@ -611,12 +611,12 @@ void smtc_cpus_done(void) int setup_irq_smtc(unsigned int irq, struct irqaction * new, unsigned long hwmask) { +#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG unsigned int vpe = current_cpu_data.vpe_id; - irq_hwmask[irq] = hwmask; -#ifdef CONFIG_SMTC_IDLE_HOOK_DEBUG vpemask[vpe][irq - MIPSCPU_INT_BASE] = 1; #endif + irq_hwmask[irq] = hwmask; return setup_irq(irq, new); } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 200de027f35..a7a17eb9bfc 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -11,6 +11,7 @@ * Copyright (C) 2000, 01 MIPS Technologies, Inc. * Copyright (C) 2002, 2003, 2004, 2005 Maciej W. Rozycki */ +#include <linux/bug.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/module.h> @@ -927,12 +928,6 @@ asmlinkage void do_reserved(struct pt_regs *regs) (regs->cp0_cause & 0x7f) >> 2); } -static asmlinkage void do_default_vi(void) -{ - show_regs(get_irq_regs()); - panic("Caught unexpected vectored interrupt."); -} - /* * Some MIPS CPUs can enable/disable for cache parity detection, but do * it different ways. @@ -1128,6 +1123,12 @@ void mips_srs_free(int set) clear_bit(set, &sr->sr_allocated); } +static asmlinkage void do_default_vi(void) +{ + show_regs(get_irq_regs()); + panic("Caught unexpected vectored interrupt."); +} + static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) { unsigned long handler; @@ -1190,8 +1191,8 @@ static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) memcpy (b, &except_vec_vi, handler_len); #ifdef CONFIG_MIPS_MT_SMTC - if (n > 7) - printk("Vector index %d exceeds SMTC maximum\n", n); + BUG_ON(n > 7); /* Vector index %d exceeds SMTC maximum. */ + w = (u32 *)(b + mori_offset); *w = (*w & 0xffff0000) | (0x100 << n); #endif /* CONFIG_MIPS_MT_SMTC */ @@ -1383,6 +1384,13 @@ void __init per_cpu_trap_init(void) cpu_cache_init(); tlb_init(); #ifdef CONFIG_MIPS_MT_SMTC + } else if (!secondaryTC) { + /* + * First TC in non-boot VPE must do subset of tlb_init() + * for MMU countrol registers. + */ + write_c0_pagemask(PM_DEFAULT_MASK); + write_c0_wired(0); } #endif /* CONFIG_MIPS_MT_SMTC */ } @@ -1531,8 +1539,7 @@ void __init trap_init(void) if (cpu_has_mipsmt) set_except_vector(25, handle_mt); - if (cpu_has_dsp) - set_except_vector(26, handle_dsp); + set_except_vector(26, handle_dsp); if (cpu_has_vce) /* Special exception: R4[04]00 uses also the divec space. */ diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c index dfa0acbd7fc..9f49da95aac 100644 --- a/arch/mips/mips-boards/atlas/atlas_int.c +++ b/arch/mips/mips-boards/atlas/atlas_int.c @@ -248,14 +248,13 @@ void __init arch_init_irq(void) case MIPS_REVISION_CORID_CORE_24K: case MIPS_REVISION_CORID_CORE_EMUL_MSC: if (cpu_has_veic) - init_msc_irqs (MSC01E_INT_BASE, + init_msc_irqs (MSC01E_INT_BASE, MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs); else - init_msc_irqs (MSC01C_INT_BASE, + init_msc_irqs (MSC01E_INT_BASE, MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs); } - if (cpu_has_veic) { set_vi_handler (MSC01E_INT_ATLAS, atlas_hw0_irqdispatch); setup_irq (MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq); diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c index 0c6b0ce1502..1cc6ebbedfd 100644 --- a/arch/mips/mips-boards/atlas/atlas_setup.c +++ b/arch/mips/mips-boards/atlas/atlas_setup.c @@ -48,6 +48,8 @@ const char *get_system_type(void) return "MIPS Atlas"; } +const char display_string[] = " LINUX ON ATLAS "; + void __init plat_mem_setup(void) { mips_pcibios_init(); diff --git a/arch/mips/mips-boards/generic/display.c b/arch/mips/mips-boards/generic/display.c index 548dbe5ce7c..5d600054090 100644 --- a/arch/mips/mips-boards/generic/display.c +++ b/arch/mips/mips-boards/generic/display.c @@ -19,9 +19,14 @@ */ #include <linux/compiler.h> +#include <linux/timer.h> #include <asm/io.h> #include <asm/mips-boards/generic.h> +extern const char display_string[]; +static unsigned int display_count; +static unsigned int max_display_count; + void mips_display_message(const char *str) { static unsigned int __iomem *display = NULL; @@ -37,3 +42,22 @@ void mips_display_message(const char *str) writel(' ', display + i); } } + +static void scroll_display_message(unsigned long data); +static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0); + +static void scroll_display_message(unsigned long data) +{ + mips_display_message(&display_string[display_count++]); + if (display_count == max_display_count) + display_count = 0; + + mod_timer(&mips_scroll_timer, jiffies + HZ); +} + +void mips_scroll_message(void) +{ + del_timer_sync(&mips_scroll_timer); + max_display_count = strlen(display_string) + 1 - 8; + mod_timer(&mips_scroll_timer, jiffies + 1); +} diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index df2a2bd3aa5..b41db9e7ab1 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -53,37 +53,11 @@ unsigned long cpu_khz; -#if defined(CONFIG_MIPS_ATLAS) -static char display_string[] = " LINUX ON ATLAS "; -#endif -#if defined(CONFIG_MIPS_MALTA) -#if defined(CONFIG_MIPS_MT_SMTC) -static char display_string[] = " SMTC LINUX ON MALTA "; -#else -static char display_string[] = " LINUX ON MALTA "; -#endif /* CONFIG_MIPS_MT_SMTC */ -#endif -#if defined(CONFIG_MIPS_SEAD) -static char display_string[] = " LINUX ON SEAD "; -#endif -static unsigned int display_count; -#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) - #define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR) -static unsigned int timer_tick_count; static int mips_cpu_timer_irq; extern void smtc_timer_broadcast(int); -static inline void scroll_display_message(void) -{ - if ((timer_tick_count++ % HZ) == 0) { - mips_display_message(&display_string[display_count++]); - if (display_count == MAX_DISPLAY_COUNT) - display_count = 0; - } -} - static void mips_timer_dispatch(void) { do_IRQ(mips_cpu_timer_irq); @@ -114,8 +88,6 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id) * the general MIPS timer_interrupt routine. */ - int vpflags; - /* * We could be here due to timer interrupt, * perf counter overflow, or both. @@ -124,15 +96,6 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id) perf_irq(); if (read_c0_cause() & (1 << 30)) { - /* If timer interrupt, make it de-assert */ - write_c0_compare (read_c0_count() - 1); - /* - * DVPE is necessary so long as cross-VPE interrupts - * are done via read-modify-write of Cause register. - */ - vpflags = dvpe(); - clear_c0_cause(CPUCTR_IMASKBIT); - evpe(vpflags); /* * There are things we only want to do once per tick * in an "MP" system. One TC of each VPE will take @@ -141,15 +104,13 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id) * the tick on VPE 0 to run the full timer_interrupt(). */ if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, NULL); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - scroll_display_message(); + timer_interrupt(irq, NULL); } else { write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); local_timer_interrupt(irq, dev_id); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); } + smtc_timer_broadcast(cpu_data[cpu].vpe_id); } #else /* CONFIG_MIPS_MT_SMTC */ int r2 = cpu_has_mips_r2; @@ -167,8 +128,6 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id) /* we keep interrupt disabled all the time */ if (!r2 || (read_c0_cause() & (1 << 30))) timer_interrupt(irq, NULL); - - scroll_display_message(); } else { /* Everyone else needs to reset the timer int here as ll_local_timer_interrupt doesn't */ @@ -262,6 +221,8 @@ void __init mips_time_init(void) (est_freq%1000000)*100/1000000); cpu_khz = est_freq / 1000; + + mips_scroll_message(); } void __init plat_timer_setup(struct irqaction *irq) diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c index 7873932532a..c14b7bf8995 100644 --- a/arch/mips/mips-boards/malta/malta_setup.c +++ b/arch/mips/mips-boards/malta/malta_setup.c @@ -56,6 +56,12 @@ const char *get_system_type(void) return "MIPS Malta"; } +#if defined(CONFIG_MIPS_MT_SMTC) +const char display_string[] = " SMTC LINUX ON MALTA "; +#else +const char display_string[] = " LINUX ON MALTA "; +#endif /* CONFIG_MIPS_MT_SMTC */ + #ifdef CONFIG_BLK_DEV_FD void __init fd_activate(void) { diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c index a189dec7c7b..811aba10060 100644 --- a/arch/mips/mips-boards/sead/sead_setup.c +++ b/arch/mips/mips-boards/sead/sead_setup.c @@ -43,6 +43,8 @@ const char *get_system_type(void) return "MIPS SEAD"; } +const char display_string[] = " LINUX ON SEAD "; + void __init plat_mem_setup(void) { ioport_resource.end = 0x7fffffff; diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index f0eb29917d9..76903c72764 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -168,8 +168,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, addr = (unsigned long) page_address(sg->page); if (!plat_device_is_coherent(dev) && addr) __dma_sync(addr + sg->offset, sg->length, direction); - sg->dma_address = plat_map_dma_mem_page(dev, sg->page) + - sg->offset; + sg->dma_address = plat_map_dma_mem(dev, + (void *)(addr + sg->offset), + sg->length); } return nents; diff --git a/arch/mips/pci/pci-ocelot.c b/arch/mips/pci/pci-ocelot.c index 7f94f26d35a..1421d34535e 100644 --- a/arch/mips/pci/pci-ocelot.c +++ b/arch/mips/pci/pci-ocelot.c @@ -71,19 +71,19 @@ static inline void pci0WriteConfigReg(unsigned int offset, unsigned int data) } static struct resource ocelot_mem_resource = { - start = GT_PCI_MEM_BASE; - end = GT_PCI_MEM_BASE + GT_PCI_MEM_BASE - 1; + .start = GT_PCI_MEM_BASE, + .end = GT_PCI_MEM_BASE + GT_PCI_MEM_BASE - 1, }; static struct resource ocelot_io_resource = { - start = GT_PCI_IO_BASE; - end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1; + .start = GT_PCI_IO_BASE, + .end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1, }; static struct pci_controller ocelot_pci_controller = { - .pci_ops = gt64xxx_pci0_ops; - .mem_resource = &ocelot_mem_resource; - .io_resource = &ocelot_io_resource; + .pci_ops = gt64xxx_pci0_ops, + .mem_resource = &ocelot_mem_resource, + .io_resource = &ocelot_io_resource, }; static int __init ocelot_pcibios_init(void) diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c index f5ea2fe10f1..89891e984b3 100644 --- a/arch/mips/qemu/q-irq.c +++ b/arch/mips/qemu/q-irq.c @@ -7,8 +7,6 @@ #include <asm/system.h> #include <asm/time.h> -extern asmlinkage void qemu_handle_int(void); - asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause(); diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index fe8a1066aec..e5e023f50a0 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -517,7 +517,7 @@ void __init paging_init(void) pfn_t start_pfn = slot_getbasepfn(node, 0); pfn_t end_pfn = node_getmaxclick(node) + 1; - zones_size[ZONE_DMA] = end_pfn - start_pfn; + zones_size[ZONE_NORMAL] = end_pfn - start_pfn; free_area_init_node(node, NODE_DATA(node), zones_size, start_pfn, NULL); diff --git a/arch/mips/sgi-ip32/Makefile b/arch/mips/sgi-ip32/Makefile index 7e1416768a6..60f0227425e 100644 --- a/arch/mips/sgi-ip32/Makefile +++ b/arch/mips/sgi-ip32/Makefile @@ -3,5 +3,5 @@ # under Linux. # -obj-y += ip32-berr.o ip32-irq.o ip32-setup.o ip32-reset.o \ +obj-y += ip32-berr.o ip32-irq.o ip32-platform.o ip32-setup.o ip32-reset.o \ crime.o ip32-memory.o diff --git a/arch/mips/sgi-ip32/ip32-platform.c b/arch/mips/sgi-ip32/ip32-platform.c new file mode 100644 index 00000000000..120b15932ca --- /dev/null +++ b/arch/mips/sgi-ip32/ip32-platform.c @@ -0,0 +1,20 @@ +#include <linux/init.h> +#include <linux/platform_device.h> + +static __init int meth_devinit(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("meth", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} + +device_initcall(meth_devinit); diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c index 9ee208daa8b..97b234361b4 100644 --- a/arch/mips/sni/pcimt.c +++ b/arch/mips/sni/pcimt.c @@ -6,7 +6,7 @@ * for more details. * * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de) */ #include <linux/init.h> @@ -131,6 +131,19 @@ static struct resource pcimt_io_resources[] = { } }; +static struct resource pcimt_mem_resources[] = { + { + /* + * this region should only be 4 bytes long, + * but it's 16MB on all RM300C I've checked + */ + .start = 0x1a000000, + .end = 0x1affffff, + .name = "PCI INT ACK", + .flags = IORESOURCE_BUSY + } +}; + static struct resource sni_mem_resource = { .start = 0x18000000UL, .end = 0x1fbfffffUL, @@ -145,6 +158,9 @@ static void __init sni_pcimt_resource_init(void) /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++) request_resource(&sni_io_resource, pcimt_io_resources + i); + /* request MEM space for devices used on all i[345]86 PCs */ + for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++) + request_resource(&sni_mem_resource, pcimt_mem_resources + i); } extern struct pci_ops sni_pcimt_ops; diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index 68d7cf609b4..4fedfbda0c7 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -6,7 +6,7 @@ * for more details. * * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) - * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de) */ #include <linux/eisa.h> #include <linux/init.h> @@ -92,3 +92,34 @@ void __init plat_mem_setup(void) sni_display_setup(); } + +#if CONFIG_PCI + +#include <linux/pci.h> +#include <video/vga.h> +#include <video/cirrus.h> + +static void __devinit quirk_cirrus_ram_size(struct pci_dev *dev) +{ + u16 cmd; + + /* + * firmware doesn't set the ram size correct, so we + * need to do it here, otherwise we get screen corruption + * on older Cirrus chips + */ + pci_read_config_word (dev, PCI_COMMAND, &cmd); + if ((cmd & (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) + == (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) { + vga_wseq (NULL, CL_SEQR6, 0x12); /* unlock all extension registers */ + vga_wseq (NULL, CL_SEQRF, 0x18); + } +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5434_8, + quirk_cirrus_ram_size); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5436, + quirk_cirrus_ram_size); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, + quirk_cirrus_ram_size); +#endif diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 56d3c0dcd2b..5eaeafd30bd 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -118,6 +118,7 @@ config GENERIC_BUG depends on BUG config SYS_SUPPORTS_APM_EMULATION + default y if PMAC_APM_EMU bool config DEFAULT_UIMAGE diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 6238b5875fd..fbafd965dcd 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -142,7 +142,6 @@ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ # Default to zImage, override when needed defaultimage-y := zImage -defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux defaultimage-$(CONFIG_DEFAULT_UIMAGE) := uImage KBUILD_IMAGE := $(defaultimage-y) all: $(KBUILD_IMAGE) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 83788986b93..ff2701949ee 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -11,20 +11,18 @@ # bootloader and increase compatibility with OpenFirmware. # # To this end we need to define BOOTCC, etc, as the tools -# needed to build the 32 bit image. These are normally HOSTCC, -# but may be a third compiler if, for example, you are cross -# compiling from an intel box. Once the 64bit ppc gcc is -# stable it will probably simply be a compiler switch to -# compile for 32bit mode. +# needed to build the 32 bit image. That's normally the same +# compiler for the rest of the kernel, with the -m32 flag added. # To make it easier to setup a cross compiler, # CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE # in the toplevel makefile. all: $(obj)/zImage -HOSTCC := gcc -BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \ - $(shell $(CROSS32CC) -print-file-name=include) -fPIC +BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ + -fno-strict-aliasing -Os -msoft-float -pipe \ + -fomit-frame-pointer -fno-builtin -fPIC -nostdinc \ + -isystem $(shell $(CROSS32CC) -print-file-name=include) BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc ifeq ($(call cc-option-yn, -fstack-protector),y) @@ -33,8 +31,8 @@ endif BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj) -$(obj)/44x.o: BOOTCFLAGS += -Wa,-mbooke -$(obj)/ebony.o: BOOTCFLAGS += -Wa,-mbooke +$(obj)/44x.o: BOOTCFLAGS += -mcpu=440 +$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440 zlib := inffast.c inflate.c inftrees.c zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h @@ -136,6 +134,7 @@ image-$(CONFIG_PPC_EFIKA) += zImage.chrp image-$(CONFIG_PPC_PMAC) += zImage.pmac image-$(CONFIG_PPC_HOLLY) += zImage.holly-elf image-$(CONFIG_PPC_PRPMC2800) += zImage.prpmc2800 +image-$(CONFIG_PPC_ISERIES) += zImage.iseries image-$(CONFIG_DEFAULT_UIMAGE) += uImage ifneq ($(CONFIG_DEVICE_TREE),"") @@ -185,6 +184,9 @@ $(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(obj)/zImage.%: vmlinux $(wrapperbits) $(call if_changed,wrap,$*) +$(obj)/zImage.iseries: vmlinux + $(STRIP) -s -R .comment $< -o $@ + $(obj)/zImage.ps3: vmlinux $(STRIP) -s -R .comment $< -o $@ diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S index 5a4215c4b01..f1c4dfc635b 100644 --- a/arch/powerpc/boot/crt0.S +++ b/arch/powerpc/boot/crt0.S @@ -13,6 +13,7 @@ .text /* a procedure descriptor used when booting this as a COFF file */ + .globl _zimage_start_opd _zimage_start_opd: .long _zimage_start, 0, 0, 0 diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts index eae68ab1177..d29308fe4c2 100644 --- a/arch/powerpc/boot/dts/lite5200.dts +++ b/arch/powerpc/boot/dts/lite5200.dts @@ -67,7 +67,7 @@ interrupt-controller; #interrupt-cells = <3>; device_type = "interrupt-controller"; - compatible = "mpc5200_pic"; + compatible = "mpc5200-pic"; reg = <500 80>; built-in; }; diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts index 5185625a941..f242531f045 100644 --- a/arch/powerpc/boot/dts/lite5200b.dts +++ b/arch/powerpc/boot/dts/lite5200b.dts @@ -67,7 +67,7 @@ interrupt-controller; #interrupt-cells = <3>; device_type = "interrupt-controller"; - compatible = "mpc5200b-pic\0mpc5200_pic"; + compatible = "mpc5200b-pic\0mpc5200-pic"; reg = <500 80>; built-in; }; diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index 2ed8b8b3f0e..da77adc7307 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -129,7 +129,7 @@ case "$platform" in pmac|pseries|chrp) platformo=$object/of.o ;; -pmaccoff) +coff) platformo=$object/of.o lds=$object/zImage.coff.lds ;; @@ -220,7 +220,7 @@ case "$platform" in pseries|chrp) $object/addnote "$ofile" ;; -pmaccoff) +coff) ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile" $object/hack-coff "$ofile" ;; diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 6ef87fb90b8..b2b5d664d32 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -235,6 +235,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .cpu_setup = __setup_cpu_ppc970, .cpu_restore = __restore_cpu_ppc970, .oprofile_cpu_type = "ppc64/970MP", @@ -251,6 +252,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 8, + .pmc_type = PPC_PMC_IBM, .cpu_setup = __setup_cpu_ppc970MP, .cpu_restore = __restore_cpu_ppc970, .oprofile_cpu_type = "ppc64/970MP", @@ -317,6 +319,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power6", .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, @@ -335,6 +338,7 @@ static struct cpu_spec cpu_specs[] = { .icache_bsize = 128, .dcache_bsize = 128, .num_pmcs = 6, + .pmc_type = PPC_PMC_IBM, .oprofile_cpu_type = "ppc64/power6", .oprofile_type = PPC_OPROFILE_POWER4, .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 068377a2a8d..42c8ed6ed52 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -489,7 +489,7 @@ struct irq_host *irq_alloc_host(unsigned int revmap_type, case IRQ_HOST_MAP_LINEAR: rmap = (unsigned int *)(host + 1); for (i = 0; i < revmap_arg; i++) - rmap[i] = IRQ_NONE; + rmap[i] = NO_IRQ; host->revmap_data.linear.size = revmap_arg; smp_wmb(); host->revmap_data.linear.revmap = rmap; @@ -614,7 +614,7 @@ unsigned int irq_create_mapping(struct irq_host *host, * host->ops->map() to update the flags */ virq = irq_find_mapping(host, hwirq); - if (virq != IRQ_NONE) { + if (virq != NO_IRQ) { if (host->ops->remap) host->ops->remap(host, virq, hwirq); pr_debug("irq: -> existing mapping on virq %d\n", virq); @@ -741,7 +741,7 @@ void irq_dispose_mapping(unsigned int virq) switch(host->revmap_type) { case IRQ_HOST_MAP_LINEAR: if (hwirq < host->revmap_data.linear.size) - host->revmap_data.linear.revmap[hwirq] = IRQ_NONE; + host->revmap_data.linear.revmap[hwirq] = NO_IRQ; break; case IRQ_HOST_MAP_TREE: /* Check if radix tree allocated yet */ diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index d501c23e515..d454f61c9c7 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -433,7 +433,7 @@ static int __devinit of_pci_phb_probe(struct of_device *dev, * Note also that we don't do ISA, this will also be fixed with a * more massive rework. */ - pci_setup_phb_io(phb, 0); + pci_setup_phb_io(phb, pci_io_base == 0); /* Init pci_dn data structures */ pci_devs_phb_init_dynamic(phb); diff --git a/arch/powerpc/kernel/pmc.c b/arch/powerpc/kernel/pmc.c index 24d7b7c99bb..ea04e0ab3f2 100644 --- a/arch/powerpc/kernel/pmc.c +++ b/arch/powerpc/kernel/pmc.c @@ -20,8 +20,8 @@ #include <asm/cputable.h> #include <asm/pmc.h> -#ifndef MMCR0_PMA0 -#define MMCR0_PMA0 0 +#ifndef MMCR0_PMAO +#define MMCR0_PMAO 0 #endif static void dummy_perf(struct pt_regs *regs) @@ -30,7 +30,7 @@ static void dummy_perf(struct pt_regs *regs) mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE); #elif defined(CONFIG_PPC64) || defined(CONFIG_6xx) if (cur_cpu_spec->pmc_type == PPC_PMC_IBM) - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMA0)); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMAO)); #else mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMXE); #endif diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 066a6a7a25b..af42ddab3ab 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -1171,11 +1171,12 @@ EXPORT_SYMBOL(of_find_node_by_name); /** * of_find_node_by_type - Find a node by its "device_type" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. of_node_put() will be called on it - * @name: The type string to match against + * @from: The node to start searching from, or NULL to start searching + * the entire device tree. The node you pass will not be + * searched, only the next one will; typically, you pass + * what the previous call returned. of_node_put() will be + * called on from for you. + * @type: The type string to match against * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index f4f391cdd8f..bf76562167c 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -218,6 +218,7 @@ set_single_step(struct task_struct *task) regs->msr |= MSR_SE; #endif } + set_tsk_thread_flag(task, TIF_SINGLESTEP); } static inline void @@ -233,6 +234,7 @@ clear_single_step(struct task_struct *task) regs->msr &= ~MSR_SE; #endif } + clear_tsk_thread_flag(task, TIF_SINGLESTEP); } #endif /* CONFIG_PPC32 */ diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 22f1ef1b310..d577b71db37 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -201,13 +201,6 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); - /* remove 'self' from the map */ - if (cpu_isset(smp_processor_id(), map)) - cpu_clear(smp_processor_id(), map); - - /* sanity check the map, remove any non-online processors. */ - cpus_and(map, map, cpu_online_map); - if (unlikely(smp_ops == NULL)) return ret; @@ -222,10 +215,17 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, /* Must grab online cpu count with preempt disabled, otherwise * it can change. */ num_cpus = num_online_cpus() - 1; - if (!num_cpus || cpus_empty(map)) { - ret = 0; - goto out; - } + if (!num_cpus) + goto done; + + /* remove 'self' from the map */ + if (cpu_isset(smp_processor_id(), map)) + cpu_clear(smp_processor_id(), map); + + /* sanity check the map, remove any non-online processors. */ + cpus_and(map, map, cpu_online_map); + if (cpus_empty(map)) + goto done; call_data = &data; smp_wmb(); @@ -263,6 +263,7 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic, } } + done: ret = 0; out: @@ -282,16 +283,17 @@ EXPORT_SYMBOL(smp_call_function); int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic, int wait) { - cpumask_t map=CPU_MASK_NONE; + cpumask_t map = CPU_MASK_NONE; + int ret = -EBUSY; if (!cpu_online(cpu)) return -EINVAL; - if (cpu == smp_processor_id()) - return -EBUSY; - cpu_set(cpu, map); - return smp_call_function_map(func,info,nonatomic,wait,map); + if (cpu != get_cpu()) + ret = smp_call_function_map(func,info,nonatomic,wait,map); + put_cpu(); + return ret; } EXPORT_SYMBOL(smp_call_function_single); diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index f7d7bf19e4f..21c39ff2dc3 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -34,7 +34,6 @@ SECTIONS /* Text and gots */ .text : { _text = .; - *(.text.*) TEXT_TEXT SCHED_TEXT LOCK_TEXT diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 246eeea40ec..0266a94d83b 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -310,11 +310,12 @@ void __init paging_init(void) #ifdef CONFIG_HIGHMEM map_page(PKMAP_BASE, 0, 0); /* XXX gross */ - pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k - (PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); + pkmap_page_table = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k + (PKMAP_BASE), PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ - kmap_pte = pte_offset_kernel(pmd_offset(pgd_offset_k - (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); + kmap_pte = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k + (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), + KMAP_FIX_BEGIN); kmap_prot = PAGE_KERNEL; #endif /* CONFIG_HIGHMEM */ diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index d8232b7a08f..f6ae1a57d65 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -93,7 +93,7 @@ void pgd_free(pgd_t *pgd) free_pages((unsigned long)pgd, PGDIR_ORDER); } -pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { pte_t *pte; extern int mem_init_done; diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index f9ac3fe3be9..ac445998d83 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c @@ -67,6 +67,7 @@ static u64 MIC_Slow_Next_Timer_table[] = { 0x00003FC000000000ull, }; +static unsigned int pmi_frequency_limit = 0; /* * hardware specific functions */ @@ -164,7 +165,6 @@ static int set_pmode(int cpu, unsigned int slow_mode) { static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) { - struct cpufreq_policy policy; u8 cpu; u8 cbe_pmode_new; @@ -173,15 +173,27 @@ static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) cpu = cbe_node_to_cpu(pmi_msg.data1); cbe_pmode_new = pmi_msg.data2; - cpufreq_get_policy(&policy, cpu); + pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency; - policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency); - policy.min = min(policy.min, policy.max); + pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit); +} + +static int pmi_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct cpufreq_policy *policy = data; - pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max); - cpufreq_set_policy(&policy); + if (event != CPUFREQ_INCOMPATIBLE) + return 0; + + cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit); + return 0; } +static struct notifier_block pmi_notifier_block = { + .notifier_call = pmi_notifier, +}; + static struct pmi_handler cbe_pmi_handler = { .type = PMI_TYPE_FREQ_CHANGE, .handle_pmi_message = cbe_cpufreq_handle_pmi, @@ -238,12 +250,21 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); + if (pmi_dev) { + /* frequency might get limited later, initialize limit with max_freq */ + pmi_frequency_limit = max_freq; + cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); + } + /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); } static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) { + if (pmi_dev) + cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); + cpufreq_frequency_table_put_attr(policy->cpu); return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 8654749e317..7c51cb54bca 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -39,7 +39,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) if (spu_init_csa(&ctx->csa)) goto out_free; spin_lock_init(&ctx->mmio_lock); - spin_lock_init(&ctx->mapping_lock); + mutex_init(&ctx->mapping_lock); kref_init(&ctx->kref); mutex_init(&ctx->state_mutex); mutex_init(&ctx->run_mutex); @@ -103,6 +103,7 @@ void spu_forget(struct spu_context *ctx) void spu_unmap_mappings(struct spu_context *ctx) { + mutex_lock(&ctx->mapping_lock); if (ctx->local_store) unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); if (ctx->mfc) @@ -117,6 +118,7 @@ void spu_unmap_mappings(struct spu_context *ctx) unmap_mapping_range(ctx->mss, 0, 0x1000, 1); if (ctx->psmap) unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); + mutex_unlock(&ctx->mapping_lock); } /** diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 45614c73c78..b1e7e2f8a2e 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -45,11 +45,11 @@ spufs_mem_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->local_store = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -59,10 +59,10 @@ spufs_mem_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->local_store = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -217,6 +217,7 @@ unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr, static const struct file_operations spufs_mem_fops = { .open = spufs_mem_open, + .release = spufs_mem_release, .read = spufs_mem_read, .write = spufs_mem_write, .llseek = generic_file_llseek, @@ -309,11 +310,11 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->cntl = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return simple_attr_open(inode, file, spufs_cntl_get, spufs_cntl_set, "0x%08lx"); } @@ -326,10 +327,10 @@ spufs_cntl_release(struct inode *inode, struct file *file) simple_attr_close(inode, file); - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->cntl = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -812,11 +813,11 @@ static int spufs_signal1_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->signal1 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -826,10 +827,10 @@ spufs_signal1_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->signal1 = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -936,11 +937,11 @@ static int spufs_signal2_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->signal2 = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -950,10 +951,10 @@ spufs_signal2_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->signal2 = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1154,10 +1155,10 @@ static int spufs_mss_open(struct inode *inode, struct file *file) file->private_data = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!i->i_openers++) ctx->mss = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1167,10 +1168,10 @@ spufs_mss_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->mss = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1211,11 +1212,11 @@ static int spufs_psmap_open(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = i->i_ctx; if (!i->i_openers++) ctx->psmap = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1225,10 +1226,10 @@ spufs_psmap_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->psmap = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } @@ -1281,11 +1282,11 @@ static int spufs_mfc_open(struct inode *inode, struct file *file) if (atomic_read(&inode->i_count) != 1) return -EBUSY; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); file->private_data = ctx; if (!i->i_openers++) ctx->mfc = inode->i_mapping; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return nonseekable_open(inode, file); } @@ -1295,10 +1296,10 @@ spufs_mfc_release(struct inode *inode, struct file *file) struct spufs_inode_info *i = SPUFS_I(inode); struct spu_context *ctx = i->i_ctx; - spin_lock(&ctx->mapping_lock); + mutex_lock(&ctx->mapping_lock); if (!--i->i_openers) ctx->mfc = NULL; - spin_unlock(&ctx->mapping_lock); + mutex_unlock(&ctx->mapping_lock); return 0; } diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 7150730e2ff..9807206e021 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -177,7 +177,7 @@ static int spufs_rmdir(struct inode *parent, struct dentry *dir) static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, int mode, struct spu_context *ctx) { - struct dentry *dentry; + struct dentry *dentry, *tmp; int ret; while (files->name && files->name[0]) { @@ -193,7 +193,20 @@ static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files, } return 0; out: - spufs_prune_dir(dir); + /* + * remove all children from dir. dir->inode is not set so don't + * just simply use spufs_prune_dir() and panic afterwards :) + * dput() looks like it will do the right thing: + * - dec parent's ref counter + * - remove child from parent's child list + * - free child's inode if possible + * - free child + */ + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { + dput(dentry); + } + + shrink_dcache_parent(dir); return ret; } @@ -274,6 +287,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags, goto out; out_free_ctx: + spu_forget(ctx); put_spu_context(ctx); out_iput: iput(inode); @@ -349,37 +363,6 @@ out: return ret; } -static int spufs_rmgang(struct inode *root, struct dentry *dir) -{ - /* FIXME: this fails if the dir is not empty, - which causes a leak of gangs. */ - return simple_rmdir(root, dir); -} - -static int spufs_gang_close(struct inode *inode, struct file *file) -{ - struct inode *parent; - struct dentry *dir; - int ret; - - dir = file->f_path.dentry; - parent = dir->d_parent->d_inode; - - ret = spufs_rmgang(parent, dir); - WARN_ON(ret); - - return dcache_dir_close(inode, file); -} - -const struct file_operations spufs_gang_fops = { - .open = dcache_dir_open, - .release = spufs_gang_close, - .llseek = dcache_dir_lseek, - .read = generic_read_dir, - .readdir = dcache_readdir, - .fsync = simple_sync_file, -}; - static int spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) { @@ -407,7 +390,6 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode) inode->i_fop = &simple_dir_operations; d_instantiate(dentry, inode); - dget(dentry); dir->i_nlink++; dentry->d_inode->i_nlink++; return ret; @@ -437,7 +419,7 @@ static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt) goto out; } - filp->f_op = &spufs_gang_fops; + filp->f_op = &simple_dir_operations; fd_install(ret, filp); out: return ret; @@ -458,8 +440,10 @@ static int spufs_create_gang(struct inode *inode, * in error path of *_open(). */ ret = spufs_gang_open(dget(dentry), mntget(mnt)); - if (ret < 0) - WARN_ON(spufs_rmgang(inode, dentry)); + if (ret < 0) { + int err = simple_rmdir(inode, dentry); + WARN_ON(err); + } out: mutex_unlock(&inode->i_mutex); @@ -600,6 +584,10 @@ spufs_create_root(struct super_block *sb, void *data) struct inode *inode; int ret; + ret = -ENODEV; + if (!spu_management_ops) + goto out; + ret = -ENOMEM; inode = spufs_new_inode(sb, S_IFDIR | 0775); if (!inode) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index b6ecb30e7d5..3b831e07f1e 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -93,43 +93,6 @@ void spu_stop_tick(struct spu_context *ctx) } } -void spu_sched_tick(struct work_struct *work) -{ - struct spu_context *ctx = - container_of(work, struct spu_context, sched_work.work); - struct spu *spu; - int preempted = 0; - - /* - * If this context is being stopped avoid rescheduling from the - * scheduler tick because we would block on the state_mutex. - * The caller will yield the spu later on anyway. - */ - if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) - return; - - mutex_lock(&ctx->state_mutex); - spu = ctx->spu; - if (spu) { - int best = sched_find_first_bit(spu_prio->bitmap); - if (best <= ctx->prio) { - spu_deactivate(ctx); - preempted = 1; - } - } - mutex_unlock(&ctx->state_mutex); - - if (preempted) { - /* - * We need to break out of the wait loop in spu_run manually - * to ensure this context gets put on the runqueue again - * ASAP. - */ - wake_up(&ctx->stop_wq); - } else - spu_start_tick(ctx); -} - /** * spu_add_to_active_list - add spu to active list * @spu: spu to add to the active list @@ -273,34 +236,6 @@ static void spu_prio_wait(struct spu_context *ctx) remove_wait_queue(&ctx->stop_wq, &wait); } -/** - * spu_reschedule - try to find a runnable context for a spu - * @spu: spu available - * - * This function is called whenever a spu becomes idle. It looks for the - * most suitable runnable spu context and schedules it for execution. - */ -static void spu_reschedule(struct spu *spu) -{ - int best; - - spu_free(spu); - - spin_lock(&spu_prio->runq_lock); - best = sched_find_first_bit(spu_prio->bitmap); - if (best < MAX_PRIO) { - struct list_head *rq = &spu_prio->runq[best]; - struct spu_context *ctx; - - BUG_ON(list_empty(rq)); - - ctx = list_entry(rq->next, struct spu_context, rq); - __spu_del_from_rq(ctx); - wake_up(&ctx->stop_wq); - } - spin_unlock(&spu_prio->runq_lock); -} - static struct spu *spu_get_idle(struct spu_context *ctx) { struct spu *spu = NULL; @@ -429,6 +364,51 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) } /** + * grab_runnable_context - try to find a runnable context + * + * Remove the highest priority context on the runqueue and return it + * to the caller. Returns %NULL if no runnable context was found. + */ +static struct spu_context *grab_runnable_context(int prio) +{ + struct spu_context *ctx = NULL; + int best; + + spin_lock(&spu_prio->runq_lock); + best = sched_find_first_bit(spu_prio->bitmap); + if (best < prio) { + struct list_head *rq = &spu_prio->runq[best]; + + BUG_ON(list_empty(rq)); + + ctx = list_entry(rq->next, struct spu_context, rq); + __spu_del_from_rq(ctx); + } + spin_unlock(&spu_prio->runq_lock); + + return ctx; +} + +static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) +{ + struct spu *spu = ctx->spu; + struct spu_context *new = NULL; + + if (spu) { + new = grab_runnable_context(max_prio); + if (new || force) { + spu_unbind_context(spu, ctx); + spu_free(spu); + if (new) + wake_up(&new->stop_wq); + } + + } + + return new != NULL; +} + +/** * spu_deactivate - unbind a context from it's physical spu * @ctx: spu context to unbind * @@ -437,12 +417,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags) */ void spu_deactivate(struct spu_context *ctx) { - struct spu *spu = ctx->spu; - - if (spu) { - spu_unbind_context(spu, ctx); - spu_reschedule(spu); - } + __spu_deactivate(ctx, 1, MAX_PRIO); } /** @@ -455,21 +430,43 @@ void spu_deactivate(struct spu_context *ctx) */ void spu_yield(struct spu_context *ctx) { - struct spu *spu; - - if (mutex_trylock(&ctx->state_mutex)) { - if ((spu = ctx->spu) != NULL) { - int best = sched_find_first_bit(spu_prio->bitmap); - if (best < MAX_PRIO) { - pr_debug("%s: yielding SPU %d NODE %d\n", - __FUNCTION__, spu->number, spu->node); - spu_deactivate(ctx); - } - } + if (!(ctx->flags & SPU_CREATE_NOSCHED)) { + mutex_lock(&ctx->state_mutex); + __spu_deactivate(ctx, 0, MAX_PRIO); mutex_unlock(&ctx->state_mutex); } } +void spu_sched_tick(struct work_struct *work) +{ + struct spu_context *ctx = + container_of(work, struct spu_context, sched_work.work); + int preempted; + + /* + * If this context is being stopped avoid rescheduling from the + * scheduler tick because we would block on the state_mutex. + * The caller will yield the spu later on anyway. + */ + if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags)) + return; + + mutex_lock(&ctx->state_mutex); + preempted = __spu_deactivate(ctx, 0, ctx->prio + 1); + mutex_unlock(&ctx->state_mutex); + + if (preempted) { + /* + * We need to break out of the wait loop in spu_run manually + * to ensure this context gets put on the runqueue again + * ASAP. + */ + wake_up(&ctx->stop_wq); + } else { + spu_start_tick(ctx); + } +} + int __init spu_sched_init(void) { int i; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 0a947fd7de5..47617e8014a 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -55,7 +55,7 @@ struct spu_context { struct address_space *signal2; /* 'signal2' area mappings. */ struct address_space *mss; /* 'mss' area mappings. */ struct address_space *psmap; /* 'psmap' area mappings. */ - spinlock_t mapping_lock; + struct mutex mapping_lock; u64 object_id; /* user space pointer for oprofile */ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile index f4f82520dc4..5240046d867 100644 --- a/arch/powerpc/platforms/celleb/Makefile +++ b/arch/powerpc/platforms/celleb/Makefile @@ -4,5 +4,5 @@ obj-y += interrupt.o iommu.o setup.o \ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o -obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o +obj-$(CONFIG_SERIAL_TXX9) += scc_sio.o obj-$(CONFIG_SPU_BASE) += spu_priv1.o diff --git a/arch/powerpc/platforms/chrp/pegasos_eth.c b/arch/powerpc/platforms/chrp/pegasos_eth.c index 71045677559..5bcc58d9a4d 100644 --- a/arch/powerpc/platforms/chrp/pegasos_eth.c +++ b/arch/powerpc/platforms/chrp/pegasos_eth.c @@ -169,7 +169,7 @@ static int Enable_SRAM(void) /***********/ /***********/ -int mv643xx_eth_add_pds(void) +static int __init mv643xx_eth_add_pds(void) { int ret = 0; static struct pci_device_id pci_marvell_mv64360[] = { diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c index 03cd45d8fef..3c962d5757b 100644 --- a/arch/powerpc/platforms/pasemi/idle.c +++ b/arch/powerpc/platforms/pasemi/idle.c @@ -26,6 +26,7 @@ #include <asm/machdep.h> #include <asm/reg.h> +#include <asm/smp.h> #include "pasemi.h" diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c index 95fa6a7d15e..f33b21b9f5d 100644 --- a/arch/powerpc/platforms/pasemi/iommu.c +++ b/arch/powerpc/platforms/pasemi/iommu.c @@ -31,8 +31,6 @@ #define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT) #define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1) -#define IOBMAP_PAGE_FACTOR (PAGE_SHIFT - IOBMAP_PAGE_SHIFT) - #define IOB_BASE 0xe0000000 #define IOB_SIZE 0x3000 /* Configuration registers */ @@ -97,9 +95,6 @@ static void iobmap_build(struct iommu_table *tbl, long index, bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; - npages <<= IOBMAP_PAGE_FACTOR; - index <<= IOBMAP_PAGE_FACTOR; - ip = ((u32 *)tbl->it_base) + index; while (npages--) { @@ -125,9 +120,6 @@ static void iobmap_free(struct iommu_table *tbl, long index, bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; - npages <<= IOBMAP_PAGE_FACTOR; - index <<= IOBMAP_PAGE_FACTOR; - ip = ((u32 *)tbl->it_base) + index; while (npages--) { diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index a410bc76a8a..07b1c4ec428 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -384,7 +384,7 @@ int boot_part; static dev_t boot_dev; #ifdef CONFIG_SCSI -void __init note_scsi_host(struct device_node *node, void *host) +void note_scsi_host(struct device_node *node, void *host) { int l; char *p; diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 9da82c266ba..ec9030dbb5f 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -25,6 +25,7 @@ #include <asm/machdep.h> #include <asm/udbg.h> #include <asm/lv1call.h> +#include <asm/smp.h> #include "platform.h" diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index b854e7f1001..f1df942072b 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -752,6 +752,7 @@ skip_gserver_check: void xics_request_IPIs(void) { unsigned int ipi; + int rc; ipi = irq_create_mapping(xics_host, XICS_IPI); BUG_ON(ipi == NO_IRQ); @@ -762,11 +763,12 @@ void xics_request_IPIs(void) */ set_irq_handler(ipi, handle_percpu_irq); if (firmware_has_feature(FW_FEATURE_LPAR)) - request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED, - "IPI", NULL); + rc = request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED, + "IPI", NULL); else - request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED, - "IPI", NULL); + rc = request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED, + "IPI", NULL); + BUG_ON(rc); } #endif /* CONFIG_SMP */ diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig index 887739f3bad..f611d344a12 100644 --- a/arch/powerpc/sysdev/qe_lib/Kconfig +++ b/arch/powerpc/sysdev/qe_lib/Kconfig @@ -5,15 +5,13 @@ config UCC_SLOW bool default n - select UCC help This option provides qe_lib support to UCC slow protocols: UART, BISYNC, QMC config UCC_FAST bool - default n - select UCC + default y if UCC_GETH help This option provides qe_lib support to UCC fast protocols: HDLC, Ethernet, ATM, transparent diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index ab64256110b..fba7ca17a67 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -596,7 +596,11 @@ fast_exception_return: mr r12,r4 /* restart at exc_exit_restart */ b 2b - .comm fee_restarts,4 + .section .bss + .align 2 +fee_restarts: + .space 4 + .previous /* aargh, a nonrecoverable interrupt, panic */ /* aargh, we don't know which trap this is */ @@ -851,7 +855,11 @@ load_dbcr0: mtspr SPRN_DBSR,r11 /* clear all pending debug events */ blr - .comm global_dbcr0,8 + .section .bss + .align 4 +global_dbcr0: + .space 8 + .previous #endif /* !(CONFIG_4xx || CONFIG_BOOKE) */ do_work: /* r10 contains MSR_KERNEL here */ @@ -926,4 +934,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) /* shouldn't return */ b 4b - .comm ee_restarts,4 + .section .bss + .align 2 +ee_restarts: + .space 4 + .previous diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 4ad499605d0..a4165209ac7 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -40,7 +40,6 @@ #include <asm/time.h> #include <asm/cputable.h> #include <asm/btext.h> -#include <asm/div64.h> #include <asm/xmon.h> #include <asm/signal.h> #include <asm/dcr.h> @@ -93,7 +92,6 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(__div64_32); EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(csum_partial_copy_generic); diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S index e756942e65c..5f364dc5015 100644 --- a/arch/ppc/mm/hashtable.S +++ b/arch/ppc/mm/hashtable.S @@ -30,7 +30,11 @@ #include <asm/asm-offsets.h> #ifdef CONFIG_SMP - .comm mmu_hash_lock,4 + .section .bss + .align 2 + .globl mmu_hash_lock +mmu_hash_lock: + .space 4 #endif /* CONFIG_SMP */ /* @@ -461,9 +465,17 @@ found_slot: sync /* make sure pte updates get to memory */ blr - .comm next_slot,4 - .comm primary_pteg_full,4 - .comm htab_hash_searches,4 + .section .bss + .align 2 +next_slot: + .space 4 + .globl primary_pteg_full +primary_pteg_full: + .space 4 + .globl htab_hash_searches +htab_hash_searches: + .space 4 + .previous /* * Flush the entry for a particular page from the hash table. diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index c023b729880..35ebb6395ae 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -92,7 +92,7 @@ void pgd_free(pgd_t *pgd) free_pages((unsigned long)pgd, PGDIR_ORDER); } -pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { pte_t *pte; extern int mem_init_done; diff --git a/arch/ppc/syslib/ibm_ocp.c b/arch/ppc/syslib/ibm_ocp.c index 3f6e55c7918..2ee176610e7 100644 --- a/arch/ppc/syslib/ibm_ocp.c +++ b/arch/ppc/syslib/ibm_ocp.c @@ -1,4 +1,5 @@ #include <linux/module.h> +#include <asm/ibm4xx.h> #include <asm/ocp.h> struct ocp_sys_info_data ocp_sys_info = { diff --git a/arch/ppc/syslib/qspan_pci.c b/arch/ppc/syslib/qspan_pci.c index 85053b2816a..7a97c7440b3 100644 --- a/arch/ppc/syslib/qspan_pci.c +++ b/arch/ppc/syslib/qspan_pci.c @@ -365,13 +365,13 @@ int qspan_pcibios_find_class(unsigned int class_code, unsigned short index, } void __init -m8xx_pcibios_fixup(void)) +m8xx_pcibios_fixup(void) { /* Lots to do here, all board and configuration specific. */ } void __init -m8xx_setup_pci_ptrs(void)) +m8xx_setup_pci_ptrs(void) { set_config_access_method(qspan); diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index 2782cf9da5b..b9a1ce1f28e 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c @@ -481,9 +481,17 @@ out: /* Diagnose 224 functions */ -static void diag224(void *ptr) +static int diag224(void *ptr) { - asm volatile("diag %0,%1,0x224" : :"d" (0), "d"(ptr) : "memory"); + int rc = -ENOTSUPP; + + asm volatile( + " diag %1,%2,0x224\n" + "0: lhi %0,0x0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) :"d" (0), "d" (ptr) : "memory"); + return rc; } static int diag224_get_name_table(void) @@ -492,7 +500,10 @@ static int diag224_get_name_table(void) diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA); if (!diag224_cpu_names) return -ENOMEM; - diag224(diag224_cpu_names); + if (diag224(diag224_cpu_names)) { + kfree(diag224_cpu_names); + return -ENOTSUPP; + } EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16); return 0; } diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index dca6eaf82c8..1b2f5ce4532 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -163,7 +163,7 @@ unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION; static debug_info_t *debug_area_first = NULL; static debug_info_t *debug_area_last = NULL; -static DECLARE_MUTEX(debug_lock); +static DEFINE_MUTEX(debug_mutex); static int initialized; @@ -576,7 +576,7 @@ debug_input(struct file *file, const char __user *user_buf, size_t length, int rc = 0; file_private_info_t *p_info; - down(&debug_lock); + mutex_lock(&debug_mutex); p_info = ((file_private_info_t *) file->private_data); if (p_info->view->input_proc) rc = p_info->view->input_proc(p_info->debug_info_org, @@ -584,7 +584,7 @@ debug_input(struct file *file, const char __user *user_buf, size_t length, length, offset); else rc = -EPERM; - up(&debug_lock); + mutex_unlock(&debug_mutex); return rc; /* number of input characters */ } @@ -602,7 +602,7 @@ debug_open(struct inode *inode, struct file *file) file_private_info_t *p_info; debug_info_t *debug_info, *debug_info_snapshot; - down(&debug_lock); + mutex_lock(&debug_mutex); debug_info = file->f_path.dentry->d_inode->i_private; /* find debug view */ for (i = 0; i < DEBUG_MAX_VIEWS; i++) { @@ -653,7 +653,7 @@ found: file->private_data = p_info; debug_info_get(debug_info); out: - up(&debug_lock); + mutex_unlock(&debug_mutex); return rc; } @@ -688,7 +688,7 @@ debug_register (char *name, int pages_per_area, int nr_areas, int buf_size) if (!initialized) BUG(); - down(&debug_lock); + mutex_lock(&debug_mutex); /* create new debug_info */ @@ -702,7 +702,7 @@ out: if (!rc){ printk(KERN_ERR "debug: debug_register failed for %s\n",name); } - up(&debug_lock); + mutex_unlock(&debug_mutex); return rc; } @@ -716,9 +716,9 @@ debug_unregister(debug_info_t * id) { if (!id) goto out; - down(&debug_lock); + mutex_lock(&debug_mutex); debug_info_put(id); - up(&debug_lock); + mutex_unlock(&debug_mutex); out: return; @@ -1054,11 +1054,11 @@ __init debug_init(void) int rc = 0; s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table); - down(&debug_lock); + mutex_lock(&debug_mutex); debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL); printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; - up(&debug_lock); + mutex_unlock(&debug_mutex); return rc; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 6bfb0889eb1..51d6309e7f3 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -102,7 +102,7 @@ static struct resource data_resource = { /* * cpu_init() initializes state that is per-CPU. */ -void __devinit cpu_init (void) +void __cpuinit cpu_init(void) { int addr = hard_smp_processor_id(); @@ -915,7 +915,7 @@ setup_arch(char **cmdline_p) setup_zfcpdump(console_devno); } -void print_cpu_info(struct cpuinfo_S390 *cpuinfo) +void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo) { printk("cpu %d " #ifdef CONFIG_SMP diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 09f028a3266..8ff2feaf9b0 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -492,7 +492,7 @@ static unsigned int __init smp_count_cpus(void) /* * Activate a secondary processor. */ -int __devinit start_secondary(void *cpuvoid) +int __cpuinit start_secondary(void *cpuvoid) { /* Setup the cpu */ cpu_init(); @@ -741,7 +741,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) smp_create_idle(cpu); } -void __devinit smp_prepare_boot_cpu(void) +void __init smp_prepare_boot_cpu(void) { BUG_ON(smp_processor_id() != 0); @@ -750,7 +750,7 @@ void __devinit smp_prepare_boot_cpu(void) current_set[0] = current; } -void smp_cpus_done(unsigned int max_cpus) +void __init smp_cpus_done(unsigned int max_cpus) { cpu_present_map = cpu_possible_map; } diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 7b112241705..883b03b040c 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -39,7 +39,7 @@ cflags-$(CONFIG_CPU_SH2A) := -m2a $(call cc-option,-m2a-nofpu,) cflags-$(CONFIG_CPU_SH3) := -m3 cflags-$(CONFIG_CPU_SH4) := -m4 \ $(call cc-option,-mno-implicit-fp,-m4-nofpu) -cflags-$(CONFIG_CPU_SH4A) := -m4a $(call cc-option,-m4a-nofpu,) +cflags-$(CONFIG_CPU_SH4A) := $(call cc-option,-m4a,) $(call cc-option,-m4a-nofpu,) cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mb cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml diff --git a/arch/sh/boards/landisk/gio.c b/arch/sh/boards/landisk/gio.c index 50d38be62f0..a37643d002b 100644 --- a/arch/sh/boards/landisk/gio.c +++ b/arch/sh/boards/landisk/gio.c @@ -69,7 +69,7 @@ static int gio_ioctl(struct inode *inode, struct file *filp, } switch (cmd) { - case GIODRV_IOCSGIOSETADDR: /* addres set */ + case GIODRV_IOCSGIOSETADDR: /* address set */ addr = data; break; diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c index 4058b4f50d4..f953c742776 100644 --- a/arch/sh/boards/landisk/setup.c +++ b/arch/sh/boards/landisk/setup.c @@ -44,8 +44,14 @@ static struct platform_device cf_ide_device = { }, }; +static struct platform_device rtc_device = { + .name = "rs5c313", + .id = -1, +}; + static struct platform_device *landisk_devices[] __initdata = { &cf_ide_device, + &rtc_device, }; static int __init landisk_devices_setup(void) diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile index 609e5d50dde..b1d20afb4eb 100644 --- a/arch/sh/boards/renesas/r7780rp/Makefile +++ b/arch/sh/boards/renesas/r7780rp/Makefile @@ -3,5 +3,8 @@ # irqinit-y := irq-r7780rp.o irqinit-$(CONFIG_SH_R7785RP) := irq-r7785rp.o +obj-y := setup.o irq.o $(irqinit-y) + +ifneq ($(CONFIG_SH_R7785RP),y) obj-$(CONFIG_PUSH_SWITCH) += psw.o -obj-y := setup.o irq.o $(irqinit-y) +endif diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c index 911ce1cdbd7..e143017c897 100644 --- a/arch/sh/boards/se/73180/setup.c +++ b/arch/sh/boards/se/73180/setup.c @@ -38,8 +38,8 @@ static struct platform_device *se73180_devices[] __initdata = { static int __init se73180_devices_setup(void) { - return platform_add_devices(sh7343se_platform_devices, - ARRAY_SIZE(sh7343se_platform_devices)); + return platform_add_devices(se73180_devices, + ARRAY_SIZE(se73180_devices)); } __initcall(se73180_devices_setup); diff --git a/arch/sh/boards/snapgear/rtc.c b/arch/sh/boards/snapgear/rtc.c index 1659fdd6695..edb3dd936cb 100644 --- a/arch/sh/boards/snapgear/rtc.c +++ b/arch/sh/boards/snapgear/rtc.c @@ -108,7 +108,7 @@ static void ds1302_writebyte(unsigned int addr, unsigned int val) static void ds1302_reset(void) { unsigned long flags; - /* Hardware dependant reset/init */ + /* Hardware dependent reset/init */ local_irq_save(flags); set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK); set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); diff --git a/arch/sh/boards/superh/microdev/io.c b/arch/sh/boards/superh/microdev/io.c index 83419bf4c83..b704e20d7e4 100644 --- a/arch/sh/boards/superh/microdev/io.c +++ b/arch/sh/boards/superh/microdev/io.c @@ -198,12 +198,12 @@ void microdev_outb(unsigned char b, unsigned long port) /* * There is a board feature with the current SH4-202 MicroDev in * that the 2 byte enables (nBE0 and nBE1) are tied together (and - * to the Chip Select Line (Ethernet_CS)). Due to this conectivity, + * to the Chip Select Line (Ethernet_CS)). Due to this connectivity, * it is not possible to safely perform 8-bit writes to the * Ethernet registers, as 16-bits will be consumed from the Data * lines (corrupting the other byte). Hence, this function is - * written to impliment 16-bit read/modify/write for all byte-wide - * acceses. + * written to implement 16-bit read/modify/write for all byte-wide + * accesses. * * Note: there is no problem with byte READS (even or odd). * diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c index 8c64baa3036..4d335077a3f 100644 --- a/arch/sh/boards/superh/microdev/irq.c +++ b/arch/sh/boards/superh/microdev/irq.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/irq.h> +#include <linux/interrupt.h> #include <asm/system.h> #include <asm/io.h> #include <asm/microdev.h> @@ -100,7 +101,7 @@ static void disable_microdev_irq(unsigned int irq) fpgaIrq = fpgaIrqTable[irq].fpgaIrq; - /* disable interupts on the FPGA INTC register */ + /* disable interrupts on the FPGA INTC register */ ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG); } @@ -125,7 +126,7 @@ static void enable_microdev_irq(unsigned int irq) priorities |= MICRODEV_FPGA_INTPRI_LEVEL(fpgaIrq, pri); ctrl_outl(priorities, priorityReg); - /* enable interupts on the FPGA INTC register */ + /* enable interrupts on the FPGA INTC register */ ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG); } @@ -152,7 +153,7 @@ extern void __init init_microdev_irq(void) { int i; - /* disable interupts on the FPGA INTC register */ + /* disable interrupts on the FPGA INTC register */ ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG); for (i = 0; i < NUM_EXTERNAL_IRQS; i++) diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c index 031c814e6e7..6396cea1c89 100644 --- a/arch/sh/boards/superh/microdev/setup.c +++ b/arch/sh/boards/superh/microdev/setup.c @@ -349,7 +349,7 @@ static int __init smsc_superio_setup(void) SMSC_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */ SMSC_WRITE_INDEXED(0x08, 0xe8); /* GP20 = nIDE2_OE */ - /* Exit the configuraton state */ + /* Exit the configuration state */ outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR); return 0; diff --git a/arch/sh/boards/unknown/setup.c b/arch/sh/boards/unknown/setup.c index 1c941370a2e..bee4612de59 100644 --- a/arch/sh/boards/unknown/setup.c +++ b/arch/sh/boards/unknown/setup.c @@ -6,7 +6,7 @@ * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * - * Setup code for an unknown machine (internal peripherials only) + * Setup code for an unknown machine (internal peripherals only) * * This is the simplest of all boards, and serves only as a quick and dirty * method to start debugging a new board during bring-up until proper board diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c index 70f12907647..d70e5c8461b 100644 --- a/arch/sh/cchips/voyagergx/irq.c +++ b/arch/sh/cchips/voyagergx/irq.c @@ -28,7 +28,7 @@ static void disable_voyagergx_irq(unsigned int irq) unsigned long val; unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); val = readl((void __iomem *)VOYAGER_INT_MASK); val &= ~mask; writel(val, (void __iomem *)VOYAGER_INT_MASK); @@ -39,7 +39,7 @@ static void enable_voyagergx_irq(unsigned int irq) unsigned long val; unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); - pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask); val = readl((void __iomem *)VOYAGER_INT_MASK); val |= mask; writel(val, (void __iomem *)VOYAGER_INT_MASK); @@ -125,11 +125,12 @@ int voyagergx_irq_demux(int irq) i = 17; else printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val); - pr_debug("voyagergx_irq_demux %d \n", i); - if (i < VOYAGER_IRQ_NUM) { + pr_debug("voyagergx_irq_demux %ld \n", i); + if (i < VOYAGER_IRQ_NUM) { irq = VOYAGER_IRQ_BASE + i; - if (voyagergx_demux[i].func != 0) - irq = voyagergx_demux[i].func(irq, voyagergx_demux[i].dev); + if (voyagergx_demux[i].func != 0) + irq = voyagergx_demux[i].func(irq, + voyagergx_demux[i].dev); } } return irq; diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index e062067edd2..cf8e1199433 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c @@ -16,6 +16,7 @@ #include <linux/list.h> #include <linux/platform_device.h> #include <linux/mm.h> +#include <linux/sched.h> #include <asm/dma.h> DEFINE_SPINLOCK(dma_spin_lock); @@ -115,7 +116,7 @@ static int search_cap(const char **haystack, const char *needle) /** * request_dma_bycap - Allocate a DMA channel based on its capabilities * @dmac: List of DMA controllers to search - * @caps: List of capabilites + * @caps: List of capabilities * * Search all channels of all DMA controllers to find a channel which * matches the requested capabilities. The result is the channel diff --git a/arch/sh/drivers/dma/dma-isa.c b/arch/sh/drivers/dma/dma-isa.c index 05a74ffdb68..5fb044b791c 100644 --- a/arch/sh/drivers/dma/dma-isa.c +++ b/arch/sh/drivers/dma/dma-isa.c @@ -28,7 +28,7 @@ * NOTE: ops->xfer() is the preferred way of doing things. However, there * are some users of the ISA DMA API that exist in common code that we * don't necessarily want to go out of our way to break, so we still - * allow for some compatability at that level. Any new code is strongly + * allow for some compatibility at that level. Any new code is strongly * advised to run far away from the ISA DMA API and use the SH DMA API * directly. */ diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c index 9d0a29370f2..5e22689c2fc 100644 --- a/arch/sh/drivers/dma/dmabrg.c +++ b/arch/sh/drivers/dma/dmabrg.c @@ -33,7 +33,7 @@ * 9 | HAC1/SSI1 | rec | half done | DMABRGI2 * * all can be enabled/disabled in the DMABRGCR register, - * as well as checked if they occured. + * as well as checked if they occurred. * * DMABRGI0 services USB DMA Address errors, but it still must be * enabled/acked in the DMABRGCR register. USB-DMA complete indicator diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c index 381306cf542..e1284fc6936 100644 --- a/arch/sh/drivers/pci/ops-dreamcast.c +++ b/arch/sh/drivers/pci/ops-dreamcast.c @@ -57,7 +57,7 @@ struct pci_channel board_pci_channels[] = { * * Also, we could very easily support both Type 0 and Type 1 configurations * here, but since it doesn't seem that there is any such implementation in - * existance, we don't bother. + * existence, we don't bother. * * I suppose if someone actually gets around to ripping the chip out of * the BBA and hanging some more devices off of it, then this might be diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c index d67656a44b1..543417ff831 100644 --- a/arch/sh/drivers/pci/pci-st40.c +++ b/arch/sh/drivers/pci/pci-st40.c @@ -292,7 +292,7 @@ int __init st40pci_init(unsigned memStart, unsigned memSize) PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_IO); - /* Accesse to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000 + /* Access to the 0xb0000000 -> 0xb6000000 area will go through to 0x10000000 -> 0x16000000 * on the PCI bus. This allows a nice 1-1 bus to phys mapping. */ @@ -315,7 +315,7 @@ int __init st40pci_init(unsigned memStart, unsigned memSize) ST40PCI_WRITE(CSR_MBAR0, 0); ST40PCI_WRITE(LSR0, 0x0fff0001); - /* ... and set up the initial incomming window to expose all of RAM */ + /* ... and set up the initial incoming window to expose all of RAM */ pci_set_rbar_region(7, memStart, memStart, memSize); /* Maximise timeout values */ @@ -473,7 +473,7 @@ static void pci_set_rbar_region(unsigned int region, unsigned long localAddr mask = r2p2(regionSize) - 0x10000; - /* Diable the region (in case currently in use, should never happen) */ + /* Disable the region (in case currently in use, should never happen) */ ST40PCI_WRITE_INDEXED(RSR, region, 0); /* Start of local address space to publish */ diff --git a/arch/sh/drivers/pci/pci-st40.h b/arch/sh/drivers/pci/pci-st40.h index d729e0c2d5f..cf0d35bd135 100644 --- a/arch/sh/drivers/pci/pci-st40.h +++ b/arch/sh/drivers/pci/pci-st40.h @@ -4,7 +4,7 @@ * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * - * Defintions for the ST40 PCI hardware. + * Definitions for the ST40 PCI hardware. */ #ifndef __PCI_ST40_H__ diff --git a/arch/sh/drivers/superhyway/ops-sh4-202.c b/arch/sh/drivers/superhyway/ops-sh4-202.c index a55c98a9052..3b14bf860db 100644 --- a/arch/sh/drivers/superhyway/ops-sh4-202.c +++ b/arch/sh/drivers/superhyway/ops-sh4-202.c @@ -130,7 +130,7 @@ static int sh4202_read_vcr(unsigned long base, struct superhyway_vcr_info *vcr) * Some modules (PBR and ePBR for instance) also appear to have * VCRL/VCRH flipped in the documentation, but on the SH4-202 * itself it appears that these are all consistently mapped with - * VCRH preceeding VCRL. + * VCRH preceding VCRL. * * Do not trust the documentation, for it is evil. */ diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c index 0758d48147a..ebc73b85094 100644 --- a/arch/sh/kernel/cf-enabler.c +++ b/arch/sh/kernel/cf-enabler.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/vmalloc.h> +#include <linux/interrupt.h> #include <asm/io.h> #include <asm/irq.h> @@ -31,7 +32,7 @@ */ #if defined(CONFIG_CPU_SH4) /* SH4 can't access PCMCIA interface through P2 area. - * we must remap it with appropreate attribute bit of the page set. + * we must remap it with appropriate attribute bit of the page set. * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */ #if defined(CONFIG_CF_AREA6) @@ -149,6 +150,11 @@ static int __init cf_init_se(void) ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200); return 0; } +#else +static int __init cf_init_se(void) +{ + return -1; +} #endif int __init cf_init(void) diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 014f318f5a0..63251549e9a 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -278,6 +278,11 @@ arch_init_clk_ops(struct clk_ops **ops, int type) { } +void __init __attribute__ ((weak)) +arch_clk_init(void) +{ +} + static int show_clocks(char *buf, char **start, off_t off, int len, int *eof, void *data) { @@ -314,6 +319,8 @@ int __init clk_init(void) ret |= clk_register(clk); } + arch_clk_init(); + /* Kick the child clocks.. */ propagate_rate(&master_clk); propagate_rate(&bus_clk); diff --git a/arch/sh/kernel/cpu/irq/maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c index 492db31b3ca..978992e367a 100644 --- a/arch/sh/kernel/cpu/irq/maskreg.c +++ b/arch/sh/kernel/cpu/irq/maskreg.c @@ -38,7 +38,7 @@ static struct hw_interrupt_type maskreg_irq_type = { .end = end_maskreg_irq }; -/* actual implementatin */ +/* actual implementation */ static unsigned int startup_maskreg_irq(unsigned int irq) { enable_maskreg_irq(irq); diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 832c0b4a1e6..b0b59d4a33c 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -320,6 +320,9 @@ skip_restore: .align 2 5: .long 0x00001000 ! DSP +#ifdef CONFIG_KGDB_NMI +6: .long in_nmi +#endif 7: .long 0x30000000 ! common exception handler diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c index fcb2c41bc34..a33429463e9 100644 --- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c +++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c @@ -111,7 +111,7 @@ static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) return 0; } -static int shoc_clk_set_rate(struct clk *clk, unsigned long rate) +static int shoc_clk_set_rate(struct clk *clk, unsigned long rate, int algo_id) { unsigned long frqcr3; unsigned int tmp; diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index d61dd599169..c5a4fc77fa0 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c @@ -138,7 +138,7 @@ restore_fpu(struct task_struct *tsk) /* * Load the FPU with signalling NANS. This bit pattern we're using * has the property that no matter wether considered as single or as - * double precission represents signaling NANS. + * double precision represents signaling NANS. */ static void diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index 8cd04904c77..fab2eb07196 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -12,6 +12,7 @@ */ #include <linux/init.h> #include <linux/io.h> +#include <linux/smp.h> #include <asm/processor.h> #include <asm/cache.h> diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c index 6f8f458912c..03b14cf78dd 100644 --- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c +++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c @@ -106,6 +106,7 @@ static struct ipr_data sh7750_ipr_map[] = { { 38, 2, 8, 7 }, /* DMAC DMAE */ }; +#ifdef CONFIG_CPU_SUBTYPE_SH7751 static struct ipr_data sh7751_ipr_map[] = { { 44, 2, 8, 7 }, /* DMAC DMTE4 */ { 45, 2, 8, 7 }, /* DMAC DMTE5 */ @@ -117,6 +118,7 @@ static struct ipr_data sh7751_ipr_map[] = { /*{ 72, INTPRI00, 8, ? },*/ /* TMU3 TUNI */ /*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */ }; +#endif static unsigned long ipr_offsets[] = { 0xffd00004UL, /* 0: IPRA */ diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index 29090035bc5..51b386d454d 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -17,7 +17,6 @@ #include <asm/clock.h> #include <asm/freq.h> -#define SH7722_PLL_FREQ (32000000/8) #define N (-1) #define NM (-2) #define ROUND_NEAREST 0 @@ -141,28 +140,36 @@ static void adjust_clocks(int originate, int *l, unsigned long v[], */ static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 }; +static void master_clk_recalc(struct clk *clk) +{ + unsigned frqcr = ctrl_inl(FRQCR); + + clk->rate = CONFIG_SH_PCLK_FREQ * (((frqcr >> 24) & 0x1f) + 1); +} + static void master_clk_init(struct clk *clk) { - clk_set_rate(clk, clk_get_rate(clk)); + clk->parent = NULL; + clk->flags |= CLK_RATE_PROPAGATES; + clk->rate = CONFIG_SH_PCLK_FREQ; + master_clk_recalc(clk); } -static void master_clk_recalc(struct clk *clk) + +static void module_clk_recalc(struct clk *clk) { unsigned long frqcr = ctrl_inl(FRQCR); - clk->rate = CONFIG_SH_PCLK_FREQ * (1 + (frqcr >> 24 & 0xF)); + clk->rate = clk->parent->rate / (((frqcr >> 24) & 0x1f) + 1); } static int master_clk_setrate(struct clk *clk, unsigned long rate, int id) { - int div = rate / SH7722_PLL_FREQ; + int div = rate / clk->rate; int master_divs[] = { 2, 3, 4, 6, 8, 16 }; int index; unsigned long frqcr; - if (rate < SH7722_PLL_FREQ * 2) - return -EINVAL; - for (index = 1; index < ARRAY_SIZE(master_divs); index++) if (div >= master_divs[index - 1] && div < master_divs[index]) break; @@ -185,6 +192,10 @@ static struct clk_ops sh7722_master_clk_ops = { .set_rate = master_clk_setrate, }; +static struct clk_ops sh7722_module_clk_ops = { + .recalc = module_clk_recalc, +}; + struct frqcr_context { unsigned mask; unsigned shift; @@ -489,7 +500,7 @@ static void sh7722_siu_recalc(struct clk *clk) if (siu < 0) return /* siu */ ; - BUG_ON(siu > 1); + BUG_ON(siu > 2); r = ctrl_inl(sh7722_siu_regs[siu]); clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF]; } @@ -571,7 +582,7 @@ static struct clk *sh7722_clocks[] = { */ struct clk_ops *onchip_ops[] = { &sh7722_master_clk_ops, - &sh7722_frqcr_clk_ops, + &sh7722_module_clk_ops, &sh7722_frqcr_clk_ops, &sh7722_frqcr_clk_ops, }; @@ -583,7 +594,7 @@ arch_init_clk_ops(struct clk_ops **ops, int type) *ops = onchip_ops[type]; } -int __init sh7722_clock_init(void) +int __init arch_clk_init(void) { struct clk *master; int i; @@ -597,4 +608,3 @@ int __init sh7722_clock_init(void) clk_put(master); return 0; } -arch_initcall(sh7722_clock_init); diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c index a5323364cbc..edd1ec214e6 100644 --- a/arch/sh/kernel/kgdb_stub.c +++ b/arch/sh/kernel/kgdb_stub.c @@ -2,7 +2,7 @@ * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * - * Containes extracts from code by Glenn Engel, Jim Kingdon, + * Contains extracts from code by Glenn Engel, Jim Kingdon, * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>, * Amit S. Kale <akale@veritas.com>, William Gatliff <bgat@open-widgets.com>, * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>. @@ -85,7 +85,7 @@ * * Responses can be run-length encoded to save space. A '*' means that * the next character is an ASCII encoding giving a repeat count which - * stands for that many repititions of the character preceding the '*'. + * stands for that many repetitions of the character preceding the '*'. * The encoding is n+29, yielding a printable character where n >=3 * (which is where RLE starts to win). Don't use an n > 126. * diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 6b4f5748d0b..a11e2aa73cb 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -26,8 +26,6 @@ static int hlt_counter; int ubc_usercnt = 0; -#define HARD_IDLE_TIMEOUT (HZ / 3) - void (*pm_idle)(void); void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); @@ -44,16 +42,39 @@ void enable_hlt(void) } EXPORT_SYMBOL(enable_hlt); +static int __init nohlt_setup(char *__unused) +{ + hlt_counter = 1; + return 1; +} +__setup("nohlt", nohlt_setup); + +static int __init hlt_setup(char *__unused) +{ + hlt_counter = 0; + return 1; +} +__setup("hlt", hlt_setup); + void default_idle(void) { - if (!hlt_counter) - cpu_sleep(); - else - cpu_relax(); + if (!hlt_counter) { + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb__after_clear_bit(); + set_bl_bit(); + while (!need_resched()) + cpu_sleep(); + clear_bl_bit(); + set_thread_flag(TIF_POLLING_NRFLAG); + } else + while (!need_resched()) + cpu_relax(); } void cpu_idle(void) { + set_thread_flag(TIF_POLLING_NRFLAG); + /* endless idle loop with no priority at all */ while (1) { void (*idle)(void) = pm_idle; diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index dbebaddcfe3..283e1425ced 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c @@ -10,6 +10,8 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ + +#include <linux/err.h> #include <linux/cache.h> #include <linux/cpumask.h> #include <linux/delay.h> diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S index 4357d1a6358..7db1c2dc599 100644 --- a/arch/sh/kernel/syscalls.S +++ b/arch/sh/kernel/syscalls.S @@ -355,3 +355,6 @@ ENTRY(sys_call_table) .long sys_getcpu .long sys_epoll_pwait .long sys_utimensat /* 320 */ + .long sys_signalfd + .long sys_timerfd + .long sys_eventfd diff --git a/arch/sh/kernel/timers/timer.c b/arch/sh/kernel/timers/timer.c index a6bcc913d25..4e7e747d1b6 100644 --- a/arch/sh/kernel/timers/timer.c +++ b/arch/sh/kernel/timers/timer.c @@ -13,7 +13,7 @@ #include <linux/string.h> #include <asm/timer.h> -static struct sys_timer *sys_timers[] __initdata = { +static struct sys_timer *sys_timers[] = { #ifdef CONFIG_SH_TMU &tmu_timer, #endif @@ -26,7 +26,7 @@ static struct sys_timer *sys_timers[] __initdata = { NULL, }; -static char timer_override[10] __initdata; +static char timer_override[10]; static int __init timer_setup(char *str) { if (str) @@ -53,4 +53,3 @@ struct sys_timer *get_sys_timer(void) return NULL; } - diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 3a197649cd8..5b75cb6f8f9 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -21,6 +21,7 @@ #include <linux/bug.h> #include <linux/debug_locks.h> #include <linux/kdebug.h> +#include <linux/kexec.h> #include <linux/limits.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -101,6 +102,16 @@ void die(const char * str, struct pt_regs * regs, long err) bust_spinlocks(0); spin_unlock_irq(&die_lock); + + if (kexec_should_crash(current)) + crash_kexec(regs); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) + panic("Fatal exception"); + do_exit(SIGSEGV); } @@ -513,7 +524,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) * misaligned data access * access to >= 0x80000000 is user mode * Unfortuntaly we can't distinguish between instruction address error - * and data address errors caused by read acceses. + * and data address errors caused by read accesses. */ asmlinkage void do_address_error(struct pt_regs *regs, unsigned long writeaccess, diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c index e146bafcd14..2aa9438361b 100644 --- a/arch/sh/kernel/vsyscall/vsyscall.c +++ b/arch/sh/kernel/vsyscall/vsyscall.c @@ -17,6 +17,7 @@ #include <linux/gfp.h> #include <linux/module.h> #include <linux/elf.h> +#include <linux/sched.h> /* * Should the kernel map a VDSO page into processes and pass its diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c index 1efbac15ff4..a38e1eed9e7 100644 --- a/arch/sh/math-emu/math.c +++ b/arch/sh/math-emu/math.c @@ -148,7 +148,7 @@ fmac(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n) return 0; } -// to process fmov's extention (odd n for DR access XD). +// to process fmov's extension (odd n for DR access XD). #define FMOV_EXT(x) if(x&1) x+=16-1 static int diff --git a/arch/sh/mm/copy_page.S b/arch/sh/mm/copy_page.S index 397c94c9731..ae039f2da16 100644 --- a/arch/sh/mm/copy_page.S +++ b/arch/sh/mm/copy_page.S @@ -129,6 +129,7 @@ ENTRY(__copy_user_page) rts nop #endif + .align 2 .Lpsz: .long PAGE_SIZE /* * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n); diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 9207da67ff8..c878faa4ae4 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c @@ -15,43 +15,11 @@ #include <linux/mm.h> #include <linux/hardirq.h> #include <linux/kprobes.h> -#include <linux/kdebug.h> #include <asm/system.h> #include <asm/mmu_context.h> #include <asm/tlbflush.h> #include <asm/kgdb.h> -#ifdef CONFIG_KPROBES -ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); - -/* Hook to register for page fault notifications */ -int register_page_fault_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); -} - -int unregister_page_fault_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); -} - -static inline int notify_page_fault(enum die_val val, struct pt_regs *regs, - int trap, int sig) -{ - struct die_args args = { - .regs = regs, - .trapnr = trap, - }; - return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); -} -#else -static inline int notify_page_fault(enum die_val val, struct pt_regs *regs, - int trap, int sig) -{ - return NOTIFY_DONE; -} -#endif - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -69,11 +37,6 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, siginfo_t info; trace_hardirqs_on(); - - if (notify_page_fault(DIE_PAGE_FAULT, regs, - writeaccess, SIGSEGV) == NOTIFY_STOP) - return; - local_irq_enable(); #ifdef CONFIG_SH_KGDB @@ -285,7 +248,7 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, pte_t *pte; pte_t entry; struct mm_struct *mm = current->mm; - spinlock_t *ptl; + spinlock_t *ptl = NULL; int ret = 1; #ifdef CONFIG_SH_KGDB diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 8fe223a890e..e0e644ff320 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/bootmem.h> #include <linux/proc_fs.h> +#include <linux/pagemap.h> #include <linux/percpu.h> #include <linux/io.h> #include <asm/mmu_context.h> @@ -112,7 +113,7 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot) * As a performance optimization, other platforms preserve the fixmap mapping * across a context switch, we don't presently do this, but this could be done * in a similar fashion as to the wired TLB interface that sh64 uses (by way - * of the memorry mapped UTLB configuration) -- this unfortunately forces us to + * of the memory mapped UTLB configuration) -- this unfortunately forces us to * give up a TLB entry for each mapping we want to preserve. While this may be * viable for a small number of fixmaps, it's not particularly useful for * everything and needs to be carefully evaluated. (ie, we may want this for diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c index be03d74e99c..0c7b7e33abd 100644 --- a/arch/sh/mm/ioremap.c +++ b/arch/sh/mm/ioremap.c @@ -22,6 +22,7 @@ #include <asm/addrspace.h> #include <asm/cacheflush.h> #include <asm/tlbflush.h> +#include <asm/mmu.h> /* * Remap an arbitrary physical address space into the kernel virtual diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 02aae06527d..b6a5a338145 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -3,7 +3,7 @@ * * Privileged Space Mapping Buffer (PMB) Support. * - * Copyright (C) 2005, 2006 Paul Mundt + * Copyright (C) 2005, 2006, 2007 Paul Mundt * * P1/P2 Section mapping definitions from map32.h, which was: * @@ -68,6 +68,32 @@ static inline unsigned long mk_pmb_data(unsigned int entry) return mk_pmb_entry(entry) | PMB_DATA; } +static DEFINE_SPINLOCK(pmb_list_lock); +static struct pmb_entry *pmb_list; + +static inline void pmb_list_add(struct pmb_entry *pmbe) +{ + struct pmb_entry **p, *tmp; + + p = &pmb_list; + while ((tmp = *p) != NULL) + p = &tmp->next; + + pmbe->next = tmp; + *p = pmbe; +} + +static inline void pmb_list_del(struct pmb_entry *pmbe) +{ + struct pmb_entry **p, *tmp; + + for (p = &pmb_list; (tmp = *p); p = &tmp->next) + if (tmp == pmbe) { + *p = tmp->next; + return; + } +} + struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn, unsigned long flags) { @@ -81,11 +107,19 @@ struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn, pmbe->ppn = ppn; pmbe->flags = flags; + spin_lock_irq(&pmb_list_lock); + pmb_list_add(pmbe); + spin_unlock_irq(&pmb_list_lock); + return pmbe; } void pmb_free(struct pmb_entry *pmbe) { + spin_lock_irq(&pmb_list_lock); + pmb_list_del(pmbe); + spin_unlock_irq(&pmb_list_lock); + kmem_cache_free(pmb_cache, pmbe); } @@ -167,31 +201,6 @@ void clear_pmb_entry(struct pmb_entry *pmbe) clear_bit(entry, &pmb_map); } -static DEFINE_SPINLOCK(pmb_list_lock); -static struct pmb_entry *pmb_list; - -static inline void pmb_list_add(struct pmb_entry *pmbe) -{ - struct pmb_entry **p, *tmp; - - p = &pmb_list; - while ((tmp = *p) != NULL) - p = &tmp->next; - - pmbe->next = tmp; - *p = pmbe; -} - -static inline void pmb_list_del(struct pmb_entry *pmbe) -{ - struct pmb_entry **p, *tmp; - - for (p = &pmb_list; (tmp = *p); p = &tmp->next) - if (tmp == pmbe) { - *p = tmp->next; - return; - } -} static struct { unsigned long size; @@ -283,25 +292,14 @@ void pmb_unmap(unsigned long addr) } while (pmbe); } -static void pmb_cache_ctor(void *pmb, struct kmem_cache *cachep, unsigned long flags) +static void pmb_cache_ctor(void *pmb, struct kmem_cache *cachep, + unsigned long flags) { struct pmb_entry *pmbe = pmb; memset(pmb, 0, sizeof(struct pmb_entry)); - spin_lock_irq(&pmb_list_lock); - pmbe->entry = PMB_NO_ENTRY; - pmb_list_add(pmbe); - - spin_unlock_irq(&pmb_list_lock); -} - -static void pmb_cache_dtor(void *pmb, struct kmem_cache *cachep, unsigned long flags) -{ - spin_lock_irq(&pmb_list_lock); - pmb_list_del(pmb); - spin_unlock_irq(&pmb_list_lock); } static int __init pmb_init(void) @@ -312,8 +310,7 @@ static int __init pmb_init(void) BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES)); pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0, - SLAB_PANIC, pmb_cache_ctor, - pmb_cache_dtor); + SLAB_PANIC, pmb_cache_ctor, NULL); jump_to_P2(); diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types index 554f801db67..fb40f188aff 100644 --- a/arch/sh/tools/mach-types +++ b/arch/sh/tools/mach-types @@ -7,8 +7,11 @@ # SE SH_SOLUTION_ENGINE 7751SE SH_7751_SOLUTION_ENGINE +7722SE SH_7722_SOLUTION_ENGINE 7300SE SH_7300_SOLUTION_ENGINE 7343SE SH_7343_SOLUTION_ENGINE +7206SE SH_7206_SOLUTION_ENGINE +7619SE SH_7619_SOLUTION_ENGINE 7780SE SH_7780_SOLUTION_ENGINE 73180SE SH_73180_SOLUTION_ENGINE 7751SYSTEMH SH_7751_SYSTEMH @@ -31,5 +34,3 @@ R7785RP SH_R7785RP TITAN SH_TITAN SHMIN SH_SHMIN 7710VOIPGW SH_7710VOIPGW -7206SE SH_7206_SOLUTION_ENGINE -7619SE SH_7619_SOLUTION_ENGINE diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c index fb51660847c..3334f99b583 100644 --- a/arch/sh64/kernel/pci_sh5.c +++ b/arch/sh64/kernel/pci_sh5.c @@ -521,10 +521,10 @@ void __init pcibios_fixup_bus(struct pci_bus *bus) bus->resource[0]->start = PCIBIOS_MIN_IO; bus->resource[1]->start = PCIBIOS_MIN_MEM; #else - bus->resource[0]->end = 0 - bus->resource[1]->end = 0 - bus->resource[0]->start =0 - bus->resource[1]->start = 0; + bus->resource[0]->end = 0; + bus->resource[1]->end = 0; + bus->resource[0]->start =0; + bus->resource[1]->start = 0; #endif /* Turn off downstream PF memory address range by default */ bus->resource[2]->start = 1024*1024; diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index bd992c0048f..fbcc00c6c06 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -178,6 +178,13 @@ config ARCH_HAS_ILOG2_U64 bool default n +config EMULATED_CMPXCHG + bool + default y + help + Sparc32 does not have a CAS instruction like sparc64. cmpxchg() + is emulated, and therefore it is not completely atomic. + config SUN_PM bool default y diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index f1401b57ccc..7b4612da74a 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -148,7 +148,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) } /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ -static void __init kick_start_clock(void) +static void __devinit kick_start_clock(void) { struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned char sec; @@ -223,7 +223,7 @@ static __inline__ int has_low_battery(void) return (data1 == data2); /* Was the write blocked? */ } -static void __init mostek_set_system_time(void) +static void __devinit mostek_set_system_time(void) { unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs; diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 559335f4917..cbddeb38ffd 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -2,6 +2,7 @@ * atomic32.c: 32-bit atomic_t implementation * * Copyright (C) 2004 Keith M Wesolowski + * Copyright (C) 2007 Kyle McMartin * * Based on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf */ @@ -117,3 +118,17 @@ unsigned long ___change_bit(unsigned long *addr, unsigned long mask) return old & mask; } EXPORT_SYMBOL(___change_bit); + +unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new) +{ + unsigned long flags; + u32 prev; + + spin_lock_irqsave(ATOMIC_HASH(ptr), flags); + if ((prev = *ptr) == old) + *ptr = new; + spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags); + + return (unsigned long)prev; +} +EXPORT_SYMBOL(__cmpxchg_u32); diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 831781cab27..89a1b469b93 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -147,10 +147,10 @@ config SMP If you don't know what to do here, say N. config NR_CPUS - int "Maximum number of CPUs (2-64)" - range 2 64 + int "Maximum number of CPUs (2-1024)" + range 2 1024 depends on SMP - default "32" + default "64" source "drivers/cpufreq/Kconfig" @@ -396,6 +396,15 @@ config SCHED_SMT when dealing with UltraSPARC cpus at a cost of slightly increased overhead in some places. If unsure say N here. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + default y + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + source "kernel/Kconfig.preempt" config CMDLINE_BOOL diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index c749dccacc3..f964bf28d21 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.70 2002/02/09 19:49:30 davem Exp $ +# # Makefile for the linux kernel. # @@ -8,11 +8,11 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ - traps.o devices.o auxio.o una_asm.o \ + traps.o auxio.o una_asm.o sysfs.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ - visemul.o prom.o of_device.o hvapi.o + visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c deleted file mode 100644 index 0e03c8e218c..00000000000 --- a/arch/sparc64/kernel/devices.c +++ /dev/null @@ -1,196 +0,0 @@ -/* devices.c: Initial scan of the prom device tree for important - * Sparc device nodes which we need to find. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include <linux/kernel.h> -#include <linux/threads.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/string.h> -#include <linux/spinlock.h> -#include <linux/errno.h> -#include <linux/bootmem.h> - -#include <asm/page.h> -#include <asm/oplib.h> -#include <asm/system.h> -#include <asm/smp.h> -#include <asm/spitfire.h> -#include <asm/timer.h> -#include <asm/cpudata.h> - -/* Used to synchronize accesses to NatSemi SUPER I/O chip configure - * operations in asm/ns87303.h - */ -DEFINE_SPINLOCK(ns87303_lock); - -extern void cpu_probe(void); -extern void central_probe(void); - -static const char *cpu_mid_prop(void) -{ - if (tlb_type == spitfire) - return "upa-portid"; - return "portid"; -} - -static int get_cpu_mid(struct device_node *dp) -{ - struct property *prop; - - if (tlb_type == hypervisor) { - struct linux_prom64_registers *reg; - int len; - - prop = of_find_property(dp, "cpuid", &len); - if (prop && len == 4) - return *(int *) prop->value; - - prop = of_find_property(dp, "reg", NULL); - reg = prop->value; - return (reg[0].phys_addr >> 32) & 0x0fffffffUL; - } else { - const char *prop_name = cpu_mid_prop(); - - prop = of_find_property(dp, prop_name, NULL); - if (prop) - return *(int *) prop->value; - return 0; - } -} - -static int check_cpu_node(struct device_node *dp, int *cur_inst, - int (*compare)(struct device_node *, int, void *), - void *compare_arg, - struct device_node **dev_node, int *mid) -{ - if (!compare(dp, *cur_inst, compare_arg)) { - if (dev_node) - *dev_node = dp; - if (mid) - *mid = get_cpu_mid(dp); - return 0; - } - - (*cur_inst)++; - - return -ENODEV; -} - -static int __cpu_find_by(int (*compare)(struct device_node *, int, void *), - void *compare_arg, - struct device_node **dev_node, int *mid) -{ - struct device_node *dp; - int cur_inst; - - cur_inst = 0; - for_each_node_by_type(dp, "cpu") { - int err = check_cpu_node(dp, &cur_inst, - compare, compare_arg, - dev_node, mid); - if (err == 0) - return 0; - } - - return -ENODEV; -} - -static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg) -{ - int desired_instance = (int) (long) _arg; - - if (instance == desired_instance) - return 0; - return -ENODEV; -} - -int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid) -{ - return __cpu_find_by(cpu_instance_compare, (void *)(long)instance, - dev_node, mid); -} - -static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg) -{ - int desired_mid = (int) (long) _arg; - int this_mid; - - this_mid = get_cpu_mid(dp); - if (this_mid == desired_mid) - return 0; - return -ENODEV; -} - -int cpu_find_by_mid(int mid, struct device_node **dev_node) -{ - return __cpu_find_by(cpu_mid_compare, (void *)(long)mid, - dev_node, NULL); -} - -void __init device_scan(void) -{ - /* FIX ME FAST... -DaveM */ - ioport_resource.end = 0xffffffffffffffffUL; - - prom_printf("Booting Linux...\n"); - -#ifndef CONFIG_SMP - { - struct device_node *dp; - int err, def; - - err = cpu_find_by_instance(0, &dp, NULL); - if (err) { - prom_printf("No cpu nodes, cannot continue\n"); - prom_halt(); - } - cpu_data(0).clock_tick = - of_getintprop_default(dp, "clock-frequency", 0); - - def = ((tlb_type == hypervisor) ? - (8 * 1024) : - (16 * 1024)); - cpu_data(0).dcache_size = of_getintprop_default(dp, - "dcache-size", - def); - - def = 32; - cpu_data(0).dcache_line_size = - of_getintprop_default(dp, "dcache-line-size", def); - - def = 16 * 1024; - cpu_data(0).icache_size = of_getintprop_default(dp, - "icache-size", - def); - - def = 32; - cpu_data(0).icache_line_size = - of_getintprop_default(dp, "icache-line-size", def); - - def = ((tlb_type == hypervisor) ? - (3 * 1024 * 1024) : - (4 * 1024 * 1024)); - cpu_data(0).ecache_size = of_getintprop_default(dp, - "ecache-size", - def); - - def = 64; - cpu_data(0).ecache_line_size = - of_getintprop_default(dp, "ecache-line-size", def); - printk("CPU[0]: Caches " - "D[sz(%d):line_sz(%d)] " - "I[sz(%d):line_sz(%d)] " - "E[sz(%d):line_sz(%d)]\n", - cpu_data(0).dcache_size, cpu_data(0).dcache_line_size, - cpu_data(0).icache_size, cpu_data(0).icache_line_size, - cpu_data(0).ecache_size, cpu_data(0).ecache_line_size); - } -#endif - - central_probe(); - - cpu_probe(); -} diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 732b77cb71f..8059531bf0a 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1725,96 +1725,142 @@ real_hard_smp_processor_id: * returns %o0: sysino */ .globl sun4v_devino_to_sysino + .type sun4v_devino_to_sysino,#function sun4v_devino_to_sysino: mov HV_FAST_INTR_DEVINO2SYSINO, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino /* %o0: sysino * * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED}) */ .globl sun4v_intr_getenabled + .type sun4v_intr_getenabled,#function sun4v_intr_getenabled: mov HV_FAST_INTR_GETENABLED, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_intr_getenabled, .-sun4v_intr_getenabled /* %o0: sysino * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED}) */ .globl sun4v_intr_setenabled + .type sun4v_intr_setenabled,#function sun4v_intr_setenabled: mov HV_FAST_INTR_SETENABLED, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_intr_setenabled, .-sun4v_intr_setenabled /* %o0: sysino * * returns %o0: intr_state (HV_INTR_STATE_*) */ .globl sun4v_intr_getstate + .type sun4v_intr_getstate,#function sun4v_intr_getstate: mov HV_FAST_INTR_GETSTATE, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_intr_getstate, .-sun4v_intr_getstate /* %o0: sysino * %o1: intr_state (HV_INTR_STATE_*) */ .globl sun4v_intr_setstate + .type sun4v_intr_setstate,#function sun4v_intr_setstate: mov HV_FAST_INTR_SETSTATE, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_intr_setstate, .-sun4v_intr_setstate /* %o0: sysino * * returns %o0: cpuid */ .globl sun4v_intr_gettarget + .type sun4v_intr_gettarget,#function sun4v_intr_gettarget: mov HV_FAST_INTR_GETTARGET, %o5 ta HV_FAST_TRAP retl mov %o1, %o0 + .size sun4v_intr_gettarget, .-sun4v_intr_gettarget /* %o0: sysino * %o1: cpuid */ .globl sun4v_intr_settarget + .type sun4v_intr_settarget,#function sun4v_intr_settarget: mov HV_FAST_INTR_SETTARGET, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_intr_settarget, .-sun4v_intr_settarget - /* %o0: type - * %o1: queue paddr - * %o2: num queue entries + /* %o0: cpuid + * %o1: pc + * %o2: rtba + * %o3: arg0 * * returns %o0: status */ - .globl sun4v_cpu_qconf -sun4v_cpu_qconf: - mov HV_FAST_CPU_QCONF, %o5 + .globl sun4v_cpu_start + .type sun4v_cpu_start,#function +sun4v_cpu_start: + mov HV_FAST_CPU_START, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_cpu_start, .-sun4v_cpu_start - /* returns %o0: status + /* %o0: cpuid + * + * returns %o0: status */ + .globl sun4v_cpu_stop + .type sun4v_cpu_stop,#function +sun4v_cpu_stop: + mov HV_FAST_CPU_STOP, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_stop, .-sun4v_cpu_stop + + /* returns %o0: status */ .globl sun4v_cpu_yield + .type sun4v_cpu_yield, #function sun4v_cpu_yield: mov HV_FAST_CPU_YIELD, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_cpu_yield, .-sun4v_cpu_yield + + /* %o0: type + * %o1: queue paddr + * %o2: num queue entries + * + * returns %o0: status + */ + .globl sun4v_cpu_qconf + .type sun4v_cpu_qconf,#function +sun4v_cpu_qconf: + mov HV_FAST_CPU_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_cpu_qconf, .-sun4v_cpu_qconf /* %o0: num cpus in cpu list * %o1: cpu list paddr @@ -1823,11 +1869,13 @@ sun4v_cpu_yield: * returns %o0: status */ .globl sun4v_cpu_mondo_send + .type sun4v_cpu_mondo_send,#function sun4v_cpu_mondo_send: mov HV_FAST_CPU_MONDO_SEND, %o5 ta HV_FAST_TRAP retl nop + .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send /* %o0: CPU ID * @@ -1835,6 +1883,7 @@ sun4v_cpu_mondo_send: * %o0: cpu state as HV_CPU_STATE_* */ .globl sun4v_cpu_state + .type sun4v_cpu_state,#function sun4v_cpu_state: mov HV_FAST_CPU_STATE, %o5 ta HV_FAST_TRAP @@ -1843,6 +1892,37 @@ sun4v_cpu_state: mov %o1, %o0 1: retl nop + .size sun4v_cpu_state, .-sun4v_cpu_state + + /* %o0: virtual address + * %o1: must be zero + * %o2: TTE + * %o3: HV_MMU_* flags + * + * returns %o0: status + */ + .globl sun4v_mmu_map_perm_addr + .type sun4v_mmu_map_perm_addr,#function +sun4v_mmu_map_perm_addr: + mov HV_FAST_MMU_MAP_PERM_ADDR, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr + + /* %o0: number of TSB descriptions + * %o1: TSB descriptions real address + * + * returns %o0: status + */ + .globl sun4v_mmu_tsb_ctx0 + .type sun4v_mmu_tsb_ctx0,#function +sun4v_mmu_tsb_ctx0: + mov HV_FAST_MMU_TSB_CTX0, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0 /* %o0: API group number * %o1: pointer to unsigned long major number storage @@ -1851,6 +1931,7 @@ sun4v_cpu_state: * returns %o0: status */ .globl sun4v_get_version + .type sun4v_get_version,#function sun4v_get_version: mov HV_CORE_GET_VER, %o5 mov %o1, %o3 @@ -1859,6 +1940,7 @@ sun4v_get_version: stx %o1, [%o3] retl stx %o2, [%o4] + .size sun4v_get_version, .-sun4v_get_version /* %o0: API group number * %o1: desired major number @@ -1868,18 +1950,49 @@ sun4v_get_version: * returns %o0: status */ .globl sun4v_set_version + .type sun4v_set_version,#function sun4v_set_version: mov HV_CORE_SET_VER, %o5 mov %o3, %o4 ta HV_CORE_TRAP retl stx %o1, [%o4] + .size sun4v_set_version, .-sun4v_set_version + + /* %o0: pointer to unsigned long time + * + * returns %o0: status + */ + .globl sun4v_tod_get + .type sun4v_tod_get,#function +sun4v_tod_get: + mov %o0, %o4 + mov HV_FAST_TOD_GET, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_tod_get, .-sun4v_tod_get + + /* %o0: time + * + * returns %o0: status + */ + .globl sun4v_tod_set + .type sun4v_tod_set,#function +sun4v_tod_set: + mov HV_FAST_TOD_SET, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_tod_set, .-sun4v_tod_set /* %o0: pointer to unsigned long status * * returns %o0: signed character */ .globl sun4v_con_getchar + .type sun4v_con_getchar,#function sun4v_con_getchar: mov %o0, %o4 mov HV_FAST_CONS_GETCHAR, %o5 @@ -1889,17 +2002,20 @@ sun4v_con_getchar: stx %o0, [%o4] retl sra %o1, 0, %o0 + .size sun4v_con_getchar, .-sun4v_con_getchar /* %o0: signed long character * * returns %o0: status */ .globl sun4v_con_putchar + .type sun4v_con_putchar,#function sun4v_con_putchar: mov HV_FAST_CONS_PUTCHAR, %o5 ta HV_FAST_TRAP retl sra %o0, 0, %o0 + .size sun4v_con_putchar, .-sun4v_con_putchar /* %o0: buffer real address * %o1: buffer size @@ -1908,6 +2024,7 @@ sun4v_con_putchar: * returns %o0: status */ .globl sun4v_con_read + .type sun4v_con_read,#function sun4v_con_read: mov %o2, %o4 mov HV_FAST_CONS_READ, %o5 @@ -1922,6 +2039,7 @@ sun4v_con_read: stx %o1, [%o4] 1: retl nop + .size sun4v_con_read, .-sun4v_con_read /* %o0: buffer real address * %o1: buffer size @@ -1930,6 +2048,7 @@ sun4v_con_read: * returns %o0: status */ .globl sun4v_con_write + .type sun4v_con_write,#function sun4v_con_write: mov %o2, %o4 mov HV_FAST_CONS_WRITE, %o5 @@ -1937,3 +2056,540 @@ sun4v_con_write: stx %o1, [%o4] retl nop + .size sun4v_con_write, .-sun4v_con_write + + /* %o0: soft state + * %o1: address of description string + * + * returns %o0: status + */ + .globl sun4v_mach_set_soft_state + .type sun4v_mach_set_soft_state,#function +sun4v_mach_set_soft_state: + mov HV_FAST_MACH_SET_SOFT_STATE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state + + /* %o0: exit code + * + * Does not return. + */ + .globl sun4v_mach_exit + .type sun4v_mach_exit,#function +sun4v_mach_exit: + mov HV_FAST_MACH_EXIT, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_mach_exit, .-sun4v_mach_exit + + /* %o0: buffer real address + * %o1: buffer length + * %o2: pointer to unsigned long real_buf_len + * + * returns %o0: status + */ + .globl sun4v_mach_desc + .type sun4v_mach_desc,#function +sun4v_mach_desc: + mov %o2, %o4 + mov HV_FAST_MACH_DESC, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_desc, .-sun4v_mach_desc + + /* %o0: new timeout in milliseconds + * %o1: pointer to unsigned long orig_timeout + * + * returns %o0: status + */ + .globl sun4v_mach_set_watchdog + .type sun4v_mach_set_watchdog,#function +sun4v_mach_set_watchdog: + mov %o1, %o4 + mov HV_FAST_MACH_SET_WATCHDOG, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog + + /* No inputs and does not return. */ + .globl sun4v_mach_sir + .type sun4v_mach_sir,#function +sun4v_mach_sir: + mov %o1, %o4 + mov HV_FAST_MACH_SIR, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mach_sir, .-sun4v_mach_sir + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_qconf + .type sun4v_ldc_tx_qconf,#function +sun4v_ldc_tx_qconf: + mov HV_FAST_LDC_TX_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_qinfo + .type sun4v_ldc_tx_qinfo,#function +sun4v_ldc_tx_qinfo: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_TX_QINFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo + + /* %o0: channel + * %o1: pointer to unsigned long head_off + * %o2: pointer to unsigned long tail_off + * %o2: pointer to unsigned long chan_state + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_get_state + .type sun4v_ldc_tx_get_state,#function +sun4v_ldc_tx_get_state: + mov %o1, %g1 + mov %o2, %g2 + mov %o3, %g3 + mov HV_FAST_LDC_TX_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + stx %o3, [%g3] + retl + nop + .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state + + /* %o0: channel + * %o1: tail_off + * + * returns %o0: status + */ + .globl sun4v_ldc_tx_set_qtail + .type sun4v_ldc_tx_set_qtail,#function +sun4v_ldc_tx_set_qtail: + mov HV_FAST_LDC_TX_SET_QTAIL, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_qconf + .type sun4v_ldc_rx_qconf,#function +sun4v_ldc_rx_qconf: + mov HV_FAST_LDC_RX_QCONF, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_qinfo + .type sun4v_ldc_rx_qinfo,#function +sun4v_ldc_rx_qinfo: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_RX_QINFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo + + /* %o0: channel + * %o1: pointer to unsigned long head_off + * %o2: pointer to unsigned long tail_off + * %o2: pointer to unsigned long chan_state + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_get_state + .type sun4v_ldc_rx_get_state,#function +sun4v_ldc_rx_get_state: + mov %o1, %g1 + mov %o2, %g2 + mov %o3, %g3 + mov HV_FAST_LDC_RX_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + stx %o3, [%g3] + retl + nop + .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state + + /* %o0: channel + * %o1: head_off + * + * returns %o0: status + */ + .globl sun4v_ldc_rx_set_qhead + .type sun4v_ldc_rx_set_qhead,#function +sun4v_ldc_rx_set_qhead: + mov HV_FAST_LDC_RX_SET_QHEAD, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead + + /* %o0: channel + * %o1: ra + * %o2: num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_set_map_table + .type sun4v_ldc_set_map_table,#function +sun4v_ldc_set_map_table: + mov HV_FAST_LDC_SET_MAP_TABLE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table + + /* %o0: channel + * %o1: pointer to unsigned long ra + * %o2: pointer to unsigned long num_entries + * + * returns %o0: status + */ + .globl sun4v_ldc_get_map_table + .type sun4v_ldc_get_map_table,#function +sun4v_ldc_get_map_table: + mov %o1, %g1 + mov %o2, %g2 + mov HV_FAST_LDC_GET_MAP_TABLE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table + + /* %o0: channel + * %o1: dir_code + * %o2: tgt_raddr + * %o3: lcl_raddr + * %o4: len + * %o5: pointer to unsigned long actual_len + * + * returns %o0: status + */ + .globl sun4v_ldc_copy + .type sun4v_ldc_copy,#function +sun4v_ldc_copy: + mov %o5, %g1 + mov HV_FAST_LDC_COPY, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_ldc_copy, .-sun4v_ldc_copy + + /* %o0: channel + * %o1: cookie + * %o2: pointer to unsigned long ra + * %o3: pointer to unsigned long perm + * + * returns %o0: status + */ + .globl sun4v_ldc_mapin + .type sun4v_ldc_mapin,#function +sun4v_ldc_mapin: + mov %o2, %g1 + mov %o3, %g2 + mov HV_FAST_LDC_MAPIN, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + stx %o2, [%g2] + retl + nop + .size sun4v_ldc_mapin, .-sun4v_ldc_mapin + + /* %o0: ra + * + * returns %o0: status + */ + .globl sun4v_ldc_unmap + .type sun4v_ldc_unmap,#function +sun4v_ldc_unmap: + mov HV_FAST_LDC_UNMAP, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_unmap, .-sun4v_ldc_unmap + + /* %o0: channel + * %o1: cookie + * %o2: mte_cookie + * + * returns %o0: status + */ + .globl sun4v_ldc_revoke + .type sun4v_ldc_revoke,#function +sun4v_ldc_revoke: + mov HV_FAST_LDC_REVOKE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ldc_revoke, .-sun4v_ldc_revoke + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long cookie + * + * returns %o0: status + */ + .globl sun4v_vintr_get_cookie + .type sun4v_vintr_get_cookie,#function +sun4v_vintr_get_cookie: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_COOKIE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie + + /* %o0: device handle + * %o1: device INO + * %o2: cookie + * + * returns %o0: status + */ + .globl sun4v_vintr_set_cookie + .type sun4v_vintr_set_cookie,#function +sun4v_vintr_set_cookie: + mov HV_FAST_VINTR_SET_COOKIE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long valid_state + * + * returns %o0: status + */ + .globl sun4v_vintr_get_valid + .type sun4v_vintr_get_valid,#function +sun4v_vintr_get_valid: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_VALID, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid + + /* %o0: device handle + * %o1: device INO + * %o2: valid_state + * + * returns %o0: status + */ + .globl sun4v_vintr_set_valid + .type sun4v_vintr_set_valid,#function +sun4v_vintr_set_valid: + mov HV_FAST_VINTR_SET_VALID, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long state + * + * returns %o0: status + */ + .globl sun4v_vintr_get_state + .type sun4v_vintr_get_state,#function +sun4v_vintr_get_state: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_STATE, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_state, .-sun4v_vintr_get_state + + /* %o0: device handle + * %o1: device INO + * %o2: state + * + * returns %o0: status + */ + .globl sun4v_vintr_set_state + .type sun4v_vintr_set_state,#function +sun4v_vintr_set_state: + mov HV_FAST_VINTR_SET_STATE, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_state, .-sun4v_vintr_set_state + + /* %o0: device handle + * %o1: device INO + * %o2: pointer to unsigned long cpuid + * + * returns %o0: status + */ + .globl sun4v_vintr_get_target + .type sun4v_vintr_get_target,#function +sun4v_vintr_get_target: + mov %o2, %g1 + mov HV_FAST_VINTR_GET_TARGET, %o5 + ta HV_FAST_TRAP + stx %o1, [%g1] + retl + nop + .size sun4v_vintr_get_target, .-sun4v_vintr_get_target + + /* %o0: device handle + * %o1: device INO + * %o2: cpuid + * + * returns %o0: status + */ + .globl sun4v_vintr_set_target + .type sun4v_vintr_set_target,#function +sun4v_vintr_set_target: + mov HV_FAST_VINTR_SET_TARGET, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_vintr_set_target, .-sun4v_vintr_set_target + + /* %o0: NCS sub-function + * %o1: sub-function arg real-address + * %o2: sub-function arg size + * + * returns %o0: status + */ + .globl sun4v_ncs_request + .type sun4v_ncs_request,#function +sun4v_ncs_request: + mov HV_FAST_NCS_REQUEST, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_ncs_request, .-sun4v_ncs_request + + .globl sun4v_svc_send + .type sun4v_svc_send,#function +sun4v_svc_send: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov HV_FAST_SVC_SEND, %o5 + ta HV_FAST_TRAP + stx %o1, [%i3] + ret + restore + .size sun4v_svc_send, .-sun4v_svc_send + + .globl sun4v_svc_recv + .type sun4v_svc_recv,#function +sun4v_svc_recv: + save %sp, -192, %sp + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov HV_FAST_SVC_RECV, %o5 + ta HV_FAST_TRAP + stx %o1, [%i3] + ret + restore + .size sun4v_svc_recv, .-sun4v_svc_recv + + .globl sun4v_svc_getstatus + .type sun4v_svc_getstatus,#function +sun4v_svc_getstatus: + mov HV_FAST_SVC_GETSTATUS, %o5 + mov %o1, %o4 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_svc_getstatus, .-sun4v_svc_getstatus + + .globl sun4v_svc_setstatus + .type sun4v_svc_setstatus,#function +sun4v_svc_setstatus: + mov HV_FAST_SVC_SETSTATUS, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_svc_setstatus, .-sun4v_svc_setstatus + + .globl sun4v_svc_clrstatus + .type sun4v_svc_clrstatus,#function +sun4v_svc_clrstatus: + mov HV_FAST_SVC_CLRSTATUS, %o5 + ta HV_FAST_TRAP + retl + nop + .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus + + .globl sun4v_mmustat_conf + .type sun4v_mmustat_conf,#function +sun4v_mmustat_conf: + mov %o1, %o4 + mov HV_FAST_MMUSTAT_CONF, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_conf, .-sun4v_mmustat_conf + + .globl sun4v_mmustat_info + .type sun4v_mmustat_info,#function +sun4v_mmustat_info: + mov %o0, %o4 + mov HV_FAST_MMUSTAT_INFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_info, .-sun4v_mmustat_info diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index baea10a9819..77259526cb1 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -523,7 +523,7 @@ tlb_fixup_done: #else mov 0, %o0 #endif - stb %o0, [%g6 + TI_CPU] + sth %o0, [%g6 + TI_CPU] /* Off we go.... */ call start_kernel @@ -653,33 +653,54 @@ setup_tba: restore sparc64_boot_end: -#include "ktlb.S" -#include "tsb.S" #include "etrap.S" #include "rtrap.S" #include "winfixup.S" #include "entry.S" #include "sun4v_tlb_miss.S" #include "sun4v_ivec.S" +#include "ktlb.S" +#include "tsb.S" /* * The following skip makes sure the trap table in ttable.S is aligned * on a 32K boundary as required by the v9 specs for TBA register. * * We align to a 32K boundary, then we have the 32K kernel TSB, - * then the 32K aligned trap table. + * the 64K kernel 4MB TSB, and then the 32K aligned trap table. */ 1: .skip 0x4000 + _start - 1b +! 0x0000000000408000 + .globl swapper_tsb swapper_tsb: .skip (32 * 1024) -! 0x0000000000408000 + .globl swapper_4m_tsb +swapper_4m_tsb: + .skip (64 * 1024) + +! 0x0000000000420000 + /* Some care needs to be exercised if you try to move the + * location of the trap table relative to other things. For + * one thing there are br* instructions in some of the + * trap table entires which branch back to code in ktlb.S + * Those instructions can only handle a signed 16-bit + * displacement. + * + * There is a binutils bug (bugzilla #4558) which causes + * the relocation overflow checks for such instructions to + * not be done correctly. So bintuils will not notice the + * error and will instead write junk into the relocation and + * you'll have an unbootable kernel. + */ #include "ttable.S" +! 0x0000000000428000 + #include "systbls.S" .data diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c index f03ffc829c7..f34f5d6181e 100644 --- a/arch/sparc64/kernel/hvapi.c +++ b/arch/sparc64/kernel/hvapi.c @@ -9,6 +9,7 @@ #include <asm/hypervisor.h> #include <asm/oplib.h> +#include <asm/sstate.h> /* If the hypervisor indicates that the API setting * calls are unsupported, by returning HV_EBADTRAP or @@ -107,7 +108,7 @@ int sun4v_hvapi_register(unsigned long group, unsigned long major, p->minor = actual_minor; ret = 0; } else if (hv_ret == HV_EBADTRAP || - HV_ENOTSUPPORTED) { + hv_ret == HV_ENOTSUPPORTED) { if (p->flags & FLAG_PRE_API) { if (major == 1) { p->major = 1; @@ -179,6 +180,8 @@ void __init sun4v_hvapi_init(void) if (sun4v_hvapi_register(group, major, &minor)) goto bad; + sun4v_sstate_init(); + return; bad: diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 3edc18e1b81..e60d283f60b 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,7 +1,6 @@ -/* $Id: irq.c,v 1.114 2002/01/11 08:45:38 davem Exp $ - * irq.c: UltraSparc IRQ handling/init/registry. +/* irq.c: UltraSparc IRQ handling/init/registry. * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ @@ -43,6 +42,7 @@ #include <asm/cpudata.h> #include <asm/auxio.h> #include <asm/head.h> +#include <asm/hypervisor.h> /* UPA nodes send interrupt packet to UltraSparc with first data reg * value low 5 (7 on Starfire) bits holding the IRQ identifier being @@ -171,8 +171,6 @@ skip: return 0; } -extern unsigned long real_hard_smp_processor_id(void); - static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid) { unsigned int tid; @@ -382,6 +380,76 @@ static void sun4v_irq_end(unsigned int virt_irq) } } +static void sun4v_virq_enable(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; + + if (likely(bucket)) { + unsigned long cpuid, dev_handle, dev_ino; + int err; + + cpuid = irq_choose_cpu(virt_irq); + + dev_handle = ino & IMAP_IGN; + dev_ino = ino & IMAP_INO; + + err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); + if (err != HV_EOK) + printk("sun4v_vintr_set_target(%lx,%lx,%lu): " + "err(%d)\n", + dev_handle, dev_ino, cpuid, err); + err = sun4v_vintr_set_state(dev_handle, dev_ino, + HV_INTR_ENABLED); + if (err != HV_EOK) + printk("sun4v_vintr_set_state(%lx,%lx," + "HV_INTR_ENABLED): err(%d)\n", + dev_handle, dev_ino, err); + } +} + +static void sun4v_virq_disable(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; + + if (likely(bucket)) { + unsigned long dev_handle, dev_ino; + int err; + + dev_handle = ino & IMAP_IGN; + dev_ino = ino & IMAP_INO; + + err = sun4v_vintr_set_state(dev_handle, dev_ino, + HV_INTR_DISABLED); + if (err != HV_EOK) + printk("sun4v_vintr_set_state(%lx,%lx," + "HV_INTR_DISABLED): err(%d)\n", + dev_handle, dev_ino, err); + } +} + +static void sun4v_virq_end(unsigned int virt_irq) +{ + struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); + unsigned int ino = bucket - &ivector_table[0]; + + if (likely(bucket)) { + unsigned long dev_handle, dev_ino; + int err; + + dev_handle = ino & IMAP_IGN; + dev_ino = ino & IMAP_INO; + + err = sun4v_vintr_set_state(dev_handle, dev_ino, + HV_INTR_STATE_IDLE); + if (err != HV_EOK) + printk("sun4v_vintr_set_state(%lx,%lx," + "HV_INTR_STATE_IDLE): err(%d)\n", + dev_handle, dev_ino, err); + } +} + static void run_pre_handler(unsigned int virt_irq) { struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); @@ -436,6 +504,21 @@ static struct irq_chip sun4v_msi = { }; #endif +static struct irq_chip sun4v_virq = { + .typename = "vsun4v", + .enable = sun4v_virq_enable, + .disable = sun4v_virq_disable, + .end = sun4v_virq_end, +}; + +static struct irq_chip sun4v_virq_ack = { + .typename = "vsun4v+ack", + .enable = sun4v_virq_enable, + .disable = sun4v_virq_disable, + .ack = run_pre_handler, + .end = sun4v_virq_end, +}; + void irq_install_pre_handler(int virt_irq, void (*func)(unsigned int, void *, void *), void *arg1, void *arg2) @@ -449,7 +532,8 @@ void irq_install_pre_handler(int virt_irq, chip = get_irq_chip(virt_irq); if (chip == &sun4u_irq_ack || - chip == &sun4v_irq_ack + chip == &sun4v_irq_ack || + chip == &sun4v_virq_ack #ifdef CONFIG_PCI_MSI || chip == &sun4v_msi #endif @@ -457,7 +541,9 @@ void irq_install_pre_handler(int virt_irq, return; chip = (chip == &sun4u_irq ? - &sun4u_irq_ack : &sun4v_irq_ack); + &sun4u_irq_ack : + (chip == &sun4v_irq ? + &sun4v_irq_ack : &sun4v_virq_ack)); set_irq_chip(virt_irq, chip); } @@ -494,19 +580,18 @@ out: return bucket->virt_irq; } -unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) +static unsigned int sun4v_build_common(unsigned long sysino, + struct irq_chip *chip) { struct ino_bucket *bucket; struct irq_handler_data *data; - unsigned long sysino; BUG_ON(tlb_type != hypervisor); - sysino = sun4v_devino_to_sysino(devhandle, devino); bucket = &ivector_table[sysino]; if (!bucket->virt_irq) { bucket->virt_irq = virt_irq_alloc(__irq(bucket)); - set_irq_chip(bucket->virt_irq, &sun4v_irq); + set_irq_chip(bucket->virt_irq, chip); } data = get_irq_chip_data(bucket->virt_irq); @@ -531,6 +616,32 @@ out: return bucket->virt_irq; } +unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) +{ + unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino); + + return sun4v_build_common(sysino, &sun4v_irq); +} + +unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) +{ + unsigned long sysino, hv_err; + + BUG_ON(devhandle & ~IMAP_IGN); + BUG_ON(devino & ~IMAP_INO); + + sysino = devhandle | devino; + + hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino); + if (hv_err) { + prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] " + "err=%lu\n", devhandle, devino, hv_err); + prom_halt(); + } + + return sun4v_build_common(sysino, &sun4v_virq); +} + #ifdef CONFIG_PCI_MSI unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p, unsigned int msi_start, unsigned int msi_end) @@ -694,9 +805,20 @@ void init_irqwork_curcpu(void) trap_block[cpu].irq_worklist = 0; } -static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type) +/* Please be very careful with register_one_mondo() and + * sun4v_register_mondo_queues(). + * + * On SMP this gets invoked from the CPU trampoline before + * the cpu has fully taken over the trap table from OBP, + * and it's kernel stack + %g6 thread register state is + * not fully cooked yet. + * + * Therefore you cannot make any OBP calls, not even prom_printf, + * from these two routines. + */ +static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type, unsigned long qmask) { - unsigned long num_entries = 128; + unsigned long num_entries = (qmask + 1) / 64; unsigned long status; status = sun4v_cpu_qconf(type, paddr, num_entries); @@ -711,44 +833,58 @@ static void __cpuinit sun4v_register_mondo_queues(int this_cpu) { struct trap_per_cpu *tb = &trap_block[this_cpu]; - register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO); - register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO); - register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR); - register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR); + register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO, + tb->cpu_mondo_qmask); + register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO, + tb->dev_mondo_qmask); + register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR, + tb->resum_qmask); + register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR, + tb->nonresum_qmask); } -static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, int use_bootmem) +static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) { - void *page; + unsigned long size = PAGE_ALIGN(qmask + 1); + unsigned long order = get_order(size); + void *p = NULL; - if (use_bootmem) - page = alloc_bootmem_low_pages(PAGE_SIZE); - else - page = (void *) get_zeroed_page(GFP_ATOMIC); + if (use_bootmem) { + p = __alloc_bootmem_low(size, size, 0); + } else { + struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); + if (page) + p = page_address(page); + } - if (!page) { + if (!p) { prom_printf("SUN4V: Error, cannot allocate mondo queue.\n"); prom_halt(); } - *pa_ptr = __pa(page); + *pa_ptr = __pa(p); } -static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, int use_bootmem) +static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) { - void *page; + unsigned long size = PAGE_ALIGN(qmask + 1); + unsigned long order = get_order(size); + void *p = NULL; - if (use_bootmem) - page = alloc_bootmem_low_pages(PAGE_SIZE); - else - page = (void *) get_zeroed_page(GFP_ATOMIC); + if (use_bootmem) { + p = __alloc_bootmem_low(size, size, 0); + } else { + struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); + if (page) + p = page_address(page); + } - if (!page) { + if (!p) { prom_printf("SUN4V: Error, cannot allocate kbuf page.\n"); prom_halt(); } - *pa_ptr = __pa(page); + *pa_ptr = __pa(p); } static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem) @@ -779,12 +915,12 @@ void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int struct trap_per_cpu *tb = &trap_block[cpu]; if (alloc) { - alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem); - alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem); - alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem); - alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem); - alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem); - alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem); + alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem); + alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem); + alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem); + alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem); + alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem); + alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem); init_cpu_send_mondo_info(tb, use_bootmem); } diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S index ad46e2024f4..5a8377b5495 100644 --- a/arch/sparc64/kernel/itlb_miss.S +++ b/arch/sparc64/kernel/itlb_miss.S @@ -11,12 +11,12 @@ /* ITLB ** ICACHE line 2: TSB compare and TLB load */ bne,pn %xcc, tsb_miss_itlb ! Miss mov FAULT_CODE_ITLB, %g3 - andcc %g5, _PAGE_EXEC_4U, %g0 ! Executable? + sethi %hi(_PAGE_EXEC_4U), %g4 + andcc %g5, %g4, %g0 ! Executable? be,pn %xcc, tsb_do_fault nop ! Delay slot, fill me stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB retry ! Trap done - nop /* ITLB ** ICACHE line 3: */ nop diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c new file mode 100644 index 00000000000..f0e16045fb1 --- /dev/null +++ b/arch/sparc64/kernel/mdesc.c @@ -0,0 +1,672 @@ +/* mdesc.c: Sun4V machine description handling. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/bootmem.h> +#include <linux/log2.h> + +#include <asm/hypervisor.h> +#include <asm/mdesc.h> +#include <asm/prom.h> +#include <asm/oplib.h> +#include <asm/smp.h> + +/* Unlike the OBP device tree, the machine description is a full-on + * DAG. An arbitrary number of ARCs are possible from one + * node to other nodes and thus we can't use the OBP device_node + * data structure to represent these nodes inside of the kernel. + * + * Actually, it isn't even a DAG, because there are back pointers + * which create cycles in the graph. + * + * mdesc_hdr and mdesc_elem describe the layout of the data structure + * we get from the Hypervisor. + */ +struct mdesc_hdr { + u32 version; /* Transport version */ + u32 node_sz; /* node block size */ + u32 name_sz; /* name block size */ + u32 data_sz; /* data block size */ +}; + +struct mdesc_elem { + u8 tag; +#define MD_LIST_END 0x00 +#define MD_NODE 0x4e +#define MD_NODE_END 0x45 +#define MD_NOOP 0x20 +#define MD_PROP_ARC 0x61 +#define MD_PROP_VAL 0x76 +#define MD_PROP_STR 0x73 +#define MD_PROP_DATA 0x64 + u8 name_len; + u16 resv; + u32 name_offset; + union { + struct { + u32 data_len; + u32 data_offset; + } data; + u64 val; + } d; +}; + +static struct mdesc_hdr *main_mdesc; +static struct mdesc_node *allnodes; + +static struct mdesc_node *allnodes_tail; +static unsigned int unique_id; + +static struct mdesc_node **mdesc_hash; +static unsigned int mdesc_hash_size; + +static inline unsigned int node_hashfn(u64 node) +{ + return ((unsigned int) (node ^ (node >> 8) ^ (node >> 16))) + & (mdesc_hash_size - 1); +} + +static inline void hash_node(struct mdesc_node *mp) +{ + struct mdesc_node **head = &mdesc_hash[node_hashfn(mp->node)]; + + mp->hash_next = *head; + *head = mp; + + if (allnodes_tail) { + allnodes_tail->allnodes_next = mp; + allnodes_tail = mp; + } else { + allnodes = allnodes_tail = mp; + } +} + +static struct mdesc_node *find_node(u64 node) +{ + struct mdesc_node *mp = mdesc_hash[node_hashfn(node)]; + + while (mp) { + if (mp->node == node) + return mp; + + mp = mp->hash_next; + } + return NULL; +} + +struct property *md_find_property(const struct mdesc_node *mp, + const char *name, + int *lenp) +{ + struct property *pp; + + for (pp = mp->properties; pp != 0; pp = pp->next) { + if (strcasecmp(pp->name, name) == 0) { + if (lenp) + *lenp = pp->length; + break; + } + } + return pp; +} +EXPORT_SYMBOL(md_find_property); + +/* + * Find a property with a given name for a given node + * and return the value. + */ +const void *md_get_property(const struct mdesc_node *mp, const char *name, + int *lenp) +{ + struct property *pp = md_find_property(mp, name, lenp); + return pp ? pp->value : NULL; +} +EXPORT_SYMBOL(md_get_property); + +struct mdesc_node *md_find_node_by_name(struct mdesc_node *from, + const char *name) +{ + struct mdesc_node *mp; + + mp = from ? from->allnodes_next : allnodes; + for (; mp != NULL; mp = mp->allnodes_next) { + if (strcmp(mp->name, name) == 0) + break; + } + return mp; +} +EXPORT_SYMBOL(md_find_node_by_name); + +static unsigned int mdesc_early_allocated; + +static void * __init mdesc_early_alloc(unsigned long size) +{ + void *ret; + + ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); + if (ret == NULL) { + prom_printf("MDESC: alloc of %lu bytes failed.\n", size); + prom_halt(); + } + + memset(ret, 0, size); + + mdesc_early_allocated += size; + + return ret; +} + +static unsigned int __init count_arcs(struct mdesc_elem *ep) +{ + unsigned int ret = 0; + + ep++; + while (ep->tag != MD_NODE_END) { + if (ep->tag == MD_PROP_ARC) + ret++; + ep++; + } + return ret; +} + +static void __init mdesc_node_alloc(u64 node, struct mdesc_elem *ep, const char *names) +{ + unsigned int num_arcs = count_arcs(ep); + struct mdesc_node *mp; + + mp = mdesc_early_alloc(sizeof(*mp) + + (num_arcs * sizeof(struct mdesc_arc))); + mp->name = names + ep->name_offset; + mp->node = node; + mp->unique_id = unique_id++; + mp->num_arcs = num_arcs; + + hash_node(mp); +} + +static inline struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) +{ + return (struct mdesc_elem *) (mdesc + 1); +} + +static inline void *name_block(struct mdesc_hdr *mdesc) +{ + return ((void *) node_block(mdesc)) + mdesc->node_sz; +} + +static inline void *data_block(struct mdesc_hdr *mdesc) +{ + return ((void *) name_block(mdesc)) + mdesc->name_sz; +} + +/* In order to avoid recursion (the graph can be very deep) we use a + * two pass algorithm. First we allocate all the nodes and hash them. + * Then we iterate over each node, filling in the arcs and properties. + */ +static void __init build_all_nodes(struct mdesc_hdr *mdesc) +{ + struct mdesc_elem *start, *ep; + struct mdesc_node *mp; + const char *names; + void *data; + u64 last_node; + + start = ep = node_block(mdesc); + last_node = mdesc->node_sz / 16; + + names = name_block(mdesc); + + while (1) { + u64 node = ep - start; + + if (ep->tag == MD_LIST_END) + break; + + if (ep->tag != MD_NODE) { + prom_printf("MDESC: Inconsistent element list.\n"); + prom_halt(); + } + + mdesc_node_alloc(node, ep, names); + + if (ep->d.val >= last_node) { + printk("MDESC: Warning, early break out of node scan.\n"); + printk("MDESC: Next node [%lu] last_node [%lu].\n", + node, last_node); + break; + } + + ep = start + ep->d.val; + } + + data = data_block(mdesc); + for (mp = allnodes; mp; mp = mp->allnodes_next) { + struct mdesc_elem *ep = start + mp->node; + struct property **link = &mp->properties; + unsigned int this_arc = 0; + + ep++; + while (ep->tag != MD_NODE_END) { + switch (ep->tag) { + case MD_PROP_ARC: { + struct mdesc_node *target; + + if (this_arc >= mp->num_arcs) { + prom_printf("MDESC: ARC overrun [%u:%u]\n", + this_arc, mp->num_arcs); + prom_halt(); + } + target = find_node(ep->d.val); + if (!target) { + printk("MDESC: Warning, arc points to " + "missing node, ignoring.\n"); + break; + } + mp->arcs[this_arc].name = + (names + ep->name_offset); + mp->arcs[this_arc].arc = target; + this_arc++; + break; + } + + case MD_PROP_VAL: + case MD_PROP_STR: + case MD_PROP_DATA: { + struct property *p = mdesc_early_alloc(sizeof(*p)); + + p->unique_id = unique_id++; + p->name = (char *) names + ep->name_offset; + if (ep->tag == MD_PROP_VAL) { + p->value = &ep->d.val; + p->length = 8; + } else { + p->value = data + ep->d.data.data_offset; + p->length = ep->d.data.data_len; + } + *link = p; + link = &p->next; + break; + } + + case MD_NOOP: + break; + + default: + printk("MDESC: Warning, ignoring unknown tag type %02x\n", + ep->tag); + } + ep++; + } + } +} + +static unsigned int __init count_nodes(struct mdesc_hdr *mdesc) +{ + struct mdesc_elem *ep = node_block(mdesc); + struct mdesc_elem *end; + unsigned int cnt = 0; + + end = ((void *)ep) + mdesc->node_sz; + while (ep < end) { + if (ep->tag == MD_NODE) + cnt++; + ep++; + } + return cnt; +} + +static void __init report_platform_properties(void) +{ + struct mdesc_node *pn = md_find_node_by_name(NULL, "platform"); + const char *s; + const u64 *v; + + if (!pn) { + prom_printf("No platform node in machine-description.\n"); + prom_halt(); + } + + s = md_get_property(pn, "banner-name", NULL); + printk("PLATFORM: banner-name [%s]\n", s); + s = md_get_property(pn, "name", NULL); + printk("PLATFORM: name [%s]\n", s); + + v = md_get_property(pn, "hostid", NULL); + if (v) + printk("PLATFORM: hostid [%08lx]\n", *v); + v = md_get_property(pn, "serial#", NULL); + if (v) + printk("PLATFORM: serial# [%08lx]\n", *v); + v = md_get_property(pn, "stick-frequency", NULL); + printk("PLATFORM: stick-frequency [%08lx]\n", *v); + v = md_get_property(pn, "mac-address", NULL); + if (v) + printk("PLATFORM: mac-address [%lx]\n", *v); + v = md_get_property(pn, "watchdog-resolution", NULL); + if (v) + printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v); + v = md_get_property(pn, "watchdog-max-timeout", NULL); + if (v) + printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v); + v = md_get_property(pn, "max-cpus", NULL); + if (v) + printk("PLATFORM: max-cpus [%lu]\n", *v); +} + +static int inline find_in_proplist(const char *list, const char *match, int len) +{ + while (len > 0) { + int l; + + if (!strcmp(list, match)) + return 1; + l = strlen(list) + 1; + list += l; + len -= l; + } + return 0; +} + +static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp) +{ + const u64 *level = md_get_property(mp, "level", NULL); + const u64 *size = md_get_property(mp, "size", NULL); + const u64 *line_size = md_get_property(mp, "line-size", NULL); + const char *type; + int type_len; + + type = md_get_property(mp, "type", &type_len); + + switch (*level) { + case 1: + if (find_in_proplist(type, "instn", type_len)) { + c->icache_size = *size; + c->icache_line_size = *line_size; + } else if (find_in_proplist(type, "data", type_len)) { + c->dcache_size = *size; + c->dcache_line_size = *line_size; + } + break; + + case 2: + c->ecache_size = *size; + c->ecache_line_size = *line_size; + break; + + default: + break; + } + + if (*level == 1) { + unsigned int i; + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + + if (strcmp(mp->arcs[i].name, "fwd")) + continue; + + if (!strcmp(t->name, "cache")) + fill_in_one_cache(c, t); + } + } +} + +static void __init mark_core_ids(struct mdesc_node *mp, int core_id) +{ + unsigned int i; + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + const u64 *id; + + if (strcmp(mp->arcs[i].name, "back")) + continue; + + if (!strcmp(t->name, "cpu")) { + id = md_get_property(t, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).core_id = core_id; + } else { + unsigned int j; + + for (j = 0; j < t->num_arcs; j++) { + struct mdesc_node *n = t->arcs[j].arc; + + if (strcmp(t->arcs[j].name, "back")) + continue; + + if (strcmp(n->name, "cpu")) + continue; + + id = md_get_property(n, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).core_id = core_id; + } + } + } +} + +static void __init set_core_ids(void) +{ + struct mdesc_node *mp; + int idx; + + idx = 1; + md_for_each_node_by_name(mp, "cache") { + const u64 *level = md_get_property(mp, "level", NULL); + const char *type; + int len; + + if (*level != 1) + continue; + + type = md_get_property(mp, "type", &len); + if (!find_in_proplist(type, "instn", len)) + continue; + + mark_core_ids(mp, idx); + + idx++; + } +} + +static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id) +{ + int i; + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + const u64 *id; + + if (strcmp(mp->arcs[i].name, "back")) + continue; + + if (strcmp(t->name, "cpu")) + continue; + + id = md_get_property(t, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).proc_id = proc_id; + } +} + +static void __init __set_proc_ids(const char *exec_unit_name) +{ + struct mdesc_node *mp; + int idx; + + idx = 0; + md_for_each_node_by_name(mp, exec_unit_name) { + const char *type; + int len; + + type = md_get_property(mp, "type", &len); + if (!find_in_proplist(type, "int", len) && + !find_in_proplist(type, "integer", len)) + continue; + + mark_proc_ids(mp, idx); + + idx++; + } +} + +static void __init set_proc_ids(void) +{ + __set_proc_ids("exec_unit"); + __set_proc_ids("exec-unit"); +} + +static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) +{ + u64 val; + + if (!p) + goto use_default; + val = *p; + + if (!val || val >= 64) + goto use_default; + + *mask = ((1U << val) * 64U) - 1U; + return; + +use_default: + *mask = ((1U << def) * 64U) - 1U; +} + +static void __init get_mondo_data(struct mdesc_node *mp, struct trap_per_cpu *tb) +{ + const u64 *val; + + val = md_get_property(mp, "q-cpu-mondo-#bits", NULL); + get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7); + + val = md_get_property(mp, "q-dev-mondo-#bits", NULL); + get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7); + + val = md_get_property(mp, "q-resumable-#bits", NULL); + get_one_mondo_bits(val, &tb->resum_qmask, 6); + + val = md_get_property(mp, "q-nonresumable-#bits", NULL); + get_one_mondo_bits(val, &tb->nonresum_qmask, 2); +} + +static void __init mdesc_fill_in_cpu_data(void) +{ + struct mdesc_node *mp; + + ncpus_probed = 0; + md_for_each_node_by_name(mp, "cpu") { + const u64 *id = md_get_property(mp, "id", NULL); + const u64 *cfreq = md_get_property(mp, "clock-frequency", NULL); + struct trap_per_cpu *tb; + cpuinfo_sparc *c; + unsigned int i; + int cpuid; + + ncpus_probed++; + + cpuid = *id; + +#ifdef CONFIG_SMP + if (cpuid >= NR_CPUS) + continue; +#else + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + continue; + cpuid = 0; +#endif + + c = &cpu_data(cpuid); + c->clock_tick = *cfreq; + + tb = &trap_block[cpuid]; + get_mondo_data(mp, tb); + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + unsigned int j; + + if (strcmp(mp->arcs[i].name, "fwd")) + continue; + + if (!strcmp(t->name, "cache")) { + fill_in_one_cache(c, t); + continue; + } + + for (j = 0; j < t->num_arcs; j++) { + struct mdesc_node *n; + + n = t->arcs[j].arc; + if (strcmp(t->arcs[j].name, "fwd")) + continue; + + if (!strcmp(n->name, "cache")) + fill_in_one_cache(c, n); + } + } + +#ifdef CONFIG_SMP + cpu_set(cpuid, cpu_present_map); + cpu_set(cpuid, phys_cpu_present_map); +#endif + + c->core_id = 0; + c->proc_id = -1; + } + +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif + + set_core_ids(); + set_proc_ids(); + + smp_fill_in_sib_core_maps(); +} + +void __init sun4v_mdesc_init(void) +{ + unsigned long len, real_len, status; + + (void) sun4v_mach_desc(0UL, 0UL, &len); + + printk("MDESC: Size is %lu bytes.\n", len); + + main_mdesc = mdesc_early_alloc(len); + + status = sun4v_mach_desc(__pa(main_mdesc), len, &real_len); + if (status != HV_EOK || real_len > len) { + prom_printf("sun4v_mach_desc fails, err(%lu), " + "len(%lu), real_len(%lu)\n", + status, len, real_len); + prom_halt(); + } + + len = count_nodes(main_mdesc); + printk("MDESC: %lu nodes.\n", len); + + len = roundup_pow_of_two(len); + + mdesc_hash = mdesc_early_alloc(len * sizeof(struct mdesc_node *)); + mdesc_hash_size = len; + + printk("MDESC: Hash size %lu entries.\n", len); + + build_all_nodes(main_mdesc); + + printk("MDESC: Built graph with %u bytes of memory.\n", + mdesc_early_allocated); + + report_platform_properties(); + mdesc_fill_in_cpu_data(); +} diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 16cc46a7187..6676b93219d 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -343,6 +343,15 @@ static int of_bus_simba_match(struct device_node *np) if (model && !strcmp(model, "SUNW,simba")) return 1; + + /* Treat PCI busses lacking ranges property just like + * simba. + */ + if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { + if (!of_find_property(np, "ranges", NULL)) + return 1; + } + return 0; } @@ -549,8 +558,6 @@ static int __init build_one_resource(struct device_node *parent, static int __init use_1to1_mapping(struct device_node *pp) { - const char *model; - /* If this is on the PMU bus, don't try to translate it even * if a ranges property exists. */ @@ -567,9 +574,11 @@ static int __init use_1to1_mapping(struct device_node *pp) if (!strcmp(pp->name, "dma")) return 0; - /* Similarly for Simba PCI bridges. */ - model = of_get_property(pp, "model", NULL); - if (model && !strcmp(model, "SUNW,simba")) + /* Similarly for all PCI bridges, if we get this far + * it lacks a ranges property, and this will include + * cases like Simba. + */ + if (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex")) return 0; return 1; diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index d4c077dc5e8..81f4a5ea05f 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -306,6 +306,20 @@ static void __init pci_controller_probe(void) pci_controller_scan(pci_controller_init); } +static int ofpci_verbose; + +static int __init ofpci_debug(char *str) +{ + int val = 0; + + get_option(&str, &val); + if (val) + ofpci_verbose = 1; + return 1; +} + +__setup("ofpci_debug=", ofpci_debug); + static unsigned long pci_parse_of_flags(u32 addr0) { unsigned long flags = 0; @@ -337,7 +351,9 @@ static void pci_parse_of_addrs(struct of_device *op, addrs = of_get_property(node, "assigned-addresses", &proplen); if (!addrs) return; - printk(" parse addresses (%d bytes) @ %p\n", proplen, addrs); + if (ofpci_verbose) + printk(" parse addresses (%d bytes) @ %p\n", + proplen, addrs); op_res = &op->resource[0]; for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) { struct resource *res; @@ -348,8 +364,9 @@ static void pci_parse_of_addrs(struct of_device *op, if (!flags) continue; i = addrs[0] & 0xff; - printk(" start: %lx, end: %lx, i: %x\n", - op_res->start, op_res->end, i); + if (ofpci_verbose) + printk(" start: %lx, end: %lx, i: %x\n", + op_res->start, op_res->end, i); if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) { res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2]; @@ -393,8 +410,9 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, if (type == NULL) type = ""; - printk(" create device, devfn: %x, type: %s hostcontroller(%d)\n", - devfn, type, host_controller); + if (ofpci_verbose) + printk(" create device, devfn: %x, type: %s\n", + devfn, type); dev->bus = bus; dev->sysdata = node; @@ -434,8 +452,9 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); } - printk(" class: 0x%x device name: %s\n", - dev->class, pci_name(dev)); + if (ofpci_verbose) + printk(" class: 0x%x device name: %s\n", + dev->class, pci_name(dev)); /* I have seen IDE devices which will not respond to * the bmdma simplex check reads if bus mastering is @@ -469,7 +488,8 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, } pci_parse_of_addrs(sd->op, node, dev); - printk(" adding to system ...\n"); + if (ofpci_verbose) + printk(" adding to system ...\n"); pci_device_add(dev, bus); @@ -502,6 +522,89 @@ static void pci_resource_adjust(struct resource *res, res->end += root->start; } +/* For PCI bus devices which lack a 'ranges' property we interrogate + * the config space values to set the resources, just like the generic + * Linux PCI probing code does. + */ +static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev, + struct pci_bus *bus, + struct pci_pbm_info *pbm) +{ + struct resource *res; + u8 io_base_lo, io_limit_lo; + u16 mem_base_lo, mem_limit_lo; + unsigned long base, limit; + + pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo); + pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo); + base = (io_base_lo & PCI_IO_RANGE_MASK) << 8; + limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8; + + if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + u16 io_base_hi, io_limit_hi; + + pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi); + pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi); + base |= (io_base_hi << 16); + limit |= (io_limit_hi << 16); + } + + res = bus->resource[0]; + if (base <= limit) { + res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; + if (!res->start) + res->start = base; + if (!res->end) + res->end = limit + 0xfff; + pci_resource_adjust(res, &pbm->io_space); + } + + pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); + base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; + + res = bus->resource[1]; + if (base <= limit) { + res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | + IORESOURCE_MEM); + res->start = base; + res->end = limit + 0xfffff; + pci_resource_adjust(res, &pbm->mem_space); + } + + pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); + pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); + base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; + limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; + + if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + u32 mem_base_hi, mem_limit_hi; + + pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi); + pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi); + + /* + * Some bridges set the base > limit by default, and some + * (broken) BIOSes do not initialize them. If we find + * this, just assume they are not being used. + */ + if (mem_base_hi <= mem_limit_hi) { + base |= ((long) mem_base_hi) << 32; + limit |= ((long) mem_limit_hi) << 32; + } + } + + res = bus->resource[2]; + if (base <= limit) { + res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | + IORESOURCE_MEM | IORESOURCE_PREFETCH); + res->start = base; + res->end = limit + 0xfffff; + pci_resource_adjust(res, &pbm->mem_space); + } +} + /* Cook up fake bus resources for SUNW,simba PCI bridges which lack * a proper 'ranges' property. */ @@ -547,7 +650,8 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, unsigned int flags; u64 size; - printk("of_scan_pci_bridge(%s)\n", node->full_name); + if (ofpci_verbose) + printk("of_scan_pci_bridge(%s)\n", node->full_name); /* parse bus-range property */ busrange = of_get_property(node, "bus-range", &len); @@ -560,13 +664,8 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, simba = 0; if (ranges == NULL) { const char *model = of_get_property(node, "model", NULL); - if (model && !strcmp(model, "SUNW,simba")) { + if (model && !strcmp(model, "SUNW,simba")) simba = 1; - } else { - printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n", - node->full_name); - return; - } } bus = pci_add_new_bus(dev->bus, dev, busrange[0]); @@ -590,7 +689,10 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, } if (simba) { apb_fake_ranges(dev, bus, pbm); - goto simba_cont; + goto after_ranges; + } else if (ranges == NULL) { + pci_cfg_fake_ranges(dev, bus, pbm); + goto after_ranges; } i = 1; for (; len >= 32; len -= 32, ranges += 8) { @@ -629,10 +731,11 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, */ pci_resource_adjust(res, root); } -simba_cont: +after_ranges: sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); - printk(" bus name: %s\n", bus->name); + if (ofpci_verbose) + printk(" bus name: %s\n", bus->name); pci_of_scan_bus(pbm, node, bus); } @@ -646,12 +749,14 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, int reglen, devfn; struct pci_dev *dev; - printk("PCI: scan_bus[%s] bus no %d\n", - node->full_name, bus->number); + if (ofpci_verbose) + printk("PCI: scan_bus[%s] bus no %d\n", + node->full_name, bus->number); child = NULL; while ((child = of_get_next_child(node, child)) != NULL) { - printk(" * %s\n", child->full_name); + if (ofpci_verbose) + printk(" * %s\n", child->full_name); reg = of_get_property(child, "reg", ®len); if (reg == NULL || reglen < 20) continue; @@ -661,7 +766,9 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, dev = of_create_pci_dev(pbm, child, bus, devfn, 0); if (!dev) continue; - printk("PCI: dev header type: %x\n", dev->hdr_type); + if (ofpci_verbose) + printk("PCI: dev header type: %x\n", + dev->hdr_type); if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index f974fefc3eb..4249214608a 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -291,8 +291,9 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) for (i = 0; i < num_pbm_ranges; i++) { const struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; - unsigned long a; + unsigned long a, size; u32 parent_phys_hi, parent_phys_lo; + u32 size_hi, size_lo; int type; parent_phys_hi = pr->parent_phys_hi; @@ -300,9 +301,14 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) if (tlb_type == hypervisor) parent_phys_hi &= 0x0fffffff; + size_hi = pr->size_hi; + size_lo = pr->size_lo; + type = (pr->child_phys_hi >> 24) & 0x3; a = (((unsigned long)parent_phys_hi << 32UL) | ((unsigned long)parent_phys_lo << 0UL)); + size = (((unsigned long)size_hi << 32UL) | + ((unsigned long)size_lo << 0UL)); switch (type) { case 0: @@ -313,7 +319,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) case 1: /* 16-bit IO space, 16MB */ pbm->io_space.start = a; - pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); + pbm->io_space.end = a + size - 1UL; pbm->io_space.flags = IORESOURCE_IO; saw_io = 1; break; @@ -321,7 +327,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm) case 2: /* 32-bit MEM space, 2GB */ pbm->mem_space.start = a; - pbm->mem_space.end = a + (0x80000000UL - 1UL); + pbm->mem_space.end = a + size - 1UL; pbm->mem_space.flags = IORESOURCE_MEM; saw_mem = 1; break; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index e2377796de8..22e1be5c748 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -636,13 +636,18 @@ static void apb_init(struct pci_bus *sabre_bus) static void sabre_scan_bus(struct pci_pbm_info *pbm) { static int once; - struct pci_bus *pbus; /* The APB bridge speaks to the Sabre host PCI bridge * at 66Mhz, but the front side of APB runs at 33Mhz * for both segments. + * + * Hummingbird systems do not use APB, so they run + * at 66MHZ. */ - pbm->is_66mhz_capable = 0; + if (hummingbird_p) + pbm->is_66mhz_capable = 1; + else + pbm->is_66mhz_capable = 0; /* This driver has not been verified to handle * multiple SABREs yet, so trap this. @@ -656,13 +661,13 @@ static void sabre_scan_bus(struct pci_pbm_info *pbm) } once++; - pbus = pci_scan_one_pbm(pbm); - if (!pbus) + pbm->pci_bus = pci_scan_one_pbm(pbm); + if (!pbm->pci_bus) return; - sabre_root_bus = pbus; + sabre_root_bus = pbm->pci_bus; - apb_init(pbus); + apb_init(pbm->pci_bus); sabre_register_error_handlers(pbm); } @@ -762,9 +767,10 @@ void sabre_init(struct device_node *dp, char *model_name) /* Of course, Sun has to encode things a thousand * different ways, inconsistently. */ - cpu_find_by_instance(0, &dp, NULL); - if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe")) - hummingbird_p = 1; + for_each_node_by_type(dp, "cpu") { + if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe")) + hummingbird_p = 1; + } } } diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 044e8ec4c0f..6b3fe2c1d65 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -12,6 +12,7 @@ #include <linux/percpu.h> #include <linux/irq.h> #include <linux/msi.h> +#include <linux/log2.h> #include <asm/iommu.h> #include <asm/irq.h> @@ -26,6 +27,9 @@ #include "pci_sun4v.h" +static unsigned long vpci_major = 1; +static unsigned long vpci_minor = 1; + #define PGLIST_NENTS (PAGE_SIZE / sizeof(u64)) struct iommu_batch { @@ -638,9 +642,8 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) { struct iommu *iommu = pbm->iommu; struct property *prop; - unsigned long num_tsb_entries, sz; + unsigned long num_tsb_entries, sz, tsbsize; u32 vdma[2], dma_mask, dma_offset; - int tsbsize; prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); if (prop) { @@ -654,31 +657,15 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) vdma[1] = 0x80000000; } - dma_mask = vdma[0]; - switch (vdma[1]) { - case 0x20000000: - dma_mask |= 0x1fffffff; - tsbsize = 64; - break; - - case 0x40000000: - dma_mask |= 0x3fffffff; - tsbsize = 128; - break; - - case 0x80000000: - dma_mask |= 0x7fffffff; - tsbsize = 256; - break; - - default: - prom_printf("PCI-SUN4V: strange virtual-dma size.\n"); - prom_halt(); + if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) { + prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n", + vdma[0], vdma[1]); + prom_halt(); }; - tsbsize *= (8 * 1024); - - num_tsb_entries = tsbsize / sizeof(iopte_t); + dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL); + num_tsb_entries = vdma[1] / IO_PAGE_SIZE; + tsbsize = num_tsb_entries * sizeof(iopte_t); dma_offset = vdma[0]; @@ -689,7 +676,7 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) iommu->dma_addr_mask = dma_mask; /* Allocate and initialize the free area map. */ - sz = num_tsb_entries / 8; + sz = (num_tsb_entries + 7) / 8; sz = (sz + 7UL) & ~7UL; iommu->arena.map = kzalloc(sz, GFP_KERNEL); if (!iommu->arena.map) { @@ -1178,6 +1165,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node void sun4v_pci_init(struct device_node *dp, char *model_name) { + static int hvapi_negotiated = 0; struct pci_controller_info *p; struct pci_pbm_info *pbm; struct iommu *iommu; @@ -1186,6 +1174,20 @@ void sun4v_pci_init(struct device_node *dp, char *model_name) u32 devhandle; int i; + if (!hvapi_negotiated++) { + int err = sun4v_hvapi_register(HV_GRP_PCI, + vpci_major, + &vpci_minor); + + if (err) { + prom_printf("SUN4V_PCI: Could not register hvapi, " + "err=%d\n", err); + prom_halt(); + } + printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n", + vpci_major, vpci_minor); + } + prop = of_find_property(dp, "reg", NULL); regs = prop->value; diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index 699b24b890d..5d6adea3967 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -19,6 +19,7 @@ #include <asm/prom.h> #include <asm/of_device.h> #include <asm/io.h> +#include <asm/sstate.h> #include <linux/unistd.h> @@ -53,6 +54,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off; void machine_power_off(void) { + sstate_poweroff(); if (!serial_console || scons_pwroff) { #ifdef CONFIG_PCI if (power_reg) { diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 952762bfb4c..f5f97e2c669 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -45,6 +45,7 @@ #include <asm/mmu_context.h> #include <asm/unistd.h> #include <asm/hypervisor.h> +#include <asm/sstate.h> /* #define VERBOSE_SHOWREGS */ @@ -106,6 +107,7 @@ extern void (*prom_keyboard)(void); void machine_halt(void) { + sstate_halt(); if (!serial_console && prom_palette) prom_palette (1); if (prom_keyboard) @@ -116,6 +118,7 @@ void machine_halt(void) void machine_alt_power_off(void) { + sstate_poweroff(); if (!serial_console && prom_palette) prom_palette(1); if (prom_keyboard) @@ -128,6 +131,7 @@ void machine_restart(char * cmd) { char *p; + sstate_reboot(); p = strchr (reboot_command, '\n'); if (p) *p = 0; if (!serial_console && prom_palette) diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 02830e4671f..61036b34666 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -28,6 +28,7 @@ #include <asm/irq.h> #include <asm/asi.h> #include <asm/upa.h> +#include <asm/smp.h> static struct device_node *allnodes; @@ -932,29 +933,29 @@ static void __init fire_irq_trans_init(struct device_node *dp) * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. */ -#define SYSIO_IMAP_SLOT0 0x2c04UL -#define SYSIO_IMAP_SLOT1 0x2c0cUL -#define SYSIO_IMAP_SLOT2 0x2c14UL -#define SYSIO_IMAP_SLOT3 0x2c1cUL -#define SYSIO_IMAP_SCSI 0x3004UL -#define SYSIO_IMAP_ETH 0x300cUL -#define SYSIO_IMAP_BPP 0x3014UL -#define SYSIO_IMAP_AUDIO 0x301cUL -#define SYSIO_IMAP_PFAIL 0x3024UL -#define SYSIO_IMAP_KMS 0x302cUL -#define SYSIO_IMAP_FLPY 0x3034UL -#define SYSIO_IMAP_SHW 0x303cUL -#define SYSIO_IMAP_KBD 0x3044UL -#define SYSIO_IMAP_MS 0x304cUL -#define SYSIO_IMAP_SER 0x3054UL -#define SYSIO_IMAP_TIM0 0x3064UL -#define SYSIO_IMAP_TIM1 0x306cUL -#define SYSIO_IMAP_UE 0x3074UL -#define SYSIO_IMAP_CE 0x307cUL -#define SYSIO_IMAP_SBERR 0x3084UL -#define SYSIO_IMAP_PMGMT 0x308cUL -#define SYSIO_IMAP_GFX 0x3094UL -#define SYSIO_IMAP_EUPA 0x309cUL +#define SYSIO_IMAP_SLOT0 0x2c00UL +#define SYSIO_IMAP_SLOT1 0x2c08UL +#define SYSIO_IMAP_SLOT2 0x2c10UL +#define SYSIO_IMAP_SLOT3 0x2c18UL +#define SYSIO_IMAP_SCSI 0x3000UL +#define SYSIO_IMAP_ETH 0x3008UL +#define SYSIO_IMAP_BPP 0x3010UL +#define SYSIO_IMAP_AUDIO 0x3018UL +#define SYSIO_IMAP_PFAIL 0x3020UL +#define SYSIO_IMAP_KMS 0x3028UL +#define SYSIO_IMAP_FLPY 0x3030UL +#define SYSIO_IMAP_SHW 0x3038UL +#define SYSIO_IMAP_KBD 0x3040UL +#define SYSIO_IMAP_MS 0x3048UL +#define SYSIO_IMAP_SER 0x3050UL +#define SYSIO_IMAP_TIM0 0x3060UL +#define SYSIO_IMAP_TIM1 0x3068UL +#define SYSIO_IMAP_UE 0x3070UL +#define SYSIO_IMAP_CE 0x3078UL +#define SYSIO_IMAP_SBERR 0x3080UL +#define SYSIO_IMAP_PMGMT 0x3088UL +#define SYSIO_IMAP_GFX 0x3090UL +#define SYSIO_IMAP_EUPA 0x3098UL #define bogon ((unsigned long) -1) static unsigned long sysio_irq_offsets[] = { @@ -1005,10 +1006,10 @@ static unsigned long sysio_irq_offsets[] = { * Interrupt Clear register pointer, SYSIO specific version. */ #define SYSIO_ICLR_UNUSED0 0x3400UL -#define SYSIO_ICLR_SLOT0 0x340cUL -#define SYSIO_ICLR_SLOT1 0x344cUL -#define SYSIO_ICLR_SLOT2 0x348cUL -#define SYSIO_ICLR_SLOT3 0x34ccUL +#define SYSIO_ICLR_SLOT0 0x3408UL +#define SYSIO_ICLR_SLOT1 0x3448UL +#define SYSIO_ICLR_SLOT2 0x3488UL +#define SYSIO_ICLR_SLOT3 0x34c8UL static unsigned long sysio_imap_to_iclr(unsigned long imap) { unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; @@ -1665,6 +1666,155 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl return ret; } +static const char *get_mid_prop(void) +{ + return (tlb_type == spitfire ? "upa-portid" : "portid"); +} + +struct device_node *of_find_node_by_cpuid(int cpuid) +{ + struct device_node *dp; + const char *mid_prop = get_mid_prop(); + + for_each_node_by_type(dp, "cpu") { + int id = of_getintprop_default(dp, mid_prop, -1); + const char *this_mid_prop = mid_prop; + + if (id < 0) { + this_mid_prop = "cpuid"; + id = of_getintprop_default(dp, this_mid_prop, -1); + } + + if (id < 0) { + prom_printf("OF: Serious problem, cpu lacks " + "%s property", this_mid_prop); + prom_halt(); + } + if (cpuid == id) + return dp; + } + return NULL; +} + +static void __init of_fill_in_cpu_data(void) +{ + struct device_node *dp; + const char *mid_prop = get_mid_prop(); + + ncpus_probed = 0; + for_each_node_by_type(dp, "cpu") { + int cpuid = of_getintprop_default(dp, mid_prop, -1); + const char *this_mid_prop = mid_prop; + struct device_node *portid_parent; + int portid = -1; + + portid_parent = NULL; + if (cpuid < 0) { + this_mid_prop = "cpuid"; + cpuid = of_getintprop_default(dp, this_mid_prop, -1); + if (cpuid >= 0) { + int limit = 2; + + portid_parent = dp; + while (limit--) { + portid_parent = portid_parent->parent; + if (!portid_parent) + break; + portid = of_getintprop_default(portid_parent, + "portid", -1); + if (portid >= 0) + break; + } + } + } + + if (cpuid < 0) { + prom_printf("OF: Serious problem, cpu lacks " + "%s property", this_mid_prop); + prom_halt(); + } + + ncpus_probed++; + +#ifdef CONFIG_SMP + if (cpuid >= NR_CPUS) + continue; +#else + /* On uniprocessor we only want the values for the + * real physical cpu the kernel booted onto, however + * cpu_data() only has one entry at index 0. + */ + if (cpuid != real_hard_smp_processor_id()) + continue; + cpuid = 0; +#endif + + cpu_data(cpuid).clock_tick = + of_getintprop_default(dp, "clock-frequency", 0); + + if (portid_parent) { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "l1-dcache-size", + 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "l1-dcache-line-size", + 32); + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "l1-icache-size", + 8 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "l1-icache-line-size", + 32); + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "l2-cache-size", 0); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "l2-cache-line-size", 0); + if (!cpu_data(cpuid).ecache_size || + !cpu_data(cpuid).ecache_line_size) { + cpu_data(cpuid).ecache_size = + of_getintprop_default(portid_parent, + "l2-cache-size", + (4 * 1024 * 1024)); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(portid_parent, + "l2-cache-line-size", 64); + } + + cpu_data(cpuid).core_id = portid + 1; + cpu_data(cpuid).proc_id = portid; +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif + } else { + cpu_data(cpuid).dcache_size = + of_getintprop_default(dp, "dcache-size", 16 * 1024); + cpu_data(cpuid).dcache_line_size = + of_getintprop_default(dp, "dcache-line-size", 32); + + cpu_data(cpuid).icache_size = + of_getintprop_default(dp, "icache-size", 16 * 1024); + cpu_data(cpuid).icache_line_size = + of_getintprop_default(dp, "icache-line-size", 32); + + cpu_data(cpuid).ecache_size = + of_getintprop_default(dp, "ecache-size", + (4 * 1024 * 1024)); + cpu_data(cpuid).ecache_line_size = + of_getintprop_default(dp, "ecache-line-size", 64); + + cpu_data(cpuid).core_id = 0; + cpu_data(cpuid).proc_id = -1; + } + +#ifdef CONFIG_SMP + cpu_set(cpuid, cpu_present_map); + cpu_set(cpuid, phys_cpu_present_map); +#endif + } + + smp_fill_in_sib_core_maps(); +} + void __init prom_build_devicetree(void) { struct device_node **nextp; @@ -1679,4 +1829,7 @@ void __init prom_build_devicetree(void) &nextp); printk("PROM: Built device tree with %u bytes of memory.\n", prom_early_allocated); + + if (tlb_type != hypervisor) + of_fill_in_cpu_data(); } diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 91f6e2a74ad..a1fd9bcc0b8 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -629,29 +629,29 @@ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) * This should conform to both Sunfire/Wildfire server and Fusion * desktop designs. */ -#define SYSIO_IMAP_SLOT0 0x2c04UL -#define SYSIO_IMAP_SLOT1 0x2c0cUL -#define SYSIO_IMAP_SLOT2 0x2c14UL -#define SYSIO_IMAP_SLOT3 0x2c1cUL -#define SYSIO_IMAP_SCSI 0x3004UL -#define SYSIO_IMAP_ETH 0x300cUL -#define SYSIO_IMAP_BPP 0x3014UL -#define SYSIO_IMAP_AUDIO 0x301cUL -#define SYSIO_IMAP_PFAIL 0x3024UL -#define SYSIO_IMAP_KMS 0x302cUL -#define SYSIO_IMAP_FLPY 0x3034UL -#define SYSIO_IMAP_SHW 0x303cUL -#define SYSIO_IMAP_KBD 0x3044UL -#define SYSIO_IMAP_MS 0x304cUL -#define SYSIO_IMAP_SER 0x3054UL -#define SYSIO_IMAP_TIM0 0x3064UL -#define SYSIO_IMAP_TIM1 0x306cUL -#define SYSIO_IMAP_UE 0x3074UL -#define SYSIO_IMAP_CE 0x307cUL -#define SYSIO_IMAP_SBERR 0x3084UL -#define SYSIO_IMAP_PMGMT 0x308cUL -#define SYSIO_IMAP_GFX 0x3094UL -#define SYSIO_IMAP_EUPA 0x309cUL +#define SYSIO_IMAP_SLOT0 0x2c00UL +#define SYSIO_IMAP_SLOT1 0x2c08UL +#define SYSIO_IMAP_SLOT2 0x2c10UL +#define SYSIO_IMAP_SLOT3 0x2c18UL +#define SYSIO_IMAP_SCSI 0x3000UL +#define SYSIO_IMAP_ETH 0x3008UL +#define SYSIO_IMAP_BPP 0x3010UL +#define SYSIO_IMAP_AUDIO 0x3018UL +#define SYSIO_IMAP_PFAIL 0x3020UL +#define SYSIO_IMAP_KMS 0x3028UL +#define SYSIO_IMAP_FLPY 0x3030UL +#define SYSIO_IMAP_SHW 0x3038UL +#define SYSIO_IMAP_KBD 0x3040UL +#define SYSIO_IMAP_MS 0x3048UL +#define SYSIO_IMAP_SER 0x3050UL +#define SYSIO_IMAP_TIM0 0x3060UL +#define SYSIO_IMAP_TIM1 0x3068UL +#define SYSIO_IMAP_UE 0x3070UL +#define SYSIO_IMAP_CE 0x3078UL +#define SYSIO_IMAP_SBERR 0x3080UL +#define SYSIO_IMAP_PMGMT 0x3088UL +#define SYSIO_IMAP_GFX 0x3090UL +#define SYSIO_IMAP_EUPA 0x3098UL #define bogon ((unsigned long) -1) static unsigned long sysio_irq_offsets[] = { @@ -700,10 +700,10 @@ static unsigned long sysio_irq_offsets[] = { * Interrupt Clear register pointer, SYSIO specific version. */ #define SYSIO_ICLR_UNUSED0 0x3400UL -#define SYSIO_ICLR_SLOT0 0x340cUL -#define SYSIO_ICLR_SLOT1 0x344cUL -#define SYSIO_ICLR_SLOT2 0x348cUL -#define SYSIO_ICLR_SLOT3 0x34ccUL +#define SYSIO_ICLR_SLOT0 0x3408UL +#define SYSIO_ICLR_SLOT1 0x3448UL +#define SYSIO_ICLR_SLOT2 0x3488UL +#define SYSIO_ICLR_SLOT3 0x34c8UL static unsigned long sysio_imap_to_iclr(unsigned long imap) { unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0; diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index dea9c3c9ec5..7490cc670a5 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -46,11 +46,17 @@ #include <asm/sections.h> #include <asm/setup.h> #include <asm/mmu.h> +#include <asm/ns87303.h> #ifdef CONFIG_IP_PNP #include <net/ipconfig.h> #endif +/* Used to synchronize accesses to NatSemi SUPER I/O chip configure + * operations in asm/ns87303.h + */ +DEFINE_SPINLOCK(ns87303_lock); + struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ 0, /* unused */ @@ -370,8 +376,6 @@ void __init setup_arch(char **cmdline_p) init_cur_cpu_trap(current_thread_info()); paging_init(); - - smp_setup_cpu_possible_map(); } static int __init set_preferred_console(void) @@ -424,7 +428,7 @@ extern void mmu_info(struct seq_file *); unsigned int dcache_parity_tl1_occurred; unsigned int icache_parity_tl1_occurred; -static int ncpus_probed; +int ncpus_probed; static int show_cpuinfo(struct seq_file *m, void *__unused) { @@ -509,30 +513,3 @@ void sun_do_break(void) int serial_console = -1; int stop_a_enabled = 1; - -static int __init topology_init(void) -{ - int i, err; - - err = -ENOMEM; - - /* Count the number of physically present processors in - * the machine, even on uniprocessor, so that /proc/cpuinfo - * output is consistent with 2.4.x - */ - ncpus_probed = 0; - while (!cpu_find_by_instance(ncpus_probed, NULL, NULL)) - ncpus_probed++; - - for_each_possible_cpu(i) { - struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p) { - register_cpu(p, i); - err = 0; - } - } - - return err; -} - -subsys_initcall(topology_init); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 24fdf1d0adc..4dcd7d0b60f 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -40,9 +40,12 @@ #include <asm/tlb.h> #include <asm/sections.h> #include <asm/prom.h> +#include <asm/mdesc.h> extern void calibrate_delay(void); +int sparc64_multi_core __read_mostly; + /* Please don't make this stuff initdata!!! --DaveM */ unsigned char boot_cpu_id; @@ -50,6 +53,8 @@ cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; +cpumask_t cpu_core_map[NR_CPUS] __read_mostly = + { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; static cpumask_t smp_commenced_mask; static cpumask_t cpu_callout_map; @@ -75,53 +80,6 @@ void smp_bogo(struct seq_file *m) i, cpu_data(i).clock_tick); } -void __init smp_store_cpu_info(int id) -{ - struct device_node *dp; - int def; - - cpu_data(id).udelay_val = loops_per_jiffy; - - cpu_find_by_mid(id, &dp); - cpu_data(id).clock_tick = - of_getintprop_default(dp, "clock-frequency", 0); - - def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024)); - cpu_data(id).dcache_size = - of_getintprop_default(dp, "dcache-size", def); - - def = 32; - cpu_data(id).dcache_line_size = - of_getintprop_default(dp, "dcache-line-size", def); - - def = 16 * 1024; - cpu_data(id).icache_size = - of_getintprop_default(dp, "icache-size", def); - - def = 32; - cpu_data(id).icache_line_size = - of_getintprop_default(dp, "icache-line-size", def); - - def = ((tlb_type == hypervisor) ? - (3 * 1024 * 1024) : - (4 * 1024 * 1024)); - cpu_data(id).ecache_size = - of_getintprop_default(dp, "ecache-size", def); - - def = 64; - cpu_data(id).ecache_line_size = - of_getintprop_default(dp, "ecache-line-size", def); - - printk("CPU[%d]: Caches " - "D[sz(%d):line_sz(%d)] " - "I[sz(%d):line_sz(%d)] " - "E[sz(%d):line_sz(%d)]\n", - id, - cpu_data(id).dcache_size, cpu_data(id).dcache_line_size, - cpu_data(id).icache_size, cpu_data(id).icache_line_size, - cpu_data(id).ecache_size, cpu_data(id).ecache_line_size); -} - extern void setup_sparc64_timer(void); static volatile unsigned long callin_flag = 0; @@ -145,7 +103,7 @@ void __init smp_callin(void) local_irq_enable(); calibrate_delay(); - smp_store_cpu_info(cpuid); + cpu_data(cpuid).udelay_val = loops_per_jiffy; callin_flag = 1; __asm__ __volatile__("membar #Sync\n\t" "flush %%g6" : : : "memory"); @@ -340,9 +298,8 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) prom_startcpu_cpuid(cpu, entry, cookie); } else { - struct device_node *dp; + struct device_node *dp = of_find_node_by_cpuid(cpu); - cpu_find_by_mid(cpu, &dp); prom_startcpu(dp->node, entry, cookie); } @@ -447,7 +404,7 @@ static __inline__ void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, c static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) { u64 pstate, ver; - int nack_busy_id, is_jbus; + int nack_busy_id, is_jbus, need_more; if (cpus_empty(mask)) return; @@ -463,6 +420,7 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); retry: + need_more = 0; __asm__ __volatile__("wrpr %0, %1, %%pstate\n\t" : : "r" (pstate), "i" (PSTATE_IE)); @@ -491,6 +449,10 @@ retry: : /* no outputs */ : "r" (target), "i" (ASI_INTR_W)); nack_busy_id++; + if (nack_busy_id == 32) { + need_more = 1; + break; + } } } @@ -507,6 +469,16 @@ retry: if (dispatch_stat == 0UL) { __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); + if (unlikely(need_more)) { + int i, cnt = 0; + for_each_cpu_mask(i, mask) { + cpu_clear(i, mask); + cnt++; + if (cnt == 32) + break; + } + goto retry; + } return; } if (!--stuck) @@ -544,6 +516,8 @@ retry: if ((dispatch_stat & check_mask) == 0) cpu_clear(i, mask); this_busy_nack += 2; + if (this_busy_nack == 64) + break; } goto retry; @@ -1191,23 +1165,14 @@ int setup_profiling_timer(unsigned int multiplier) static void __init smp_tune_scheduling(void) { - struct device_node *dp; - int instance; - unsigned int def, smallest = ~0U; - - def = ((tlb_type == hypervisor) ? - (3 * 1024 * 1024) : - (4 * 1024 * 1024)); + unsigned int smallest = ~0U; + int i; - instance = 0; - while (!cpu_find_by_instance(instance, &dp, NULL)) { - unsigned int val; + for (i = 0; i < NR_CPUS; i++) { + unsigned int val = cpu_data(i).ecache_size; - val = of_getintprop_default(dp, "ecache-size", def); - if (val < smallest) + if (val && val < smallest) smallest = val; - - instance++; } /* Any value less than 256K is nonsense. */ @@ -1230,60 +1195,59 @@ void __init smp_prepare_cpus(unsigned int max_cpus) int i; if (num_possible_cpus() > max_cpus) { - int instance, mid; - - instance = 0; - while (!cpu_find_by_instance(instance, NULL, &mid)) { - if (mid != boot_cpu_id) { - cpu_clear(mid, phys_cpu_present_map); - cpu_clear(mid, cpu_present_map); + for_each_possible_cpu(i) { + if (i != boot_cpu_id) { + cpu_clear(i, phys_cpu_present_map); + cpu_clear(i, cpu_present_map); if (num_possible_cpus() <= max_cpus) break; } - instance++; } } + cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy; + smp_tune_scheduling(); +} + +void __devinit smp_prepare_boot_cpu(void) +{ +} + +void __devinit smp_fill_in_sib_core_maps(void) +{ + unsigned int i; + for_each_possible_cpu(i) { - if (tlb_type == hypervisor) { - int j; + unsigned int j; - /* XXX get this mapping from machine description */ - for_each_possible_cpu(j) { - if ((j >> 2) == (i >> 2)) - cpu_set(j, cpu_sibling_map[i]); - } - } else { - cpu_set(i, cpu_sibling_map[i]); + if (cpu_data(i).core_id == 0) { + cpu_set(i, cpu_core_map[i]); + continue; + } + + for_each_possible_cpu(j) { + if (cpu_data(i).core_id == + cpu_data(j).core_id) + cpu_set(j, cpu_core_map[i]); } } - smp_store_cpu_info(boot_cpu_id); - smp_tune_scheduling(); -} + for_each_possible_cpu(i) { + unsigned int j; -/* Set this up early so that things like the scheduler can init - * properly. We use the same cpu mask for both the present and - * possible cpu map. - */ -void __init smp_setup_cpu_possible_map(void) -{ - int instance, mid; + if (cpu_data(i).proc_id == -1) { + cpu_set(i, cpu_sibling_map[i]); + continue; + } - instance = 0; - while (!cpu_find_by_instance(instance, NULL, &mid)) { - if (mid < NR_CPUS) { - cpu_set(mid, phys_cpu_present_map); - cpu_set(mid, cpu_present_map); + for_each_possible_cpu(j) { + if (cpu_data(i).proc_id == + cpu_data(j).proc_id) + cpu_set(j, cpu_sibling_map[i]); } - instance++; } } -void __devinit smp_prepare_boot_cpu(void) -{ -} - int __cpuinit __cpu_up(unsigned int cpu) { int ret = smp_boot_one_cpu(cpu); @@ -1337,7 +1301,7 @@ unsigned long __per_cpu_shift __read_mostly; EXPORT_SYMBOL(__per_cpu_base); EXPORT_SYMBOL(__per_cpu_shift); -void __init setup_per_cpu_areas(void) +void __init real_setup_per_cpu_areas(void) { unsigned long goal, size, i; char *ptr; diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index d00f51a5683..6fa76161289 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -24,6 +24,7 @@ #include <linux/syscalls.h> #include <linux/percpu.h> #include <linux/init.h> +#include <linux/rwsem.h> #include <net/compat.h> #include <asm/oplib.h> @@ -58,7 +59,6 @@ #include <asm/ns87303.h> #include <asm/timer.h> #include <asm/cpudata.h> -#include <asm/rwsem.h> struct poll { int fd; diff --git a/arch/sparc64/kernel/sstate.c b/arch/sparc64/kernel/sstate.c new file mode 100644 index 00000000000..5b6e75b7f05 --- /dev/null +++ b/arch/sparc64/kernel/sstate.c @@ -0,0 +1,104 @@ +/* sstate.c: System soft state support. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ + +#include <linux/kernel.h> +#include <linux/notifier.h> +#include <linux/init.h> + +#include <asm/hypervisor.h> +#include <asm/sstate.h> +#include <asm/oplib.h> +#include <asm/head.h> +#include <asm/io.h> + +static int hv_supports_soft_state; + +static unsigned long kimage_addr_to_ra(const char *p) +{ + unsigned long val = (unsigned long) p; + + return kern_base + (val - KERNBASE); +} + +static void do_set_sstate(unsigned long state, const char *msg) +{ + unsigned long err; + + if (!hv_supports_soft_state) + return; + + err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg)); + if (err) { + printk(KERN_WARNING "SSTATE: Failed to set soft-state to " + "state[%lx] msg[%s], err=%lu\n", + state, msg, err); + } +} + +static const char booting_msg[32] __attribute__((aligned(32))) = + "Linux booting"; +static const char running_msg[32] __attribute__((aligned(32))) = + "Linux running"; +static const char halting_msg[32] __attribute__((aligned(32))) = + "Linux halting"; +static const char poweroff_msg[32] __attribute__((aligned(32))) = + "Linux powering off"; +static const char rebooting_msg[32] __attribute__((aligned(32))) = + "Linux rebooting"; +static const char panicing_msg[32] __attribute__((aligned(32))) = + "Linux panicing"; + +void sstate_booting(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg); +} + +void sstate_running(void) +{ + do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg); +} + +void sstate_halt(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg); +} + +void sstate_poweroff(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg); +} + +void sstate_reboot(void) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg); +} + +static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr) +{ + do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg); + + return NOTIFY_DONE; +} + +static struct notifier_block sstate_panic_block = { + .notifier_call = sstate_panic_event, + .priority = INT_MAX, +}; + +void __init sun4v_sstate_init(void) +{ + unsigned long major, minor; + + major = 1; + minor = 0; + if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor)) + return; + + hv_supports_soft_state = 1; + + prom_sun4v_guest_soft_state(); + atomic_notifier_chain_register(&panic_notifier_list, + &sstate_panic_block); +} diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S index 405855dd886..574bc248bca 100644 --- a/arch/sparc64/kernel/sun4v_ivec.S +++ b/arch/sparc64/kernel/sun4v_ivec.S @@ -22,12 +22,12 @@ sun4v_cpu_mondo: be,pn %xcc, sun4v_cpu_mondo_queue_empty nop - /* Get &trap_block[smp_processor_id()] into %g3. */ - ldxa [%g0] ASI_SCRATCHPAD, %g3 - sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 + /* Get &trap_block[smp_processor_id()] into %g4. */ + ldxa [%g0] ASI_SCRATCHPAD, %g4 + sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4 /* Get CPU mondo queue base phys address into %g7. */ - ldx [%g3 + TRAP_PER_CPU_CPU_MONDO_PA], %g7 + ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7 /* Now get the cross-call arguments and handler PC, same * layout as sun4u: @@ -47,8 +47,7 @@ sun4v_cpu_mondo: add %g2, 0x40 - 0x8 - 0x8, %g2 /* Update queue head pointer. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 + lduw [%g4 + TRAP_PER_CPU_CPU_MONDO_QMASK], %g4 and %g2, %g4, %g2 mov INTRQ_CPU_MONDO_HEAD, %g4 @@ -71,12 +70,12 @@ sun4v_dev_mondo: be,pn %xcc, sun4v_dev_mondo_queue_empty nop - /* Get &trap_block[smp_processor_id()] into %g3. */ - ldxa [%g0] ASI_SCRATCHPAD, %g3 - sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3 + /* Get &trap_block[smp_processor_id()] into %g4. */ + ldxa [%g0] ASI_SCRATCHPAD, %g4 + sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4 /* Get DEV mondo queue base phys address into %g5. */ - ldx [%g3 + TRAP_PER_CPU_DEV_MONDO_PA], %g5 + ldx [%g4 + TRAP_PER_CPU_DEV_MONDO_PA], %g5 /* Load IVEC into %g3. */ ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3 @@ -90,8 +89,7 @@ sun4v_dev_mondo: */ /* Update queue head pointer, this frees up some registers. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 + lduw [%g4 + TRAP_PER_CPU_DEV_MONDO_QMASK], %g4 and %g2, %g4, %g2 mov INTRQ_DEVICE_MONDO_HEAD, %g4 @@ -143,6 +141,8 @@ sun4v_res_mondo: brnz,pn %g1, sun4v_res_mondo_queue_full nop + lduw [%g3 + TRAP_PER_CPU_RESUM_QMASK], %g4 + /* Remember this entry's offset in %g1. */ mov %g2, %g1 @@ -173,8 +173,6 @@ sun4v_res_mondo: add %g2, 0x08, %g2 /* Update queue head pointer. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 and %g2, %g4, %g2 mov INTRQ_RESUM_MONDO_HEAD, %g4 @@ -254,6 +252,8 @@ sun4v_nonres_mondo: brnz,pn %g1, sun4v_nonres_mondo_queue_full nop + lduw [%g3 + TRAP_PER_CPU_NONRESUM_QMASK], %g4 + /* Remember this entry's offset in %g1. */ mov %g2, %g1 @@ -284,8 +284,6 @@ sun4v_nonres_mondo: add %g2, 0x08, %g2 /* Update queue head pointer. */ - sethi %hi(8192 - 1), %g4 - or %g4, %lo(8192 - 1), %g4 and %g2, %g4, %g2 mov INTRQ_NONRESUM_MONDO_HEAD, %g4 diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c new file mode 100644 index 00000000000..cdb1477af89 --- /dev/null +++ b/arch/sparc64/kernel/sysfs.c @@ -0,0 +1,297 @@ +/* sysfs.c: Toplogy sysfs support code for sparc64. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ +#include <linux/sysdev.h> +#include <linux/cpu.h> +#include <linux/smp.h> +#include <linux/percpu.h> +#include <linux/init.h> + +#include <asm/hypervisor.h> +#include <asm/spitfire.h> + +static DEFINE_PER_CPU(struct hv_mmu_statistics, mmu_stats) __attribute__((aligned(64))); + +#define SHOW_MMUSTAT_ULONG(NAME) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + struct hv_mmu_statistics *p = &per_cpu(mmu_stats, dev->id); \ + return sprintf(buf, "%lu\n", p->NAME); \ +} \ +static SYSDEV_ATTR(NAME, 0444, show_##NAME, NULL) + +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_256mb_tte); + +static struct attribute *mmu_stat_attrs[] = { + &attr_immu_tsb_hits_ctx0_8k_tte.attr, + &attr_immu_tsb_ticks_ctx0_8k_tte.attr, + &attr_immu_tsb_hits_ctx0_64k_tte.attr, + &attr_immu_tsb_ticks_ctx0_64k_tte.attr, + &attr_immu_tsb_hits_ctx0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_immu_tsb_hits_ctx0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_256mb_tte.attr, + NULL, +}; + +static struct attribute_group mmu_stat_group = { + .attrs = mmu_stat_attrs, + .name = "mmu_stats", +}; + +/* XXX convert to rusty's on_one_cpu */ +static unsigned long run_on_cpu(unsigned long cpu, + unsigned long (*func)(unsigned long), + unsigned long arg) +{ + cpumask_t old_affinity = current->cpus_allowed; + unsigned long ret; + + /* should return -EINVAL to userspace */ + if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) + return 0; + + ret = func(arg); + + set_cpus_allowed(current, old_affinity); + + return ret; +} + +static unsigned long read_mmustat_enable(unsigned long junk) +{ + unsigned long ra = 0; + + sun4v_mmustat_info(&ra); + + return ra != 0; +} + +static unsigned long write_mmustat_enable(unsigned long val) +{ + unsigned long ra, orig_ra; + + if (val) + ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); + else + ra = 0UL; + + return sun4v_mmustat_conf(ra, &orig_ra); +} + +static ssize_t show_mmustat_enable(struct sys_device *s, char *buf) +{ + unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); + return sprintf(buf, "%lx\n", val); +} + +static ssize_t store_mmustat_enable(struct sys_device *s, const char *buf, size_t count) +{ + unsigned long val, err; + int ret = sscanf(buf, "%ld", &val); + + if (ret != 1) + return -EINVAL; + + err = run_on_cpu(s->id, write_mmustat_enable, val); + if (err) + return -EIO; + + return count; +} + +static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); + +static int mmu_stats_supported; + +static int register_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return 0; + sysdev_create_file(s, &attr_mmustat_enable); + return sysfs_create_group(&s->kobj, &mmu_stat_group); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return; + sysfs_remove_group(&s->kobj, &mmu_stat_group); + sysdev_remove_file(s, &attr_mmustat_enable); +} +#endif + +#define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ + return sprintf(buf, "%lu\n", c->MEMBER); \ +} + +#define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ + return sprintf(buf, "%u\n", c->MEMBER); \ +} + +SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); +SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val); +SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); +SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); + +static struct sysdev_attribute cpu_core_attrs[] = { + _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), + _SYSDEV_ATTR(udelay_val, 0444, show_udelay_val, NULL), + _SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL), + _SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL), + _SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL), + _SYSDEV_ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL), + _SYSDEV_ATTR(l2_cache_size, 0444, show_l2_cache_size, NULL), + _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), +}; + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +static void register_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_create_file(s, &cpu_core_attrs[i]); + + register_mmu_stats(s); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + unregister_mmu_stats(s); + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_remove_file(s, &cpu_core_attrs[i]); +} +#endif + +static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned int)(long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + register_cpu_online(cpu); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + case CPU_DEAD_FROZEN: + unregister_cpu_online(cpu); + break; +#endif + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata sysfs_cpu_nb = { + .notifier_call = sysfs_cpu_notify, +}; + +static void __init check_mmu_stats(void) +{ + unsigned long dummy1, err; + + if (tlb_type != hypervisor) + return; + + err = sun4v_mmustat_info(&dummy1); + if (!err) + mmu_stats_supported = 1; +} + +static int __init topology_init(void) +{ + int cpu; + + check_mmu_stats(); + + register_cpu_notifier(&sysfs_cpu_nb); + + for_each_possible_cpu(cpu) { + struct cpu *c = &per_cpu(cpu_devices, cpu); + + register_cpu(c, cpu); + if (cpu_online(cpu)) + register_cpu_online(cpu); + } + + return 0; +} + +subsys_initcall(topology_init); diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 2d63d768996..a31a0439244 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -680,22 +680,14 @@ static int starfire_set_time(u32 val) static u32 hypervisor_get_time(void) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); - register unsigned long arg1 asm("%o1"); + unsigned long ret, time; int retries = 10000; retry: - func = HV_FAST_TOD_GET; - arg0 = 0; - arg1 = 0; - __asm__ __volatile__("ta %6" - : "=&r" (func), "=&r" (arg0), "=&r" (arg1) - : "0" (func), "1" (arg0), "2" (arg1), - "i" (HV_FAST_TRAP)); - if (arg0 == HV_EOK) - return arg1; - if (arg0 == HV_EWOULDBLOCK) { + ret = sun4v_tod_get(&time); + if (ret == HV_EOK) + return time; + if (ret == HV_EWOULDBLOCK) { if (--retries > 0) { udelay(100); goto retry; @@ -709,20 +701,14 @@ retry: static int hypervisor_set_time(u32 secs) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); + unsigned long ret; int retries = 10000; retry: - func = HV_FAST_TOD_SET; - arg0 = secs; - __asm__ __volatile__("ta %4" - : "=&r" (func), "=&r" (arg0) - : "0" (func), "1" (arg0), - "i" (HV_FAST_TRAP)); - if (arg0 == HV_EOK) + ret = sun4v_tod_set(secs); + if (ret == HV_EOK) return 0; - if (arg0 == HV_EWOULDBLOCK) { + if (ret == HV_EWOULDBLOCK) { if (--retries > 0) { udelay(100); goto retry; @@ -862,7 +848,6 @@ fs_initcall(clock_init); static unsigned long sparc64_init_timers(void) { struct device_node *dp; - struct property *prop; unsigned long clock; #ifdef CONFIG_SMP extern void smp_tick_init(void); @@ -879,17 +864,15 @@ static unsigned long sparc64_init_timers(void) if (manuf == 0x17 && impl == 0x13) { /* Hummingbird, aka Ultra-IIe */ tick_ops = &hbtick_operations; - prop = of_find_property(dp, "stick-frequency", NULL); + clock = of_getintprop_default(dp, "stick-frequency", 0); } else { tick_ops = &tick_operations; - cpu_find_by_instance(0, &dp, NULL); - prop = of_find_property(dp, "clock-frequency", NULL); + clock = local_cpu_data().clock_tick; } } else { tick_ops = &stick_operations; - prop = of_find_property(dp, "stick-frequency", NULL); + clock = of_getintprop_default(dp, "stick-frequency", 0); } - clock = *(unsigned int *) prop->value; #ifdef CONFIG_SMP smp_tick_init(); @@ -1365,6 +1348,7 @@ static int hypervisor_set_rtc_time(struct rtc_time *time) return hypervisor_set_time(seconds); } +#ifdef CONFIG_PCI static void bq4802_get_rtc_time(struct rtc_time *time) { unsigned char val = readb(bq4802_regs + 0x0e); @@ -1436,6 +1420,7 @@ static int bq4802_set_rtc_time(struct rtc_time *time) return 0; } +#endif /* CONFIG_PCI */ struct mini_rtc_ops { void (*get_rtc_time)(struct rtc_time *); @@ -1452,10 +1437,12 @@ static struct mini_rtc_ops hypervisor_rtc_ops = { .set_rtc_time = hypervisor_set_rtc_time, }; +#ifdef CONFIG_PCI static struct mini_rtc_ops bq4802_rtc_ops = { .get_rtc_time = bq4802_get_rtc_time, .set_rtc_time = bq4802_set_rtc_time, }; +#endif /* CONFIG_PCI */ static struct mini_rtc_ops *mini_rtc_ops; @@ -1579,8 +1566,10 @@ static int __init rtc_mini_init(void) mini_rtc_ops = &hypervisor_rtc_ops; else if (this_is_starfire) mini_rtc_ops = &starfire_rtc_ops; +#ifdef CONFIG_PCI else if (bq4802_regs) mini_rtc_ops = &bq4802_rtc_ops; +#endif /* CONFIG_PCI */ else return -ENODEV; diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index d0fde36395b..00a9e3286c8 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -795,8 +795,7 @@ extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector void __init cheetah_ecache_flush_init(void) { unsigned long largest_size, smallest_linesize, order, ver; - struct device_node *dp; - int i, instance, sz; + int i, sz; /* Scan all cpu device tree nodes, note two values: * 1) largest E-cache size @@ -805,18 +804,20 @@ void __init cheetah_ecache_flush_init(void) largest_size = 0UL; smallest_linesize = ~0UL; - instance = 0; - while (!cpu_find_by_instance(instance, &dp, NULL)) { + for (i = 0; i < NR_CPUS; i++) { unsigned long val; - val = of_getintprop_default(dp, "ecache-size", - (2 * 1024 * 1024)); + val = cpu_data(i).ecache_size; + if (!val) + continue; + if (val > largest_size) largest_size = val; - val = of_getintprop_default(dp, "ecache-line-size", 64); + + val = cpu_data(i).ecache_line_size; if (val < smallest_linesize) smallest_linesize = val; - instance++; + } if (largest_size == 0UL || smallest_linesize == ~0UL) { @@ -2564,7 +2565,15 @@ void __init trap_init(void) (TRAP_PER_CPU_TSB_HUGE_TEMP != offsetof(struct trap_per_cpu, tsb_huge_temp)) || (TRAP_PER_CPU_IRQ_WORKLIST != - offsetof(struct trap_per_cpu, irq_worklist))) + offsetof(struct trap_per_cpu, irq_worklist)) || + (TRAP_PER_CPU_CPU_MONDO_QMASK != + offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || + (TRAP_PER_CPU_DEV_MONDO_QMASK != + offsetof(struct trap_per_cpu, dev_mondo_qmask)) || + (TRAP_PER_CPU_RESUM_QMASK != + offsetof(struct trap_per_cpu, resum_qmask)) || + (TRAP_PER_CPU_NONRESUM_QMASK != + offsetof(struct trap_per_cpu, nonresum_qmask))) trap_per_cpu_offsets_are_bolixed_dave(); if ((TSB_CONFIG_TSB != diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S index fb648de18a8..3ad10f3027e 100644 --- a/arch/sparc64/kernel/vmlinux.lds.S +++ b/arch/sparc64/kernel/vmlinux.lds.S @@ -1,5 +1,6 @@ /* ld script to make UltraLinux kernel */ +#include <asm/page.h> #include <asm-generic/vmlinux.lds.h> OUTPUT_FORMAT("elf64-sparc", "elf64-sparc", "elf64-sparc") @@ -23,7 +24,7 @@ SECTIONS _etext = .; PROVIDE (etext = .); - RODATA + RO_DATA(PAGE_SIZE) .data : { @@ -44,7 +45,7 @@ SECTIONS __ex_table : { *(__ex_table) } __stop___ex_table = .; - . = ALIGN(8192); + . = ALIGN(PAGE_SIZE); __init_begin = .; .init.text : { _sinittext = .; @@ -83,17 +84,17 @@ SECTIONS __sun4v_2insn_patch_end = .; #ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(8192); + . = ALIGN(PAGE_SIZE); __initramfs_start = .; .init.ramfs : { *(.init.ramfs) } __initramfs_end = .; #endif - . = ALIGN(8192); + . = ALIGN(PAGE_SIZE); __per_cpu_start = .; .data.percpu : { *(.data.percpu) } __per_cpu_end = .; - . = ALIGN(8192); + . = ALIGN(PAGE_SIZE); __init_end = .; __bss_start = .; .sbss : { *(.sbss) *(.scommon) } diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 6e5b01d779d..3010227fe24 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -23,6 +23,7 @@ #include <linux/kprobes.h> #include <linux/cache.h> #include <linux/sort.h> +#include <linux/percpu.h> #include <asm/head.h> #include <asm/system.h> @@ -43,8 +44,8 @@ #include <asm/tsb.h> #include <asm/hypervisor.h> #include <asm/prom.h> - -extern void device_scan(void); +#include <asm/sstate.h> +#include <asm/mdesc.h> #define MAX_PHYS_ADDRESS (1UL << 42UL) #define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL) @@ -60,8 +61,11 @@ unsigned long kern_linear_pte_xor[2] __read_mostly; unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)]; #ifndef CONFIG_DEBUG_PAGEALLOC -/* A special kernel TSB for 4MB and 256MB linear mappings. */ -struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES]; +/* A special kernel TSB for 4MB and 256MB linear mappings. + * Space is allocated for this right after the trap table + * in arch/sparc64/kernel/head.S + */ +extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES]; #endif #define MAX_BANKS 32 @@ -190,12 +194,9 @@ inline void flush_dcache_page_impl(struct page *page) } #define PG_dcache_dirty PG_arch_1 -#define PG_dcache_cpu_shift 24UL -#define PG_dcache_cpu_mask (256UL - 1UL) - -#if NR_CPUS > 256 -#error D-cache dirty tracking and thread_info->cpu need fixing for > 256 cpus -#endif +#define PG_dcache_cpu_shift 32UL +#define PG_dcache_cpu_mask \ + ((1UL<<ilog2(roundup_pow_of_two(NR_CPUS)))-1UL) #define dcache_dirty_cpu(page) \ (((page)->flags >> PG_dcache_cpu_shift) & PG_dcache_cpu_mask) @@ -557,26 +558,11 @@ static void __init hypervisor_tlb_lock(unsigned long vaddr, unsigned long pte, unsigned long mmu) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); - register unsigned long arg1 asm("%o1"); - register unsigned long arg2 asm("%o2"); - register unsigned long arg3 asm("%o3"); - - func = HV_FAST_MMU_MAP_PERM_ADDR; - arg0 = vaddr; - arg1 = 0; - arg2 = pte; - arg3 = mmu; - __asm__ __volatile__("ta 0x80" - : "=&r" (func), "=&r" (arg0), - "=&r" (arg1), "=&r" (arg2), - "=&r" (arg3) - : "0" (func), "1" (arg0), "2" (arg1), - "3" (arg2), "4" (arg3)); - if (arg0 != 0) { + unsigned long ret = sun4v_mmu_map_perm_addr(vaddr, 0, pte, mmu); + + if (ret != 0) { prom_printf("hypervisor_tlb_lock[%lx:%lx:%lx:%lx]: " - "errors with %lx\n", vaddr, 0, pte, mmu, arg0); + "errors with %lx\n", vaddr, 0, pte, mmu, ret); prom_halt(); } } @@ -1313,20 +1299,16 @@ static void __init sun4v_ktsb_init(void) void __cpuinit sun4v_ktsb_register(void) { - register unsigned long func asm("%o5"); - register unsigned long arg0 asm("%o0"); - register unsigned long arg1 asm("%o1"); - unsigned long pa; + unsigned long pa, ret; pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE); - func = HV_FAST_MMU_TSB_CTX0; - arg0 = NUM_KTSB_DESCR; - arg1 = pa; - __asm__ __volatile__("ta %6" - : "=&r" (func), "=&r" (arg0), "=&r" (arg1) - : "0" (func), "1" (arg0), "2" (arg1), - "i" (HV_FAST_TRAP)); + ret = sun4v_mmu_tsb_ctx0(NUM_KTSB_DESCR, pa); + if (ret != 0) { + prom_printf("hypervisor_mmu_tsb_ctx0[%lx]: " + "errors with %lx\n", pa, ret); + prom_halt(); + } } /* paging_init() sets up the page tables */ @@ -1334,6 +1316,9 @@ void __cpuinit sun4v_ktsb_register(void) extern void cheetah_ecache_flush_init(void); extern void sun4v_patch_tlb_handlers(void); +extern void cpu_probe(void); +extern void central_probe(void); + static unsigned long last_valid_pfn; pgd_t swapper_pg_dir[2048]; @@ -1345,9 +1330,24 @@ void __init paging_init(void) unsigned long end_pfn, pages_avail, shift, phys_base; unsigned long real_end, i; + /* These build time checkes make sure that the dcache_dirty_cpu() + * page->flags usage will work. + * + * When a page gets marked as dcache-dirty, we store the + * cpu number starting at bit 32 in the page->flags. Also, + * functions like clear_dcache_dirty_cpu use the cpu mask + * in 13-bit signed-immediate instruction fields. + */ + BUILD_BUG_ON(FLAGS_RESERVED != 32); + BUILD_BUG_ON(SECTIONS_WIDTH + NODES_WIDTH + ZONES_WIDTH + + ilog2(roundup_pow_of_two(NR_CPUS)) > FLAGS_RESERVED); + BUILD_BUG_ON(NR_CPUS > 4096); + kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL; kern_size = (unsigned long)&_end - (unsigned long)KERNBASE; + sstate_booting(); + /* Invalidate both kernel TSBs. */ memset(swapper_tsb, 0x40, sizeof(swapper_tsb)); #ifndef CONFIG_DEBUG_PAGEALLOC @@ -1416,8 +1416,13 @@ void __init paging_init(void) kernel_physical_mapping_init(); + real_setup_per_cpu_areas(); + prom_build_devicetree(); + if (tlb_type == hypervisor) + sun4v_mdesc_init(); + { unsigned long zones_size[MAX_NR_ZONES]; unsigned long zholes_size[MAX_NR_ZONES]; @@ -1434,7 +1439,10 @@ void __init paging_init(void) zholes_size); } - device_scan(); + prom_printf("Booting Linux...\n"); + + central_probe(); + cpu_probe(); } static void __init taint_real_pages(void) diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 0b4213720d4..f3e0c14e9ee 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -15,6 +15,25 @@ #include <asm/oplib.h> #include <asm/system.h> +int prom_service_exists(const char *service_name) +{ + int err = p1275_cmd("test", P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_INOUT(1, 1), service_name); + + if (err) + return 0; + return 1; +} + +void prom_sun4v_guest_soft_state(void) +{ + const char *svc = "SUNW,soft-state-supported"; + + if (!prom_service_exists(svc)) + return; + p1275_cmd(svc, P1275_INOUT(0, 0)); +} + /* Reset and reboot the machine with the command 'bcommand'. */ void prom_reboot(const char *bcommand) { diff --git a/arch/um/Kconfig b/arch/um/Kconfig index c504312219b..e6ff3026654 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -278,6 +278,7 @@ config HIGHMEM config KERNEL_STACK_ORDER int "Kernel stack size order" default 1 if 64BIT + range 1 10 if 64BIT default 0 if !64BIT help This option determines the size of UML kernel stacks. They will diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index ced99106f79..4bd40bb43ec 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include "linux/kernel.h" #include "linux/sched.h" #include "linux/slab.h" #include "linux/list.h" diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c index 91153929387..4739dd527b4 100644 --- a/arch/um/drivers/stderr_console.c +++ b/arch/um/drivers/stderr_console.c @@ -1,3 +1,4 @@ +#include <linux/kernel.h> #include <linux/init.h> #include <linux/console.h> diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 70509ddaac0..2e09f162c42 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -20,6 +20,7 @@ #define MAJOR_NR UBD_MAJOR #define UBD_SHIFT 4 +#include "linux/kernel.h" #include "linux/module.h" #include "linux/blkdev.h" #include "linux/hdreg.h" diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 8b7f2cdedf9..c716b5a6db1 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -1,8 +1,9 @@ -/* +/* * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ +#include "linux/kernel.h" #include "linux/init.h" #include "linux/ctype.h" #include "linux/proc_fs.h" @@ -24,11 +25,14 @@ static int read_proc_exitcode(char *page, char **start, off_t off, val = uml_exitcode; len = sprintf(page, "%d\n", val); len -= off; - if(len <= off+count) *eof = 1; + if(len <= off+count) + *eof = 1; *start = page + off; - if(len > count) len = count; - if(len < 0) len = 0; - return(len); + if(len > count) + len = count; + if(len < 0) + len = 0; + return len; } static int write_proc_exitcode(struct file *file, const char __user *buffer, @@ -38,12 +42,14 @@ static int write_proc_exitcode(struct file *file, const char __user *buffer, int tmp; if(copy_from_user(buf, buffer, count)) - return(-EFAULT); + return -EFAULT; + tmp = simple_strtol(buf, &end, 0); if((*end != '\0') && !isspace(*end)) - return(-EINVAL); + return -EINVAL; + uml_exitcode = tmp; - return(count); + return count; } static int make_proc_exitcode(void) @@ -54,24 +60,13 @@ static int make_proc_exitcode(void) if(ent == NULL){ printk(KERN_WARNING "make_proc_exitcode : Failed to register " "/proc/exitcode\n"); - return(0); + return 0; } ent->read_proc = read_proc_exitcode; ent->write_proc = write_proc_exitcode; - - return(0); + + return 0; } __initcall(make_proc_exitcode); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 79471f85eb8..3fc13fa8729 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -144,9 +144,7 @@ static int stop_ptraced_child(int pid, void *stack, int exitcode, int exit_with = WEXITSTATUS(status); if (exit_with == 2) non_fatal("check_ptrace : child exited with status 2. " - "Serious trouble happening! Try updating " - "your host skas patch!\nDisabling SYSEMU " - "support."); + "\nDisabling SYSEMU support.\n"); non_fatal("check_ptrace : child exited with exitcode %d, while " "expecting %d; status 0x%x\n", exit_with, exitcode, status); @@ -209,6 +207,7 @@ __uml_setup("nosysemu", nosysemu_cmd_param, static void __init check_sysemu(void) { void *stack; + unsigned long regs[MAX_REG_NR]; int pid, n, status, count=0; non_fatal("Checking syscall emulation patch for ptrace..."); @@ -225,11 +224,20 @@ static void __init check_sysemu(void) fatal("check_sysemu : expected SIGTRAP, got status = %d", status); - n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, - os_getpid()); - if(n < 0) - fatal_perror("check_sysemu : failed to modify system call " - "return"); + if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) + fatal_perror("check_sysemu : PTRACE_GETREGS failed"); + if(PT_SYSCALL_NR(regs) != __NR_getpid){ + non_fatal("check_sysemu got system call number %d, " + "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); + goto fail; + } + + n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); + if(n < 0){ + non_fatal("check_sysemu : failed to modify system call " + "return"); + goto fail; + } if (stop_ptraced_child(pid, stack, 0, 0) < 0) goto fail_stopped; diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 145bb824b2a..5ce94430c01 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -428,12 +428,15 @@ config NR_CPUS memory in the static kernel configuration. config HOTPLUG_CPU - bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + bool "Support for suspend on SMP and hot-pluggable CPUs (EXPERIMENTAL)" depends on SMP && HOTPLUG && EXPERIMENTAL help Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu/cpu#. - Say N if you want to disable CPU hotplug. + This is also required for suspend/hibernation on SMP systems. + + Say N if you want to disable CPU hotplug and don't need to + suspend. config ARCH_ENABLE_MEMORY_HOTPLUG def_bool y diff --git a/arch/x86_64/kernel/k8.c b/arch/x86_64/kernel/k8.c index bc11b32e8b4..7377ccb2133 100644 --- a/arch/x86_64/kernel/k8.c +++ b/arch/x86_64/kernel/k8.c @@ -39,10 +39,10 @@ int cache_k8_northbridges(void) { int i; struct pci_dev *dev; + if (num_k8_northbridges) return 0; - num_k8_northbridges = 0; dev = NULL; while ((dev = next_k8_northbridge(dev)) != NULL) num_k8_northbridges++; @@ -52,6 +52,11 @@ int cache_k8_northbridges(void) if (!k8_northbridges) return -ENOMEM; + if (!num_k8_northbridges) { + k8_northbridges[0] = NULL; + return 0; + } + flush_words = kmalloc(num_k8_northbridges * sizeof(u32), GFP_KERNEL); if (!flush_words) { kfree(k8_northbridges); diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index cb29fb96948..aac1c0be54c 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -465,13 +465,14 @@ static unsigned int die_nest_count; unsigned __kprobes long oops_begin(void) { - int cpu = smp_processor_id(); + int cpu; unsigned long flags; oops_enter(); /* racy, but better than risking deadlock. */ local_irq_save(flags); + cpu = smp_processor_id(); if (!spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index bfb62a13d7e..635e58d443d 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -476,6 +476,12 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ if (error_code & PF_USER) { + + /* + * It's possible to have interrupts off here. + */ + local_irq_enable(); + if (is_prefetch(regs, address, error_code)) return; diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index 1336da8bdee..efb6e845114 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -79,6 +79,8 @@ void show_mem(void) if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) { touch_nmi_watchdog(); } + if (!pfn_valid(pgdat->node_start_pfn + i)) + continue; page = pfn_to_page(pgdat->node_start_pfn + i); total++; if (PageReserved(page)) @@ -761,3 +763,9 @@ int in_gate_area_no_task(unsigned long addr) { return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END); } + +void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size) +{ + return __alloc_bootmem_core(pgdat->bdata, size, + SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0); +} diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 698079b3a33..d0323cd6a2e 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c @@ -39,6 +39,7 @@ int main(void) DEFINE(PT_LEND, offsetof (struct pt_regs, lend)); DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount)); DEFINE(PT_SAR, offsetof (struct pt_regs, sar)); + DEFINE(PT_ICOUNTLEVEL, offsetof (struct pt_regs, icountlevel)); DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall)); DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0])); DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0])); diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 9e271ba009b..8dc7a2c26ff 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -125,8 +125,9 @@ _user_exception: movi a2, 0 rsr a3, SAR - wsr a2, ICOUNTLEVEL + xsr a2, ICOUNTLEVEL s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL /* Rotate ws so that the current windowbase is at bit0. */ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ @@ -276,8 +277,9 @@ _kernel_exception: movi a2, 0 rsr a3, SAR - wsr a2, ICOUNTLEVEL + xsr a2, ICOUNTLEVEL s32i a3, a1, PT_SAR + s32i a2, a1, PT_ICOUNTLEVEL /* Rotate ws so that the current windowbase is at bit0. */ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ @@ -330,14 +332,16 @@ _kernel_exception: common_exception: - /* Save EXCVADDR, DEBUGCAUSE, and PC, and clear LCOUNT */ + /* Save some registers, disable loops and clear the syscall flag. */ rsr a2, DEBUGCAUSE rsr a3, EPC_1 s32i a2, a1, PT_DEBUGCAUSE s32i a3, a1, PT_PC + movi a2, -1 rsr a3, EXCVADDR + s32i a2, a1, PT_SYSCALL movi a2, 0 s32i a3, a1, PT_EXCVADDR xsr a2, LCOUNT @@ -450,27 +454,8 @@ common_exception_return: /* Restore the state of the task and return from the exception. */ - - /* If we are returning from a user exception, and the process - * to run next has PT_SINGLESTEP set, we want to setup - * ICOUNT and ICOUNTLEVEL to step one instruction. - * PT_SINGLESTEP is set by sys_ptrace (ptrace.c) - */ - 4: /* a2 holds GET_CURRENT(a2,a1) */ - l32i a3, a2, TI_TASK - l32i a3, a3, TASK_PTRACE - bbci.l a3, PT_SINGLESTEP_BIT, 1f # jump if single-step flag is not set - - movi a3, -2 # PT_SINGLESTEP flag is set, - movi a4, 1 # icountlevel of 1 means it won't - wsr a3, ICOUNT # start counting until after rfe - wsr a4, ICOUNTLEVEL # so setup icount & icountlevel. - isync - -1: - #if XCHAL_EXTRA_SA_SIZE /* For user exceptions, restore the extra state from the user's TCB. */ @@ -665,6 +650,13 @@ common_exception_exit: wsr a3, LEND wsr a2, LCOUNT + /* We control single stepping through the ICOUNTLEVEL register. */ + + l32i a2, a1, PT_ICOUNTLEVEL + movi a3, -2 + wsr a2, ICOUNTLEVEL + wsr a3, ICOUNT + /* Check if it was double exception. */ l32i a0, a1, PT_DEPC diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index ea89910efa4..67e69139520 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S @@ -19,6 +19,8 @@ #include <asm/page.h> #include <asm/cacheasm.h> +#include <linux/linkage.h> + /* * This module contains the entry code for kernel images. It performs the * minimal setup needed to call the generic C routines. @@ -227,13 +229,14 @@ _startup: should_never_return: j should_never_return - /* Define some common data structures here. We define them - * here in this assembly file due to their unusual alignment - * requirements. - */ - .comm swapper_pg_dir,PAGE_SIZE,PAGE_SIZE - .comm empty_bad_page_table,PAGE_SIZE,PAGE_SIZE - .comm empty_bad_page,PAGE_SIZE,PAGE_SIZE - .comm empty_zero_page,PAGE_SIZE,PAGE_SIZE +/* + * BSS section + */ + +.section ".bss.page_aligned", "w" +ENTRY(swapper_pg_dir) + .fill PAGE_SIZE, 1, 0 +ENTRY(empty_zero_page) + .fill PAGE_SIZE, 1, 0 diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index 45571ccb72d..77deae5290f 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -401,7 +401,7 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, * Also, think for a moment about likes of floppy.c that * include architecture specific parts. They may want to redefine ins/outs. * - * We do not use horroble macroses here because we want to + * We do not use horrible macros here because we want to * advance pointer by sizeof(size). */ void outsb(unsigned long addr, const void *src, unsigned long count) { diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 1ecf6716c32..2e8d398cf19 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -41,6 +41,7 @@ #include <asm/platform.h> #include <asm/page.h> #include <asm/setup.h> +#include <asm/param.h> #if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16}; diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 58107672a61..033aae0336d 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -1,397 +1,239 @@ -// TODO coprocessor stuff /* - * linux/arch/xtensa/kernel/signal.c + * arch/xtensa/kernel/signal.c * - * Copyright (C) 1991, 1992 Linus Torvalds - * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson - * - * Joe Taylor <joe@tensilica.com> - * Chris Zankel <chris@zankel.net> + * Default platform functions. * + * 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) 2005, 2006 Tensilica Inc. + * Copyright (C) 1991, 1992 Linus Torvalds + * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * + * Chris Zankel <chris@zankel.net> + * Joe Taylor <joe@tensilica.com> */ -#include <asm/variant/core.h> -#include <asm/coprocessor.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> -#include <linux/wait.h> #include <linux/ptrace.h> -#include <linux/unistd.h> -#include <linux/stddef.h> #include <linux/personality.h> +#include <linux/freezer.h> + #include <asm/ucontext.h> #include <asm/uaccess.h> -#include <asm/pgtable.h> #include <asm/cacheflush.h> +#include <asm/coprocessor.h> +#include <asm/unistd.h> #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, - struct rusage * ru); asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); extern struct task_struct *coproc_owners[]; +extern void release_all_cp (struct task_struct *); -/* - * Atomically swap in the new signal mask, and wait for a signal. +struct rt_sigframe +{ + struct siginfo info; + struct ucontext uc; + cp_state_t cpstate; + unsigned char retcode[6]; + unsigned int window[4]; +}; + +/* + * Flush register windows stored in pt_regs to stack. + * Returns 1 for errors. + * + * Note that windowbase, windowstart, and wmask are not updated! */ -int xtensa_sigsuspend(struct pt_regs *regs) +int +flush_window_regs_user(struct pt_regs *regs) { - old_sigset_t mask = (old_sigset_t) regs->areg[3]; - sigset_t saveset; + const unsigned long ws = regs->windowstart; + const unsigned long wb = regs->windowbase; + unsigned long sp = 0; + unsigned long wm; + int err = 1; + int base; - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + /* Return if no other frames. */ - regs->areg[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} + if (regs->wmask == 1) + return 0; -asmlinkage int -xtensa_rt_sigsuspend(struct pt_regs *regs) -{ - sigset_t *unewset = (sigset_t *) regs->areg[4]; - size_t sigsetsize = (size_t) regs->areg[3]; - sigset_t saveset, newset; - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; + /* Rotate windowmask and skip empty frames. */ - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + wm = (ws >> wb) | (ws << (XCHAL_NUM_AREGS / 4 - wb)); + base = (XCHAL_NUM_AREGS / 4) - (regs->wmask >> 4); + + /* For call8 or call12 frames, we need the previous stack pointer. */ - regs->areg[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_signal(regs, &saveset)) - return -EINTR; - } -} + if ((regs->wmask & 2) == 0) + if (__get_user(sp, (int*)(regs->areg[base * 4 + 1] - 12))) + goto errout; -asmlinkage int -xtensa_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; + /* Spill frames to stack. */ - if (act) { - old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } + while (base < XCHAL_NUM_AREGS / 4) { - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + int m = (wm >> base); + int inc = 0; - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + /* Save registers a4..a7 (call8) or a4...a11 (call12) */ - return ret; -} + if (m & 2) { /* call4 */ + inc = 1; -asmlinkage int -xtensa_sigaltstack(struct pt_regs *regs) -{ - const stack_t *uss = (stack_t *) regs->areg[4]; - stack_t *uoss = (stack_t *) regs->areg[3]; + } else if (m & 4) { /* call8 */ + if (copy_to_user((void*)(sp - 32), + ®s->areg[(base + 1) * 4], 16)) + goto errout; + inc = 2; - if (regs->depc > 64) - panic ("Double exception sys_sigreturn\n"); + } else if (m & 8) { /* call12 */ + if (copy_to_user((void*)(sp - 48), + ®s->areg[(base + 1) * 4], 32)) + goto errout; + inc = 3; + } + /* Save current frame a0..a3 under next SP */ - return do_sigaltstack(uss, uoss, regs->areg[1]); -} + sp = regs->areg[((base + inc) * 4 + 1) % XCHAL_NUM_AREGS]; + if (copy_to_user((void*)(sp - 16), ®s->areg[base * 4], 16)) + goto errout; + + /* Get current stack pointer for next loop iteration. */ + + sp = regs->areg[base * 4 + 1]; + base += inc; + } + + return 0; +errout: + return err; +} /* - * Do a signal return; undo the signal stack. + * Note: We don't copy double exception 'regs', we have to finish double exc. + * first before we return to signal handler! This dbl.exc.handler might cause + * another double exception, but I think we are fine as the situation is the + * same as if we had returned to the signal handerl and got an interrupt + * immediately... */ -struct sigframe -{ - struct sigcontext sc; - struct _cpstate cpstate; - unsigned long extramask[_NSIG_WORDS-1]; - unsigned char retcode[6]; - unsigned int reserved[4]; /* Reserved area for chaining */ - unsigned int window[4]; /* Window of 4 registers for initial context */ -}; - -struct rt_sigframe +static int +setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, + struct pt_regs *regs, unsigned long mask) { - struct siginfo info; - struct ucontext uc; - struct _cpstate cpstate; - unsigned char retcode[6]; - unsigned int reserved[4]; /* Reserved area for chaining */ - unsigned int window[4]; /* Window of 4 registers for initial context */ -}; + int err = 0; -extern void release_all_cp (struct task_struct *); +#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) + COPY(pc); + COPY(ps); + COPY(lbeg); + COPY(lend); + COPY(lcount); + COPY(sar); +#undef COPY + err |= flush_window_regs_user(regs); + err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); -// FIXME restore_cpextra -static inline int -restore_cpextra (struct _cpstate *buf) -{ -#if 0 - /* The signal handler may have used coprocessors in which - * case they are still enabled. We disable them to force a - * reloading of the original task's CP state by the lazy - * context-switching mechanisms of CP exception handling. - * Also, we essentially discard any coprocessor state that the - * signal handler created. */ + // err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4) - struct task_struct *tsk = current; - release_all_cp(tsk); - return __copy_from_user(tsk->thread.cpextra, buf, XTENSA_CP_EXTRA_SIZE); +#if XCHAL_HAVE_CP +# error Coprocessors unsupported + err |= save_cpextra(cpstate); + err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); #endif - return 0; -} - -/* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately... - */ + /* non-iBCS2 extensions.. */ + err |= __put_user(mask, &sc->oldmask); + return err; +} static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { - struct thread_struct *thread; unsigned int err = 0; unsigned long ps; - struct _cpstate *buf; #define COPY(x) err |= __get_user(regs->x, &sc->sc_##x) COPY(pc); - COPY(depc); - COPY(wmask); COPY(lbeg); COPY(lend); COPY(lcount); COPY(sar); - COPY(windowbase); - COPY(windowstart); #undef COPY + /* All registers were flushed to stack. Start with a prestine frame. */ + + regs->wmask = 1; + regs->windowbase = 0; + regs->windowstart = 1; + /* For PS, restore only PS.CALLINC. * Assume that all other bits are either the same as for the signal * handler, or the user mode value doesn't matter (e.g. PS.OWB). */ err |= __get_user(ps, &sc->sc_ps); - regs->ps = (regs->ps & ~PS_CALLINC_MASK) - | (ps & PS_CALLINC_MASK); + regs->ps = (regs->ps & ~PS_CALLINC_MASK) | (ps & PS_CALLINC_MASK); /* Additional corruption checks */ - if ((regs->windowbase >= (XCHAL_NUM_AREGS/4)) - || ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) ) - err = 1; if ((regs->lcount > 0) - && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) + && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) ) err = 1; - /* Restore extended register state. - * See struct thread_struct in processor.h. - */ - thread = ¤t->thread; - - err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4); - err |= __get_user(buf, &sc->sc_cpstate); - if (buf) { - if (!access_ok(VERIFY_READ, buf, sizeof(*buf))) - goto badframe; - err |= restore_cpextra(buf); - } - - regs->syscall = -1; /* disable syscall checks */ - return err; - -badframe: - return 1; -} - -static inline void -flush_my_cpstate(struct task_struct *tsk) -{ - unsigned long flags; - local_irq_save(flags); - -#if 0 // FIXME - for (i = 0; i < XCHAL_CP_NUM; i++) { - if (tsk == coproc_owners[i]) { - xthal_validate_cp(i); - xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i); + err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); - /* Invalidate and "disown" the cp to allow - * callers the chance to reset cp state in the - * task_struct. */ +#if XCHAL_HAVE_CP +# error Coprocessors unsupported + /* The signal handler may have used coprocessors in which + * case they are still enabled. We disable them to force a + * reloading of the original task's CP state by the lazy + * context-switching mechanisms of CP exception handling. + * Also, we essentially discard any coprocessor state that the + * signal handler created. */ - xthal_invalidate_cp(i); - coproc_owners[i] = 0; - } + if (!err) { + struct task_struct *tsk = current; + release_all_cp(tsk); + err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate, + XTENSA_CP_EXTRA_SIZE); } #endif - local_irq_restore(flags); -} - -/* Return codes: - 0: nothing saved - 1: stuff to save, successful - -1: stuff to save, error happened -*/ -static int -save_cpextra (struct _cpstate *buf) -{ -#if XCHAL_CP_NUM == 0 - return 0; -#else - - /* FIXME: If a task has never used a coprocessor, there is - * no need to save and restore anything. Tracking this - * information would allow us to optimize this section. - * Perhaps we can use current->used_math or (current->flags & - * PF_USEDFPU) or define a new field in the thread - * structure. */ - - /* We flush any live, task-owned cp state to the task_struct, - * then copy it all to the sigframe. Then we clear all - * cp/extra state in the task_struct, effectively - * clearing/resetting all cp/extra state for the signal - * handler (cp-exception handling will load these new values - * into the cp/extra registers.) This step is important for - * things like a floating-point cp, where the OS must reset - * the FCR to the default rounding mode. */ - - int err = 0; - struct task_struct *tsk = current; - - flush_my_cpstate(tsk); - /* Note that we just copy everything: 'extra' and 'cp' state together.*/ - err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE); - memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE); - -#if (XTENSA_CP_EXTRA_SIZE == 0) -#error Sanity check on memset above, cpextra_size should not be zero. -#endif - - return err ? -1 : 1; -#endif -} - -static int -setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate, - struct pt_regs *regs, unsigned long mask) -{ - struct thread_struct *thread; - int err = 0; - -//printk("setup_sigcontext\n"); -#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) - COPY(pc); - COPY(ps); - COPY(depc); - COPY(wmask); - COPY(lbeg); - COPY(lend); - COPY(lcount); - COPY(sar); - COPY(windowbase); - COPY(windowstart); -#undef COPY - - /* Save extended register state. - * See struct thread_struct in processor.h. - */ - thread = ¤t->thread; - err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4); - err |= save_cpextra(cpstate); - err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); - /* non-iBCS2 extensions.. */ - err |= __put_user(mask, &sc->oldmask); + regs->syscall = -1; /* disable syscall checks */ return err; } -asmlinkage int xtensa_sigreturn(struct pt_regs *regs) -{ - struct sigframe *frame = (struct sigframe *)regs->areg[1]; - sigset_t set; - if (regs->depc > 64) - panic ("Double exception sys_sigreturn\n"); - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - - if (__get_user(set.sig[0], &frame->sc.oldmask) - || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, - sizeof(frame->extramask)))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - if (restore_sigcontext(regs, &frame->sc)) - goto badframe; - return regs->areg[2]; -badframe: - force_sig(SIGSEGV, current); - return 0; -} +/* + * Do a signal return; undo the signal stack. + */ -asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs) +asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, + long a4, long a5, struct pt_regs *regs) { - struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1]; + struct rt_sigframe __user *frame; sigset_t set; - stack_t st; int ret; + if (regs->depc > 64) - { - printk("!!!!!!! DEPC !!!!!!!\n"); - return 0; - } + panic("rt_sigreturn in double exception!\n"); + + frame = (struct rt_sigframe __user *) regs->areg[1]; if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -407,13 +249,11 @@ asmlinkage int xtensa_rt_sigreturn(struct pt_regs *regs) if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; + ret = regs->areg[2]; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->areg[1]) == -EFAULT) goto badframe; - /* It is more difficult to avoid calling this function than to - call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->areg[1]); return ret; @@ -422,77 +262,50 @@ badframe: return 0; } -/* - * Set up a signal frame. - */ + /* - * Determine which stack to use.. + * Set up a signal frame. */ -static inline void * -get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) -{ - if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp)) - sp = current->sas_ss_sp + current->sas_ss_size; - - return (void *)((sp - frame_size) & -16ul); -} - -#define USE_SIGRETURN 0 -#define USE_RT_SIGRETURN 1 static int -gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) +gen_return_code(unsigned char *codemem) { - unsigned int retcall; int err = 0; -#if 0 - /* Ignoring SA_RESTORER for now; it's supposed to be obsolete, - * and the xtensa glibc doesn't use it. + /* + * The 12-bit immediate is really split up within the 24-bit MOVI + * instruction. As long as the above system call numbers fit within + * 8-bits, the following code works fine. See the Xtensa ISA for + * details. */ - if (ka->sa.sa_flags & SA_RESTORER) { - regs->pr = (unsigned long) ka->sa.sa_restorer; - } else -#endif /* 0 */ - { - -#if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255) - -/* The 12-bit immediate is really split up within the 24-bit MOVI - * instruction. As long as the above system call numbers fit within - * 8-bits, the following code works fine. See the Xtensa ISA for - * details. - */ -#error Generating the MOVI instruction below breaks! +#if __NR_rt_sigreturn > 255 +# error Generating the MOVI instruction below breaks! #endif - retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn; - #ifdef __XTENSA_EB__ /* Big Endian version */ - /* Generate instruction: MOVI a2, retcall */ - err |= __put_user(0x22, &codemem[0]); - err |= __put_user(0x0a, &codemem[1]); - err |= __put_user(retcall, &codemem[2]); - /* Generate instruction: SYSCALL */ - err |= __put_user(0x00, &codemem[3]); - err |= __put_user(0x05, &codemem[4]); - err |= __put_user(0x00, &codemem[5]); + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0x0a, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x05, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); #elif defined __XTENSA_EL__ /* Little Endian version */ - /* Generate instruction: MOVI a2, retcall */ - err |= __put_user(0x22, &codemem[0]); - err |= __put_user(0xa0, &codemem[1]); - err |= __put_user(retcall, &codemem[2]); - /* Generate instruction: SYSCALL */ - err |= __put_user(0x00, &codemem[3]); - err |= __put_user(0x50, &codemem[4]); - err |= __put_user(0x00, &codemem[5]); + /* Generate instruction: MOVI a2, __NR_rt_sigreturn */ + err |= __put_user(0x22, &codemem[0]); + err |= __put_user(0xa0, &codemem[1]); + err |= __put_user(__NR_rt_sigreturn, &codemem[2]); + /* Generate instruction: SYSCALL */ + err |= __put_user(0x00, &codemem[3]); + err |= __put_user(0x50, &codemem[4]); + err |= __put_user(0x00, &codemem[5]); #else -#error Must use compiler for Xtensa processors. +# error Must use compiler for Xtensa processors. #endif - } /* Flush generated code out of the data cache */ @@ -504,97 +317,29 @@ gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn) return err; } -static void -set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr, - void *handler, unsigned long arg1, void *arg2, void *arg3) -{ - /* Set up registers for signal handler */ - start_thread(regs, (unsigned long) handler, (unsigned long) stack); - - /* Set up a stack frame for a call4 - * Note: PS.CALLINC is set to one by start_thread - */ - regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000; - regs->areg[6] = arg1; - regs->areg[7] = (unsigned long) arg2; - regs->areg[8] = (unsigned long) arg3; -} -static void setup_frame(int sig, struct k_sigaction *ka, +static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs) { - struct sigframe *frame; + struct rt_sigframe *frame; int err = 0; int signal; + unsigned long sp, ra; - frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); - if (regs->depc > 64) - { - printk("!!!!!!! DEPC !!!!!!!\n"); - return; - } - - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto give_sigsegv; - - signal = current_thread_info()->exec_domain - && current_thread_info()->exec_domain->signal_invmap - && sig < 32 - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig; - - err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]); + sp = regs->areg[1]; - if (_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) { + sp = current->sas_ss_sp + current->sas_ss_size; } - /* Create sys_sigreturn syscall in stack frame */ - err |= gen_return_code(frame->retcode, USE_SIGRETURN); - - if (err) - goto give_sigsegv; - - /* Create signal handler execution context. - * Return context not modified until this point. - */ - set_thread_state(regs, frame, frame->retcode, - ka->sa.sa_handler, signal, &frame->sc, NULL); - - /* Set access mode to USER_DS. Nomenclature is outdated, but - * functionality is used in uaccess.h - */ - set_fs(USER_DS); - - -#if DEBUG_SIG - printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n", - current->comm, current->pid, signal, frame, regs->pc); -#endif - - return; - -give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); -} - -static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - struct rt_sigframe *frame; - int err = 0; - int signal; + frame = (void *)((sp - sizeof(*frame)) & -16ul); - frame = get_sigframe(ka, regs->areg[1], sizeof(*frame)); if (regs->depc > 64) panic ("Double exception sys_sigreturn\n"); - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) { goto give_sigsegv; + } signal = current_thread_info()->exec_domain && current_thread_info()->exec_domain->signal_invmap @@ -602,9 +347,12 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, ? current_thread_info()->exec_domain->signal_invmap[sig] : sig; - err |= copy_siginfo_to_user(&frame->info, info); + if (ka->sa.sa_flags & SA_SIGINFO) { + err |= copy_siginfo_to_user(&frame->info, info); + } + + /* Create the user context. */ - /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, @@ -617,16 +365,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Create sys_rt_sigreturn syscall in stack frame */ - err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN); - if (err) + err |= gen_return_code(frame->retcode); + + if (err) { goto give_sigsegv; + } + - /* Create signal handler execution context. + /* + * Create signal handler execution context. * Return context not modified until this point. */ - set_thread_state(regs, frame, frame->retcode, - ka->sa.sa_handler, signal, &frame->info, &frame->uc); + + /* Set up registers for signal handler */ + start_thread(regs, (unsigned long) ka->sa.sa_handler, + (unsigned long) frame); + + /* Set up a stack frame for a call4 + * Note: PS.CALLINC is set to one by start_thread + */ + ra = (unsigned long) frame->retcode; + regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000; + regs->areg[6] = (unsigned long) signal; + regs->areg[7] = (unsigned long) &frame->info; + regs->areg[8] = (unsigned long) &frame->uc; /* Set access mode to USER_DS. Nomenclature is outdated, but * functionality is used in uaccess.h @@ -646,6 +409,48 @@ give_sigsegv: force_sig(SIGSEGV, current); } +/* + * Atomically swap in the new signal mask, and wait for a signal. + */ + +asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset, + size_t sigsetsize, + long a2, long a3, long a4, long a5, + struct pt_regs *regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + + sigdelsetmask(&newset, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + regs->areg[2] = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(regs, &saveset)) + return -EINTR; + } +} + +asmlinkage long xtensa_sigaltstack(const stack_t __user *uss, + stack_t __user *uoss, + long a2, long a3, long a4, long a5, + struct pt_regs *regs) +{ + return do_sigaltstack(uss, uoss, regs->areg[1]); +} + /* @@ -663,51 +468,89 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) int signr; struct k_sigaction ka; + if (!user_mode(regs)) + return 0; + + if (try_to_freeze()) + goto no_signal; + if (!oldset) oldset = ¤t->blocked; + task_pt_regs(current)->icountlevel = 0; + signr = get_signal_to_deliver(&info, &ka, regs, NULL); - /* Are we from a system call? */ - if (regs->syscall >= 0) { - /* If so, check system call restarting.. */ - switch (regs->areg[2]) { - case ERESTARTNOHAND: - case ERESTART_RESTARTBLOCK: - regs->areg[2] = -EINTR; - break; + if (signr > 0) { + + /* Are we from a system call? */ + + if ((signed)regs->syscall >= 0) { - case ERESTARTSYS: - if (!(ka.sa.sa_flags & SA_RESTART)) { + /* If so, check system call restarting.. */ + + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: regs->areg[2] = -EINTR; break; - } - /* fallthrough */ - case ERESTARTNOINTR: - regs->areg[2] = regs->syscall; - regs->pc -= 3; + + case -ERESTARTSYS: + if (!(ka.sa.sa_flags & SA_RESTART)) { + regs->areg[2] = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + + default: + /* nothing to do */ + if (regs->areg[2] != 0) + break; + } } - } - if (signr == 0) - return 0; /* no signals delivered */ + /* Whee! Actually deliver the signal. */ + /* Set up the stack frame */ + setup_frame(signr, &ka, &info, oldset, regs); - /* Whee! Actually deliver the signal. */ + if (ka.sa.sa_flags & SA_ONESHOT) + ka.sa.sa_handler = SIG_DFL; - /* Set up the stack frame */ - if (ka.sa.sa_flags & SA_SIGINFO) - setup_rt_frame(signr, &ka, &info, oldset, regs); - else - setup_frame(signr, &ka, oldset, regs); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); + if (!(ka.sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, signr); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; - if (ka.sa.sa_flags & SA_ONESHOT) - ka.sa.sa_handler = SIG_DFL; + return 1; + } - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka.sa.sa_mask); - if (!(ka.sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, signr); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - return 1; +no_signal: + /* Did we come from a system call? */ + if ((signed) regs->syscall >= 0) { + /* Restart the system call - no handlers present */ + switch (regs->areg[2]) { + case -ERESTARTNOHAND: + case -ERESTARTSYS: + case -ERESTARTNOINTR: + regs->areg[2] = regs->syscall; + regs->pc -= 3; + break; + case -ERESTART_RESTARTBLOCK: + regs->areg[2] = __NR_restart_syscall; + regs->pc -= 3; + break; + } + } + if (current->ptrace & PT_SINGLESTEP) + task_pt_regs(current)->icountlevel = 1; + return 0; } + diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S index 4b7b4ff7997..b0582c3c5f8 100644 --- a/arch/xtensa/kernel/vmlinux.lds.S +++ b/arch/xtensa/kernel/vmlinux.lds.S @@ -84,9 +84,7 @@ SECTIONS { /* The .head.text section must be the first section! */ *(.head.text) - *(.literal) - TEXT_TEXT - *(.srom.text) + *(.literal .text) VMLINUX_SYMBOL(__sched_text_start) = .; *(.sched.literal .sched.text) VMLINUX_SYMBOL(__sched_text_end) = .; @@ -96,6 +94,7 @@ SECTIONS } _etext = .; + PROVIDE (etext = .); . = ALIGN(16); @@ -103,32 +102,6 @@ SECTIONS /* Relocation table */ - . = ALIGN(16); - __boot_reloc_table_start = ABSOLUTE(.); - - __relocate : { - - RELOCATE_ENTRY(_WindowVectors_text, - .WindowVectors.text); -#if 0 - RELOCATE_ENTRY(_KernelExceptionVector_literal, - .KernelExceptionVector.literal); -#endif - RELOCATE_ENTRY(_KernelExceptionVector_text, - .KernelExceptionVector.text); -#if 0 - RELOCATE_ENTRY(_UserExceptionVector_literal, - .UserExceptionVector.literal); -#endif - RELOCATE_ENTRY(_UserExceptionVector_text, - .UserExceptionVector.text); - RELOCATE_ENTRY(_DoubleExceptionVector_literal, - .DoubleExceptionVector.literal); - RELOCATE_ENTRY(_DoubleExceptionVector_text, - .DoubleExceptionVector.text); - } - __boot_reloc_table_end = ABSOLUTE(.) ; - .fixup : { *(.fixup) } . = ALIGN(16); @@ -145,8 +118,7 @@ SECTIONS _fdata = .; .data : { - DATA_DATA - CONSTRUCTORS + *(.data) CONSTRUCTORS . = ALIGN(XCHAL_ICACHE_LINESIZE); *(.data.cacheline_aligned) } @@ -174,6 +146,22 @@ SECTIONS __tagtable_begin = .; *(.taglist) __tagtable_end = .; + + . = ALIGN(16); + __boot_reloc_table_start = ABSOLUTE(.); + + RELOCATE_ENTRY(_WindowVectors_text, + .WindowVectors.text); + RELOCATE_ENTRY(_KernelExceptionVector_text, + .KernelExceptionVector.text); + RELOCATE_ENTRY(_UserExceptionVector_text, + .UserExceptionVector.text); + RELOCATE_ENTRY(_DoubleExceptionVector_literal, + .DoubleExceptionVector.literal); + RELOCATE_ENTRY(_DoubleExceptionVector_text, + .DoubleExceptionVector.text); + + __boot_reloc_table_end = ABSOLUTE(.) ; } . = ALIGN(XCHAL_ICACHE_LINESIZE); @@ -194,16 +182,6 @@ SECTIONS SECURITY_INIT - . = ALIGN(4); - - __start___ftr_fixup = .; - __ftr_fixup : { *(__ftr_fixup) } - __stop___ftr_fixup = .; - - . = ALIGN(4096); - __per_cpu_start = .; - .data.percpu : { *(.data.percpu) } - __per_cpu_end = .; #ifdef CONFIG_BLK_DEV_INITRD . = ALIGN(4096); @@ -212,6 +190,12 @@ SECTIONS __initramfs_end = .; #endif + . = ALIGN(4096); + __per_cpu_start = .; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = .; + + /* We need this dummy segment here */ . = ALIGN(4); @@ -273,9 +257,9 @@ SECTIONS /* BSS section */ _bss_start = .; - .sbss : { *(.sbss) *(.scommon) } - .bss : { *(COMMON) *(.bss) } + .bss : { *(.bss.page_aligned) *(.bss) } _bss_end = .; + _end = .; /* only used by the boot loader */ @@ -293,16 +277,16 @@ SECTIONS *(.ResetVector.text) } - /* Sections to be discarded */ /DISCARD/ : { - *(.text.exit) - *(.text.exit.literal) - *(.data.exit) + *(.exit.literal .exit.text) + *(.exit.data) *(.exitcall.exit) } + .xt.lit : { *(.xt.lit) } + .xt.prop : { *(.xt.prop) } .debug 0 : { *(.debug) } .line 0 : { *(.line) } diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index cd7e6a02060..60dbdb43fb4 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -38,21 +38,10 @@ /* * String functions */ -EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); /* diff --git a/arch/xtensa/lib/strncpy_user.S b/arch/xtensa/lib/strncpy_user.S index a834057bda6..b2655d94558 100644 --- a/arch/xtensa/lib/strncpy_user.S +++ b/arch/xtensa/lib/strncpy_user.S @@ -25,18 +25,18 @@ /* * char *__strncpy_user(char *dst, const char *src, size_t len) */ -.text -.begin literal -.align 4 -.Lmask0: - .byte 0xff, 0x00, 0x00, 0x00 -.Lmask1: - .byte 0x00, 0xff, 0x00, 0x00 -.Lmask2: - .byte 0x00, 0x00, 0xff, 0x00 -.Lmask3: - .byte 0x00, 0x00, 0x00, 0xff -.end literal + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif # Register use # a0/ return address @@ -53,6 +53,7 @@ # a11/ dst # a12/ tmp +.text .align 4 .global __strncpy_user .type __strncpy_user,@function @@ -61,10 +62,10 @@ __strncpy_user: # a2/ dst, a3/ src, a4/ len mov a11, a2 # leave dst in return value register beqz a4, .Lret # if len is zero - l32r a5, .Lmask0 # mask for byte 0 - l32r a6, .Lmask1 # mask for byte 1 - l32r a7, .Lmask2 # mask for byte 2 - l32r a8, .Lmask3 # mask for byte 3 + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned .Lsrcaligned: # return here when src is word-aligned diff --git a/arch/xtensa/lib/strnlen_user.S b/arch/xtensa/lib/strnlen_user.S index 5e9c1e709b2..ad3f616322c 100644 --- a/arch/xtensa/lib/strnlen_user.S +++ b/arch/xtensa/lib/strnlen_user.S @@ -24,18 +24,18 @@ /* * size_t __strnlen_user(const char *s, size_t len) */ -.text -.begin literal -.align 4 -.Lmask0: - .byte 0xff, 0x00, 0x00, 0x00 -.Lmask1: - .byte 0x00, 0xff, 0x00, 0x00 -.Lmask2: - .byte 0x00, 0x00, 0xff, 0x00 -.Lmask3: - .byte 0x00, 0x00, 0x00, 0xff -.end literal + +#ifdef __XTENSA_EB__ +# define MASK0 0xff000000 +# define MASK1 0x00ff0000 +# define MASK2 0x0000ff00 +# define MASK3 0x000000ff +#else +# define MASK0 0x000000ff +# define MASK1 0x0000ff00 +# define MASK2 0x00ff0000 +# define MASK3 0xff000000 +#endif # Register use: # a2/ src @@ -48,6 +48,7 @@ # a9/ tmp # a10/ tmp +.text .align 4 .global __strnlen_user .type __strnlen_user,@function @@ -56,10 +57,10 @@ __strnlen_user: # a2/ s, a3/ len addi a4, a2, -4 # because we overincrement at the end; # we compensate with load offsets of 4 - l32r a5, .Lmask0 # mask for byte 0 - l32r a6, .Lmask1 # mask for byte 1 - l32r a7, .Lmask2 # mask for byte 2 - l32r a8, .Lmask3 # mask for byte 3 + movi a5, MASK0 # mask for byte 0 + movi a6, MASK1 # mask for byte 1 + movi a7, MASK2 # mask for byte 2 + movi a8, MASK3 # mask for byte 3 bbsi.l a2, 0, .L1mod2 # if only 8-bit aligned bbsi.l a2, 1, .L2mod4 # if only 16-bit aligned diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index e1ec2d1e818..8415c76f11c 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c @@ -205,7 +205,7 @@ void __init init_mmu (void) /* Writing zeros to the <t>TLBCFG special registers ensure * that valid values exist in the register. For existing * PGSZID<w> fields, zero selects the first element of the - * page-size array. For nonexistant PGSZID<w> fields, zero is + * page-size array. For nonexistent PGSZID<w> fields, zero is * the best value to write. Also, when changing PGSZID<w> * fields, the corresponding TLB must be flushed. */ diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c index 4bfe333be22..f09962fa98c 100644 --- a/arch/xtensa/platform-iss/network.c +++ b/arch/xtensa/platform-iss/network.c @@ -473,7 +473,7 @@ static int iss_net_open(struct net_device *dev) netif_start_queue(dev); /* clear buffer - it can happen that the host side of the interface - * is full when we gethere. In this case, new data is never queued, + * is full when we get here. In this case, new data is never queued, * SIGIOs never arrive, and the net never works. */ while ((err = iss_net_rx(dev)) > 0) |