Notice: the grml team is migrating from Mercurial to Git.
Please visit git.grml.org instead!
| author | Michael Prokop <mika@grml.org> |
| Thu May 03 19:05:17 2007 +0200 (19 months ago) | |
| changeset 32 | 6d0a9e113229 |
| manifest | 6d0a9e113229 |
| parent 31 | d678459cafde |
| child 33 | 994e41ee3a3f |
--- a/config/config-2.6.20-grml Sun Apr 22 15:48:09 2007 +0200+++ b/config/config-2.6.20-grml Thu May 03 19:05:17 2007 +0200@@ -1,7 +1,7 @@## Automatically generated make config: don't edit# Linux kernel version: 2.6.20-grml-# Sat Apr 7 00:01:41 2007+# Sun Apr 22 13:06:31 2007#CONFIG_X86_32=yCONFIG_GENERIC_TIME=y@@ -3806,7 +3806,6 @@ CONFIG_DEBUG_MUTEXES=y# CONFIG_PROVE_LOCKING is not set# CONFIG_DEBUG_SPINLOCK_SLEEP is not set# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set-CONFIG_STACKTRACE=y# CONFIG_DEBUG_KOBJECT is not set# CONFIG_DEBUG_HIGHMEM is not setCONFIG_DEBUG_BUGVERBOSE=y@@ -3817,9 +3816,6 @@ CONFIG_FORCED_INLINING=yCONFIG_FORCED_INLINING=yCONFIG_RCU_TORTURE_TEST=m# CONFIG_FAULT_INJECTION is not set-# CONFIG_FAILSLAB is not set-# CONFIG_FAIL_PAGE_ALLOC is not set-# CONFIG_FAIL_MAKE_REQUEST is not setCONFIG_EARLY_PRINTK=y# CONFIG_DEBUG_STACKOVERFLOW is not set# CONFIG_DEBUG_STACK_USAGE is not set
--- /dev/null Thu Jan 01 00:00:00 1970 +0000+++ b/2.6.20/x86/1000_2.6.20.11.patch Thu May 03 19:05:17 2007 +0200@@ -0,0 +1,11911 @@+diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt+index a0f6842..713c283 100644+--- a/Documentation/networking/ip-sysctl.txt++++ b/Documentation/networking/ip-sysctl.txt+@@ -825,6 +825,15 @@ accept_redirects - BOOLEAN+ Functional default: enabled if local forwarding is disabled.+ disabled if local forwarding is enabled.+++accept_source_route - INTEGER++ Accept source routing (routing extension header).++++ > 0: Accept routing header.++ = 0: Accept only routing header type 2.++ < 0: Do not accept routing header.++++ Default: 0+++ autoconf - BOOLEAN+ Autoconfigure addresses using Prefix Information in Router+ Advertisements.+diff --git a/Makefile b/Makefile+index 7e2750f..f585e79 100644+--- a/Makefile++++ b/Makefile+@@ -1,7 +1,7 @@+ VERSION = 2+ PATCHLEVEL = 6+ SUBLEVEL = 20+-EXTRAVERSION =++EXTRAVERSION = .11+ NAME = Homicidal Dwarf Hamster++ # *DOCUMENTATION*+diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S+index 2c5b5cc..8143c95 100644+--- a/arch/i386/boot/video.S++++ b/arch/i386/boot/video.S+@@ -571,6 +571,16 @@ setr1: lodsw+ jmp _m_s++ check_vesa:++#ifdef CONFIG_FIRMWARE_EDID++ leaw modelist+1024, %di++ movw $0x4f00, %ax++ int $0x10++ cmpw $0x004f, %ax++ jnz setbad++++ movw 4(%di), %ax++ movw %ax, vbe_version++#endif+ leaw modelist+1024, %di+ subb $VIDEO_FIRST_VESA>>8, %bh+ movw %bx, %cx # Get mode information structure+@@ -1945,6 +1955,9 @@ store_edid:+ rep+ stosl+++ cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0++ jl no_edid+++ pushw %es # save ES+ xorw %di, %di # Report Capability+ pushw %di+@@ -1987,6 +2000,7 @@ do_restore: .byte 0 # Screen contents altered during mode change+ svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes+ graphic_mode: .byte 0 # Graphic mode with a linear frame buffer+ dac_size: .byte 6 # DAC bit depth++vbe_version: .word 0 # VBE bios version++ # Status messages+ keymsg: .ascii "Press <RETURN> to see video modes available, "+diff --git a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c+index 5ae1705..590d99e 100644+--- a/arch/i386/kernel/cpu/mtrr/if.c++++ b/arch/i386/kernel/cpu/mtrr/if.c+@@ -158,8 +158,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)+ struct mtrr_sentry sentry;+ struct mtrr_gentry gentry;+ void __user *arg = (void __user *) __arg;++ unsigned int compat_cmd = cmd;++- switch (cmd) {++ switch (compat_cmd) {+ case MTRRIOC_ADD_ENTRY:+ case MTRRIOC_SET_ENTRY:+ case MTRRIOC_DEL_ENTRY:+@@ -177,14 +178,20 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)+ return -EFAULT;+ break;+ #ifdef CONFIG_COMPAT+- case MTRRIOC32_ADD_ENTRY:+- case MTRRIOC32_SET_ENTRY:+- case MTRRIOC32_DEL_ENTRY:+- case MTRRIOC32_KILL_ENTRY:+- case MTRRIOC32_ADD_PAGE_ENTRY:+- case MTRRIOC32_SET_PAGE_ENTRY:+- case MTRRIOC32_DEL_PAGE_ENTRY:+- case MTRRIOC32_KILL_PAGE_ENTRY: {++#define MTRR_COMPAT_OP(op, type)\++ case MTRRIOC32_##op: \++ cmd = MTRRIOC_##op; \++ goto compat_get_##type++++ MTRR_COMPAT_OP(ADD_ENTRY, sentry);++ MTRR_COMPAT_OP(SET_ENTRY, sentry);++ MTRR_COMPAT_OP(DEL_ENTRY, sentry);++ MTRR_COMPAT_OP(KILL_ENTRY, sentry);++ MTRR_COMPAT_OP(ADD_PAGE_ENTRY, sentry);++ MTRR_COMPAT_OP(SET_PAGE_ENTRY, sentry);++ MTRR_COMPAT_OP(DEL_PAGE_ENTRY, sentry);++ MTRR_COMPAT_OP(KILL_PAGE_ENTRY, sentry);++compat_get_sentry: {+ struct mtrr_sentry32 __user *s32 = (struct mtrr_sentry32 __user *)__arg;+ err = get_user(sentry.base, &s32->base);+ err |= get_user(sentry.size, &s32->size);+@@ -193,8 +200,9 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)+ return err;+ break;+ }+- case MTRRIOC32_GET_ENTRY:+- case MTRRIOC32_GET_PAGE_ENTRY: {++ MTRR_COMPAT_OP(GET_ENTRY, gentry);++ MTRR_COMPAT_OP(GET_PAGE_ENTRY, gentry);++compat_get_gentry: {+ struct mtrr_gentry32 __user *g32 = (struct mtrr_gentry32 __user *)__arg;+ err = get_user(gentry.regnum, &g32->regnum);+ err |= get_user(gentry.base, &g32->base);+@@ -204,6 +212,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)+ return err;+ break;+ }++#undef MTRR_COMPAT_OP+ #endif+ }++@@ -287,7 +296,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg)+ if (err)+ return err;++- switch(cmd) {++ switch(compat_cmd) {+ case MTRRIOC_GET_ENTRY:+ case MTRRIOC_GET_PAGE_ENTRY:+ if (copy_to_user(arg, &gentry, sizeof gentry))+diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c+index 65d7620..f654505 100644+--- a/arch/i386/kernel/signal.c++++ b/arch/i386/kernel/signal.c+@@ -21,6 +21,7 @@+ #include <linux/suspend.h>+ #include <linux/ptrace.h>+ #include <linux/elf.h>++#include <linux/binfmts.h>+ #include <asm/processor.h>+ #include <asm/ucontext.h>+ #include <asm/uaccess.h>+@@ -349,7 +350,10 @@ static int setup_frame(int sig, struct k_sigaction *ka,+ goto give_sigsegv;+ }++- restorer = (void *)VDSO_SYM(&__kernel_sigreturn);++ if (current->binfmt->hasvdso)++ restorer = (void *)VDSO_SYM(&__kernel_sigreturn);++ else++ restorer = (void *)&frame->retcode;+ if (ka->sa.sa_flags & SA_RESTORER)+ restorer = ka->sa.sa_restorer;++diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c+index 5da7442..666f70d 100644+--- a/arch/i386/kernel/sysenter.c++++ b/arch/i386/kernel/sysenter.c+@@ -77,7 +77,7 @@ int __init sysenter_setup(void)+ syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);++ #ifdef CONFIG_COMPAT_VDSO+- __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);++ __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY_EXEC);+ printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));+ #endif++diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c+index d22cfc9..086b372 100644+--- a/arch/i386/lib/usercopy.c++++ b/arch/i386/lib/usercopy.c+@@ -10,6 +10,7 @@+ #include <linux/blkdev.h>+ #include <linux/module.h>+ #include <linux/backing-dev.h>++#include <linux/interrupt.h>+ #include <asm/uaccess.h>+ #include <asm/mmx.h>++@@ -719,6 +720,14 @@ unsigned long __copy_to_user_ll(void __user *to, const void *from,+ #ifndef CONFIG_X86_WP_WORKS_OK+ if (unlikely(boot_cpu_data.wp_works_ok == 0) &&+ ((unsigned long )to) < TASK_SIZE) {++ /*++ * When we are in an atomic section (see++ * mm/filemap.c:file_read_actor), return the full++ * length to take the slow path.++ */++ if (in_atomic())++ return n;+++ /*+ * CPU does not honor the WP bit when writing+ * from supervisory mode, and due to preemption or SMP,+diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig+index fcacfe2..c085199 100644+--- a/arch/ia64/Kconfig++++ b/arch/ia64/Kconfig+@@ -11,6 +11,7 @@ menu "Processor type and features"++ config IA64+ bool++ select ATA_NONSTANDARD if ATA+ default y+ help+ The Itanium Processor Family is Intel's 64-bit successor to+diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c+index bc2f64d..2018e62 100644+--- a/arch/ia64/kernel/crash.c++++ b/arch/ia64/kernel/crash.c+@@ -79,6 +79,7 @@ crash_save_this_cpu()+ final_note(buf);+ }+++#ifdef CONFIG_SMP+ static int+ kdump_wait_cpu_freeze(void)+ {+@@ -91,6 +92,7 @@ kdump_wait_cpu_freeze(void)+ }+ return 1;+ }++#endif++ void+ machine_crash_shutdown(struct pt_regs *pt)+@@ -132,11 +134,12 @@ kdump_cpu_freeze(struct unw_frame_info *info, void *arg)+ atomic_inc(&kdump_cpu_freezed);+ kdump_status[cpuid] = 1;+ mb();+- if (cpuid == 0) {+- for (;;)+- cpu_relax();+- } else++#ifdef CONFIG_HOTPLUG_CPU++ if (cpuid != 0)+ ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);++#endif++ for (;;)++ cpu_relax();+ }++ static int+diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c+index 0fc5fb7..02479e1 100644+--- a/arch/ia64/kernel/iosapic.c++++ b/arch/ia64/kernel/iosapic.c+@@ -446,7 +446,7 @@ iosapic_end_level_irq (unsigned int irq)+ #define iosapic_disable_level_irq mask_irq+ #define iosapic_ack_level_irq nop++-struct hw_interrupt_type irq_type_iosapic_level = {++struct irq_chip irq_type_iosapic_level = {+ .name = "IO-SAPIC-level",+ .startup = iosapic_startup_level_irq,+ .shutdown = iosapic_shutdown_level_irq,+@@ -454,6 +454,8 @@ struct hw_interrupt_type irq_type_iosapic_level = {+ .disable = iosapic_disable_level_irq,+ .ack = iosapic_ack_level_irq,+ .end = iosapic_end_level_irq,++ .mask = mask_irq,++ .unmask = unmask_irq,+ .set_affinity = iosapic_set_affinity+ };++@@ -493,7 +495,7 @@ iosapic_ack_edge_irq (unsigned int irq)+ #define iosapic_disable_edge_irq nop+ #define iosapic_end_edge_irq nop++-struct hw_interrupt_type irq_type_iosapic_edge = {++struct irq_chip irq_type_iosapic_edge = {+ .name = "IO-SAPIC-edge",+ .startup = iosapic_startup_edge_irq,+ .shutdown = iosapic_disable_edge_irq,+@@ -501,6 +503,8 @@ struct hw_interrupt_type irq_type_iosapic_edge = {+ .disable = iosapic_disable_edge_irq,+ .ack = iosapic_ack_edge_irq,+ .end = iosapic_end_edge_irq,++ .mask = mask_irq,++ .unmask = unmask_irq,+ .set_affinity = iosapic_set_affinity+ };++diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c+index e2ccc9f..7141795 100644+--- a/arch/ia64/kernel/machine_kexec.c++++ b/arch/ia64/kernel/machine_kexec.c+@@ -70,12 +70,14 @@ void machine_kexec_cleanup(struct kimage *image)++ void machine_shutdown(void)+ {++#ifdef CONFIG_HOTPLUG_CPU+ int cpu;++ for_each_online_cpu(cpu) {+ if (cpu != smp_processor_id())+ cpu_down(cpu);+ }++#endif+ kexec_disable_iosapic();+ }++diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c+index 8c5bee0..8d2a1bf 100644+--- a/arch/ia64/sn/kernel/irq.c++++ b/arch/ia64/sn/kernel/irq.c+@@ -205,7 +205,17 @@ static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)+ (void)sn_retarget_vector(sn_irq_info, nasid, slice);+ }++-struct hw_interrupt_type irq_type_sn = {++static void++sn_mask_irq(unsigned int irq)++{++}++++static void++sn_unmask_irq(unsigned int irq)++{++}++++struct irq_chip irq_type_sn = {+ .name = "SN hub",+ .startup = sn_startup_irq,+ .shutdown = sn_shutdown_irq,+@@ -213,6 +223,8 @@ struct hw_interrupt_type irq_type_sn = {+ .disable = sn_disable_irq,+ .ack = sn_ack_irq,+ .end = sn_end_irq,++ .mask = sn_mask_irq,++ .unmask = sn_unmask_irq,+ .set_affinity = sn_set_affinity_irq+ };++diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c+index 44cbe0c..a689e29 100644+--- a/arch/m32r/kernel/process.c++++ b/arch/m32r/kernel/process.c+@@ -174,7 +174,7 @@ void show_regs(struct pt_regs * regs)+ regs->acc1h, regs->acc1l);+ #elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)+ printk("ACCH[%08lx]:ACCL[%08lx]\n", \+- regs->acch, regs->accl);++ regs->acc0h, regs->acc0l);+ #else+ #error unknown isa configuration+ #endif+diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c+index 092ea86..4b15605 100644+--- a/arch/m32r/kernel/signal.c++++ b/arch/m32r/kernel/signal.c+@@ -109,19 +109,10 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,+ COPY(r10);+ COPY(r11);+ COPY(r12);+-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)+ COPY(acc0h);+ COPY(acc0l);+- COPY(acc1h);+- COPY(acc1l);+-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)+- COPY(acch);+- COPY(accl);+- COPY(dummy_acc1h);+- COPY(dummy_acc1l);+-#else+-#error unknown isa configuration+-#endif++ COPY(acc1h); /* ISA_DSP_LEVEL2 only */++ COPY(acc1l); /* ISA_DSP_LEVEL2 only */+ COPY(psw);+ COPY(bpc);+ COPY(bbpsw);+@@ -196,19 +187,10 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,+ COPY(r10);+ COPY(r11);+ COPY(r12);+-#if defined(CONFIG_ISA_M32R2) && defined(CONFIG_ISA_DSP_LEVEL2)+ COPY(acc0h);+ COPY(acc0l);+- COPY(acc1h);+- COPY(acc1l);+-#elif defined(CONFIG_ISA_M32R2) || defined(CONFIG_ISA_M32R)+- COPY(acch);+- COPY(accl);+- COPY(dummy_acc1h);+- COPY(dummy_acc1l);+-#else+-#error unknown isa configuration+-#endif++ COPY(acc1h); /* ISA_DSP_LEVEL2 only */++ COPY(acc1l); /* ISA_DSP_LEVEL2 only */+ COPY(psw);+ COPY(bpc);+ COPY(bbpsw);+diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S+index 71b1fe5..97cedcd 100644+--- a/arch/powerpc/kernel/head_64.S++++ b/arch/powerpc/kernel/head_64.S+@@ -613,7 +613,7 @@ system_call_pSeries:+ /*** pSeries interrupt support ***/++ /* moved from 0xf00 */+- MASKABLE_EXCEPTION_PSERIES(., performance_monitor)++ STD_EXCEPTION_PSERIES(., performance_monitor)++ /*+ * An interrupt came in while soft-disabled; clear EE in SRR1,+diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c+index c8b65ca..6d9857c 100644+--- a/arch/ppc/kernel/ppc_ksyms.c++++ b/arch/ppc/kernel/ppc_ksyms.c+@@ -270,7 +270,7 @@ EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */+ extern long *intercept_table;+ EXPORT_SYMBOL(intercept_table);+ #endif /* CONFIG_PPC_STD_MMU */+-#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)++#ifdef CONFIG_PPC_DCR_NATIVE+ EXPORT_SYMBOL(__mtdcr);+ EXPORT_SYMBOL(__mfdcr);+ #endif+diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c+index dab6169..798b140 100644+--- a/arch/sparc/kernel/of_device.c++++ b/arch/sparc/kernel/of_device.c+@@ -495,7 +495,7 @@ static void __init build_device_resources(struct of_device *op,+ u32 *reg = (preg + (index * ((na + ns) * 4)));+ struct device_node *dp = op->node;+ struct device_node *pp = p_op->node;+- struct of_bus *pbus;++ struct of_bus *pbus, *dbus;+ u64 size, result = OF_BAD_ADDR;+ unsigned long flags;+ int dna, dns;+@@ -516,6 +516,7 @@ static void __init build_device_resources(struct of_device *op,++ dna = na;+ dns = ns;++ dbus = bus;++ while (1) {+ dp = pp;+@@ -528,13 +529,13 @@ static void __init build_device_resources(struct of_device *op,+ pbus = of_match_bus(pp);+ pbus->count_cells(dp, &pna, &pns);++- if (build_one_resource(dp, bus, pbus, addr,++ if (build_one_resource(dp, dbus, pbus, addr,+ dna, dns, pna))+ break;++ dna = pna;+ dns = pns;+- bus = pbus;++ dbus = pbus;+ }++ build_res:+diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S+index e492db8..d4024ac 100644+--- a/arch/sparc64/kernel/ktlb.S++++ b/arch/sparc64/kernel/ktlb.S+@@ -138,9 +138,15 @@ kvmap_dtlb_4v:+ brgez,pn %g4, kvmap_dtlb_nonlinear+ nop+++#ifdef CONFIG_DEBUG_PAGEALLOC++ /* Index through the base page size TSB even for linear++ * mappings when using page allocation debugging.++ */++ KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)++#else+ /* Correct TAG_TARGET is already in %g6, check 4mb TSB. */+ KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)+-++#endif+ /* TSB entry address left in %g1, lookup linear PTE.+ * Must preserve %g1 and %g6 (TAG).+ */+diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c+index b0f3e00..1f45985 100644+--- a/arch/sparc64/kernel/of_device.c++++ b/arch/sparc64/kernel/of_device.c+@@ -581,7 +581,7 @@ static void __init build_device_resources(struct of_device *op,+ u32 *reg = (preg + (index * ((na + ns) * 4)));+ struct device_node *dp = op->node;+ struct device_node *pp = p_op->node;+- struct of_bus *pbus;++ struct of_bus *pbus, *dbus;+ u64 size, result = OF_BAD_ADDR;+ unsigned long flags;+ int dna, dns;+@@ -599,6 +599,7 @@ static void __init build_device_resources(struct of_device *op,++ dna = na;+ dns = ns;++ dbus = bus;++ while (1) {+ dp = pp;+@@ -611,13 +612,13 @@ static void __init build_device_resources(struct of_device *op,+ pbus = of_match_bus(pp);+ pbus->count_cells(dp, &pna, &pns);++- if (build_one_resource(dp, bus, pbus, addr,++ if (build_one_resource(dp, dbus, pbus, addr,+ dna, dns, pna))+ break;++ dna = pna;+ dns = pns;+- bus = pbus;++ dbus = pbus;+ }++ build_res:+@@ -708,7 +709,7 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,+ unsigned int irq)+ {+ struct linux_prom_pci_registers *regs;+- unsigned int devfn, slot, ret;++ unsigned int bus, devfn, slot, ret;++ if (irq < 1 || irq > 4)+ return irq;+@@ -717,10 +718,46 @@ static unsigned int __init pci_irq_swizzle(struct device_node *dp,+ if (!regs)+ return irq;+++ bus = (regs->phys_hi >> 16) & 0xff;+ devfn = (regs->phys_hi >> 8) & 0xff;+ slot = (devfn >> 3) & 0x1f;++- ret = ((irq - 1 + (slot & 3)) & 3) + 1;++ if (pp->irq_trans) {++ /* Derived from Table 8-3, U2P User's Manual. This branch++ * is handling a PCI controller that lacks a proper set of++ * interrupt-map and interrupt-map-mask properties. The++ * Ultra-E450 is one example.++ *++ * The bit layout is BSSLL, where:++ * B: 0 on bus A, 1 on bus B++ * D: 2-bit slot number, derived from PCI device number as++ * (dev - 1) for bus A, or (dev - 2) for bus B++ * L: 2-bit line number++ *++ * Actually, more "portable" way to calculate the funky++ * slot number is to subtract pbm->pci_first_slot from the++ * device number, and that's exactly what the pre-OF++ * sparc64 code did, but we're building this stuff generically++ * using the OBP tree, not in the PCI controller layer.++ */++ if (bus & 0x80) {++ /* PBM-A */++ bus = 0x00;++ slot = (slot - 1) << 2;++ } else {++ /* PBM-B */++ bus = 0x10;++ slot = (slot - 2) << 2;++ }++ irq -= 1;++++ ret = (bus | slot | irq);++ } else {++ /* Going through a PCI-PCI bridge that lacks a set of++ * interrupt-map and interrupt-map-mask properties.++ */++ ret = ((irq - 1 + (slot & 3)) & 3) + 1;++ }++ return ret;+ }+diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c+index 2e7f142..7aca0f3 100644+--- a/arch/sparc64/kernel/pci_iommu.c++++ b/arch/sparc64/kernel/pci_iommu.c+@@ -64,7 +64,7 @@ static void __iommu_flushall(struct pci_iommu *iommu)+ #define IOPTE_IS_DUMMY(iommu, iopte) \+ ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa)++-static void inline iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)++static inline void iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte)+ {+ unsigned long val = iopte_val(*iopte);++diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c+index 01d6d86..14f78fb 100644+--- a/arch/sparc64/kernel/sbus.c++++ b/arch/sparc64/kernel/sbus.c+@@ -24,48 +24,25 @@++ #include "iommu_common.h"++-/* These should be allocated on an SMP_CACHE_BYTES+- * aligned boundary for optimal performance.+- *+- * On SYSIO, using an 8K page size we have 1GB of SBUS+- * DMA space mapped. We divide this space into equally+- * sized clusters. We allocate a DMA mapping from the+- * cluster that matches the order of the allocation, or+- * if the order is greater than the number of clusters,+- * we try to allocate from the last cluster.+- */+-+-#define NCLUSTERS 8UL+-#define ONE_GIG (1UL * 1024UL * 1024UL * 1024UL)+-#define CLUSTER_SIZE (ONE_GIG / NCLUSTERS)+-#define CLUSTER_MASK (CLUSTER_SIZE - 1)+-#define CLUSTER_NPAGES (CLUSTER_SIZE >> IO_PAGE_SHIFT)+ #define MAP_BASE ((u32)0xc0000000)+++struct sbus_iommu_arena {++ unsigned long *map;++ unsigned int hint;++ unsigned int limit;++};+++ struct sbus_iommu {+-/*0x00*/spinlock_t lock;++ spinlock_t lock;++-/*0x08*/iopte_t *page_table;+-/*0x10*/unsigned long strbuf_regs;+-/*0x18*/unsigned long iommu_regs;+-/*0x20*/unsigned long sbus_control_reg;++ struct sbus_iommu_arena arena;++-/*0x28*/volatile unsigned long strbuf_flushflag;++ iopte_t *page_table;++ unsigned long strbuf_regs;++ unsigned long iommu_regs;++ unsigned long sbus_control_reg;++- /* If NCLUSTERS is ever decresed to 4 or lower,+- * you must increase the size of the type of+- * these counters. You have been duly warned. -DaveM+- */+-/*0x30*/struct {+- u16 next;+- u16 flush;+- } alloc_info[NCLUSTERS];+-+- /* The lowest used consistent mapping entry. Since+- * we allocate consistent maps out of cluster 0 this+- * is relative to the beginning of closter 0.+- */+-/*0x50*/u32 lowest_consistent_map;++ volatile unsigned long strbuf_flushflag;+ };++ /* Offsets from iommu_regs */+@@ -91,19 +68,6 @@ static void __iommu_flushall(struct sbus_iommu *iommu)+ tag += 8UL;+ }+ upa_readq(iommu->sbus_control_reg);+-+- for (entry = 0; entry < NCLUSTERS; entry++) {+- iommu->alloc_info[entry].flush =+- iommu->alloc_info[entry].next;+- }+-}+-+-static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)+-{+- while (npages--)+- upa_writeq(base + (npages << IO_PAGE_SHIFT),+- iommu->iommu_regs + IOMMU_FLUSH);+- upa_readq(iommu->sbus_control_reg);+ }++ /* Offsets from strbuf_regs */+@@ -156,178 +120,115 @@ static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long+ base, npages);+ }++-static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages)++/* Based largely upon the ppc64 iommu allocator. */++static long sbus_arena_alloc(struct sbus_iommu *iommu, unsigned long npages)+ {+- iopte_t *iopte, *limit, *first, *cluster;+- unsigned long cnum, ent, nent, flush_point, found;+-+- cnum = 0;+- nent = 1;+- while ((1UL << cnum) < npages)+- cnum++;+- if(cnum >= NCLUSTERS) {+- nent = 1UL << (cnum - NCLUSTERS);+- cnum = NCLUSTERS - 1;+- }+- iopte = iommu->page_table + (cnum * CLUSTER_NPAGES);+-+- if (cnum == 0)+- limit = (iommu->page_table ++- iommu->lowest_consistent_map);+- else+- limit = (iopte + CLUSTER_NPAGES);+-+- iopte += ((ent = iommu->alloc_info[cnum].next) << cnum);+- flush_point = iommu->alloc_info[cnum].flush;+-+- first = iopte;+- cluster = NULL;+- found = 0;+- for (;;) {+- if (iopte_val(*iopte) == 0UL) {+- found++;+- if (!cluster)+- cluster = iopte;++ struct sbus_iommu_arena *arena = &iommu->arena;++ unsigned long n, i, start, end, limit;++ int pass;++++ limit = arena->limit;++ start = arena->hint;++ pass = 0;++++again:++ n = find_next_zero_bit(arena->map, limit, start);++ end = n + npages;++ if (unlikely(end >= limit)) {++ if (likely(pass < 1)) {++ limit = start;++ start = 0;++ __iommu_flushall(iommu);++ pass++;++ goto again;+ } else {+- /* Used cluster in the way */+- cluster = NULL;+- found = 0;++ /* Scanned the whole thing, give up. */++ return -1;+ }++ }++- if (found == nent)+- break;+-+- iopte += (1 << cnum);+- ent++;+- if (iopte >= limit) {+- iopte = (iommu->page_table + (cnum * CLUSTER_NPAGES));+- ent = 0;+-+- /* Multiple cluster allocations must not wrap */+- cluster = NULL;+- found = 0;++ for (i = n; i < end; i++) {++ if (test_bit(i, arena->map)) {++ start = i + 1;++ goto again;+ }+- if (ent == flush_point)+- __iommu_flushall(iommu);+- if (iopte == first)+- goto bad;+ }++- /* ent/iopte points to the last cluster entry we're going to use,+- * so save our place for the next allocation.+- */+- if ((iopte + (1 << cnum)) >= limit)+- ent = 0;+- else+- ent = ent + 1;+- iommu->alloc_info[cnum].next = ent;+- if (ent == flush_point)+- __iommu_flushall(iommu);+-+- /* I've got your streaming cluster right here buddy boy... */+- return cluster;+-+-bad:+- printk(KERN_EMERG "sbus: alloc_streaming_cluster of npages(%ld) failed!\n",+- npages);+- return NULL;++ for (i = n; i < end; i++)++ __set_bit(i, arena->map);++++ arena->hint = end;++++ return n;+ }++-static void free_streaming_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)++static void sbus_arena_free(struct sbus_iommu_arena *arena, unsigned long base, unsigned long npages)+ {+- unsigned long cnum, ent, nent;+- iopte_t *iopte;++ unsigned long i;++- cnum = 0;+- nent = 1;+- while ((1UL << cnum) < npages)+- cnum++;+- if(cnum >= NCLUSTERS) {+- nent = 1UL << (cnum - NCLUSTERS);+- cnum = NCLUSTERS - 1;+- }+- ent = (base & CLUSTER_MASK) >> (IO_PAGE_SHIFT + cnum);+- iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT);+- do {+- iopte_val(*iopte) = 0UL;+- iopte += 1 << cnum;+- } while(--nent);+-+- /* If the global flush might not have caught this entry,+- * adjust the flush point such that we will flush before+- * ever trying to reuse it.+- */+-#define between(X,Y,Z) (((Z) - (Y)) >= ((X) - (Y)))+- if (between(ent, iommu->alloc_info[cnum].next, iommu->alloc_info[cnum].flush))+- iommu->alloc_info[cnum].flush = ent;+-#undef between++ for (i = base; i < (base + npages); i++)++ __clear_bit(i, arena->map);+ }++-/* We allocate consistent mappings from the end of cluster zero. */+-static iopte_t *alloc_consistent_cluster(struct sbus_iommu *iommu, unsigned long npages)++static void sbus_iommu_table_init(struct sbus_iommu *iommu, unsigned int tsbsize)+ {+- iopte_t *iopte;++ unsigned long tsbbase, order, sz, num_tsb_entries;++- iopte = iommu->page_table + (1 * CLUSTER_NPAGES);+- while (iopte > iommu->page_table) {+- iopte--;+- if (!(iopte_val(*iopte) & IOPTE_VALID)) {+- unsigned long tmp = npages;++ num_tsb_entries = tsbsize / sizeof(iopte_t);++- while (--tmp) {+- iopte--;+- if (iopte_val(*iopte) & IOPTE_VALID)+- break;+- }+- if (tmp == 0) {+- u32 entry = (iopte - iommu->page_table);++ /* Setup initial software IOMMU state. */++ spin_lock_init(&iommu->lock);++- if (entry < iommu->lowest_consistent_map)+- iommu->lowest_consistent_map = entry;+- return iopte;+- }+- }++ /* Allocate and initialize the free area map. */++ sz = num_tsb_entries / 8;++ sz = (sz + 7UL) & ~7UL;++ iommu->arena.map = kzalloc(sz, GFP_KERNEL);++ if (!iommu->arena.map) {++ prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");++ prom_halt();++ }++ iommu->arena.limit = num_tsb_entries;++++ /* Now allocate and setup the IOMMU page table itself. */++ order = get_order(tsbsize);++ tsbbase = __get_free_pages(GFP_KERNEL, order);++ if (!tsbbase) {++ prom_printf("IOMMU: Error, gfp(tsb) failed.\n");++ prom_halt();+ }+- return NULL;++ iommu->page_table = (iopte_t *)tsbbase;++ memset(iommu->page_table, 0, tsbsize);+ }++-static void free_consistent_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)++static inline iopte_t *alloc_npages(struct sbus_iommu *iommu, unsigned long npages)+ {+- iopte_t *iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT);++ long entry;++- if ((iopte - iommu->page_table) == iommu->lowest_consistent_map) {+- iopte_t *walk = iopte + npages;+- iopte_t *limit;++ entry = sbus_arena_alloc(iommu, npages);++ if (unlikely(entry < 0))++ return NULL;++- limit = iommu->page_table + CLUSTER_NPAGES;+- while (walk < limit) {+- if (iopte_val(*walk) != 0UL)+- break;+- walk++;+- }+- iommu->lowest_consistent_map =+- (walk - iommu->page_table);+- }++ return iommu->page_table + entry;++}++- while (npages--)+- *iopte++ = __iopte(0UL);++static inline void free_npages(struct sbus_iommu *iommu, dma_addr_t base, unsigned long npages)++{++ sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);+ }++ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr)+ {+- unsigned long order, first_page, flags;+ struct sbus_iommu *iommu;+ iopte_t *iopte;++ unsigned long flags, order, first_page;+ void *ret;+ int npages;++- if (size <= 0 || sdev == NULL || dvma_addr == NULL)+- return NULL;+-+ size = IO_PAGE_ALIGN(size);+ order = get_order(size);+ if (order >= 10)+ return NULL;+++ first_page = __get_free_pages(GFP_KERNEL|__GFP_COMP, order);+ if (first_page == 0UL)+ return NULL;+@@ -336,108 +237,121 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma+ iommu = sdev->bus->iommu;++ spin_lock_irqsave(&iommu->lock, flags);+- iopte = alloc_consistent_cluster(iommu, size >> IO_PAGE_SHIFT);+- if (iopte == NULL) {+- spin_unlock_irqrestore(&iommu->lock, flags);++ iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);++ spin_unlock_irqrestore(&iommu->lock, flags);++++ if (unlikely(iopte == NULL)) {+ free_pages(first_page, order);+ return NULL;+ }++- /* Ok, we're committed at this point. */+- *dvma_addr = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);++ *dvma_addr = (MAP_BASE +++ ((iopte - iommu->page_table) << IO_PAGE_SHIFT));+ ret = (void *) first_page;+ npages = size >> IO_PAGE_SHIFT;++ first_page = __pa(first_page);+ while (npages--) {+- *iopte++ = __iopte(IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE |+- (__pa(first_page) & IOPTE_PAGE));++ iopte_val(*iopte) = (IOPTE_VALID | IOPTE_CACHE |++ IOPTE_WRITE |++ (first_page & IOPTE_PAGE));++ iopte++;+ first_page += IO_PAGE_SIZE;+ }+- iommu_flush(iommu, *dvma_addr, size >> IO_PAGE_SHIFT);+- spin_unlock_irqrestore(&iommu->lock, flags);++ return ret;+ }++ void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma)+ {+- unsigned long order, npages;+ struct sbus_iommu *iommu;+-+- if (size <= 0 || sdev == NULL || cpu == NULL)+- return;++ iopte_t *iopte;++ unsigned long flags, order, npages;++ npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;+ iommu = sdev->bus->iommu;++ iopte = iommu->page_table +++ ((dvma - MAP_BASE) >> IO_PAGE_SHIFT);++++ spin_lock_irqsave(&iommu->lock, flags);++++ free_npages(iommu, dvma - MAP_BASE, npages);++- spin_lock_irq(&iommu->lock);+- free_consistent_cluster(iommu, dvma, npages);+- iommu_flush(iommu, dvma, npages);+- spin_unlock_irq(&iommu->lock);++ spin_unlock_irqrestore(&iommu->lock, flags);++ order = get_order(size);+ if (order < 10)+ free_pages((unsigned long)cpu, order);+ }++-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int dir)++dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction)+ {+- struct sbus_iommu *iommu = sdev->bus->iommu;+- unsigned long npages, pbase, flags;+- iopte_t *iopte;+- u32 dma_base, offset;+- unsigned long iopte_bits;++ struct sbus_iommu *iommu;++ iopte_t *base;++ unsigned long flags, npages, oaddr;++ unsigned long i, base_paddr;++ u32 bus_addr, ret;++ unsigned long iopte_protection;++++ iommu = sdev->bus->iommu;++- if (dir == SBUS_DMA_NONE)++ if (unlikely(direction == SBUS_DMA_NONE))+ BUG();++- pbase = (unsigned long) ptr;+- offset = (u32) (pbase & ~IO_PAGE_MASK);+- size = (IO_PAGE_ALIGN(pbase + size) - (pbase & IO_PAGE_MASK));+- pbase = (unsigned long) __pa(pbase & IO_PAGE_MASK);++ oaddr = (unsigned long)ptr;++ npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);++ npages >>= IO_PAGE_SHIFT;++ spin_lock_irqsave(&iommu->lock, flags);+- npages = size >> IO_PAGE_SHIFT;+- iopte = alloc_streaming_cluster(iommu, npages);+- if (iopte == NULL)+- goto bad;+- dma_base = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);+- npages = size >> IO_PAGE_SHIFT;+- iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;+- if (dir != SBUS_DMA_TODEVICE)+- iopte_bits |= IOPTE_WRITE;+- while (npages--) {+- *iopte++ = __iopte(iopte_bits | (pbase & IOPTE_PAGE));+- pbase += IO_PAGE_SIZE;+- }+- npages = size >> IO_PAGE_SHIFT;++ base = alloc_npages(iommu, npages);+ spin_unlock_irqrestore(&iommu->lock, flags);++- return (dma_base | offset);++ if (unlikely(!base))++ BUG();++-bad:+- spin_unlock_irqrestore(&iommu->lock, flags);+- BUG();+- return 0;++ bus_addr = (MAP_BASE +++ ((base - iommu->page_table) << IO_PAGE_SHIFT));++ ret = bus_addr | (oaddr & ~IO_PAGE_MASK);++ base_paddr = __pa(oaddr & IO_PAGE_MASK);++++ iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;++ if (direction != SBUS_DMA_TODEVICE)++ iopte_protection |= IOPTE_WRITE;++++ for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE)++ iopte_val(*base) = iopte_protection | base_paddr;++++ return ret;+ }++-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, int direction)++void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)+ {+ struct sbus_iommu *iommu = sdev->bus->iommu;+- u32 dma_base = dma_addr & IO_PAGE_MASK;+- unsigned long flags;++ iopte_t *base;++ unsigned long flags, npages, i;++++ if (unlikely(direction == SBUS_DMA_NONE))++ BUG();++++ npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);++ npages >>= IO_PAGE_SHIFT;++ base = iommu->page_table +++ ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);++- size = (IO_PAGE_ALIGN(dma_addr + size) - dma_base);++ bus_addr &= IO_PAGE_MASK;++ spin_lock_irqsave(&iommu->lock, flags);+- free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT);+- sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT, direction);++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);++ for (i = 0; i < npages; i++)++ iopte_val(base[i]) = 0UL;++ free_npages(iommu, bus_addr - MAP_BASE, npages);+ spin_unlock_irqrestore(&iommu->lock, flags);+ }++ #define SG_ENT_PHYS_ADDRESS(SG) \+ (__pa(page_address((SG)->page)) + (SG)->offset)++-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, int nelems, unsigned long iopte_bits)++static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,++ int nused, int nelems, unsigned long iopte_protection)+ {+ struct scatterlist *dma_sg = sg;+ struct scatterlist *sg_end = sg + nelems;+@@ -462,7 +376,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, in+ for (;;) {+ unsigned long tmp;++- tmp = (unsigned long) SG_ENT_PHYS_ADDRESS(sg);++ tmp = SG_ENT_PHYS_ADDRESS(sg);+ len = sg->length;+ if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {+ pteval = tmp & IO_PAGE_MASK;+@@ -478,7 +392,7 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, in+ sg++;+ }++- pteval = ((pteval & IOPTE_PAGE) | iopte_bits);++ pteval = iopte_protection | (pteval & IOPTE_PAGE);+ while (len > 0) {+ *iopte++ = __iopte(pteval);+ pteval += IO_PAGE_SIZE;+@@ -509,103 +423,111 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, in+ }+ }++-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int dir)++int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)+ {+- struct sbus_iommu *iommu = sdev->bus->iommu;+- unsigned long flags, npages;+- iopte_t *iopte;++ struct sbus_iommu *iommu;++ unsigned long flags, npages, iopte_protection;++ iopte_t *base;+ u32 dma_base;+ struct scatterlist *sgtmp;+ int used;+- unsigned long iopte_bits;+-+- if (dir == SBUS_DMA_NONE)+- BUG();++ /* Fast path single entry scatterlists. */+- if (nents == 1) {+- sg->dma_address =++ if (nelems == 1) {++ sglist->dma_address =+ sbus_map_single(sdev,+- (page_address(sg->page) + sg->offset),+- sg->length, dir);+- sg->dma_length = sg->length;++ (page_address(sglist->page) + sglist->offset),++ sglist->length, direction);++ sglist->dma_length = sglist->length;+ return 1;+ }++- npages = prepare_sg(sg, nents);++ iommu = sdev->bus->iommu;++++ if (unlikely(direction == SBUS_DMA_NONE))++ BUG();++++ npages = prepare_sg(sglist, nelems);++ spin_lock_irqsave(&iommu->lock, flags);+- iopte = alloc_streaming_cluster(iommu, npages);+- if (iopte == NULL)+- goto bad;+- dma_base = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);++ base = alloc_npages(iommu, npages);++ spin_unlock_irqrestore(&iommu->lock, flags);++++ if (unlikely(base == NULL))++ BUG();++++ dma_base = MAP_BASE +++ ((base - iommu->page_table) << IO_PAGE_SHIFT);++ /* Normalize DVMA addresses. */+- sgtmp = sg;+- used = nents;++ used = nelems;+++ sgtmp = sglist;+ while (used && sgtmp->dma_length) {+ sgtmp->dma_address += dma_base;+ sgtmp++;+ used--;+ }+- used = nents - used;++ used = nelems - used;++- iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;+- if (dir != SBUS_DMA_TODEVICE)+- iopte_bits |= IOPTE_WRITE;++ iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;++ if (direction != SBUS_DMA_TODEVICE)++ iopte_protection |= IOPTE_WRITE;++++ fill_sg(base, sglist, used, nelems, iopte_protection);++- fill_sg(iopte, sg, used, nents, iopte_bits);+ #ifdef VERIFY_SG+- verify_sglist(sg, nents, iopte, npages);++ verify_sglist(sglist, nelems, base, npages);+ #endif+- spin_unlock_irqrestore(&iommu->lock, flags);++ return used;+-+-bad:+- spin_unlock_irqrestore(&iommu->lock, flags);+- BUG();+- return 0;+ }++-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)++void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)+ {+- unsigned long size, flags;+ struct sbus_iommu *iommu;+- u32 dvma_base;+- int i;++ iopte_t *base;++ unsigned long flags, i, npages;++ u32 bus_addr;++- /* Fast path single entry scatterlists. */+- if (nents == 1) {+- sbus_unmap_single(sdev, sg->dma_address, sg->dma_length, direction);+- return;+- }++ if (unlikely(direction == SBUS_DMA_NONE))++ BUG();++++ iommu = sdev->bus->iommu;++++ bus_addr = sglist->dma_address & IO_PAGE_MASK;++- dvma_base = sg[0].dma_address & IO_PAGE_MASK;+- for (i = 0; i < nents; i++) {+- if (sg[i].dma_length == 0)++ for (i = 1; i < nelems; i++)++ if (sglist[i].dma_length == 0)+ break;+- }+ i--;+- size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - dvma_base;++ npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) -++ bus_addr) >> IO_PAGE_SHIFT;++++ base = iommu->page_table +++ ((bus_addr - MAP_BASE) >> IO_PAGE_SHIFT);++- iommu = sdev->bus->iommu;+ spin_lock_irqsave(&iommu->lock, flags);+- free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT);+- sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT, direction);++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);++ for (i = 0; i < npages; i++)++ iopte_val(base[i]) = 0UL;++ free_npages(iommu, bus_addr - MAP_BASE, npages);+ spin_unlock_irqrestore(&iommu->lock, flags);+ }++-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction)++void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)+ {+- struct sbus_iommu *iommu = sdev->bus->iommu;+- unsigned long flags;++ struct sbus_iommu *iommu;++ unsigned long flags, npages;++++ iommu = sdev->bus->iommu;++- size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK));++ npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);++ npages >>= IO_PAGE_SHIFT;++ bus_addr &= IO_PAGE_MASK;++ spin_lock_irqsave(&iommu->lock, flags);+- sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT, direction);++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);+ spin_unlock_irqrestore(&iommu->lock, flags);+ }++@@ -613,23 +535,25 @@ void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, siz+ {+ }++-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)++void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)+ {+- struct sbus_iommu *iommu = sdev->bus->iommu;+- unsigned long flags, size;+- u32 base;+- int i;++ struct sbus_iommu *iommu;++ unsigned long flags, npages, i;++ u32 bus_addr;++++ iommu = sdev->bus->iommu;++- base = sg[0].dma_address & IO_PAGE_MASK;+- for (i = 0; i < nents; i++) {+- if (sg[i].dma_length == 0)++ bus_addr = sglist[0].dma_address & IO_PAGE_MASK;++ for (i = 0; i < nelems; i++) {++ if (!sglist[i].dma_length)+ break;+ }+ i--;+- size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base;++ npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length)++ - bus_addr) >> IO_PAGE_SHIFT;++ spin_lock_irqsave(&iommu->lock, flags);+- sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT, direction);++ sbus_strbuf_flush(iommu, bus_addr, npages, direction);+ spin_unlock_irqrestore(&iommu->lock, flags);+ }++@@ -1104,7 +1028,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)+ struct linux_prom64_registers *pr;+ struct device_node *dp;+ struct sbus_iommu *iommu;+- unsigned long regs, tsb_base;++ unsigned long regs;+ u64 control;+ int i;++@@ -1132,14 +1056,6 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)++ memset(iommu, 0, sizeof(*iommu));++- /* We start with no consistent mappings. */+- iommu->lowest_consistent_map = CLUSTER_NPAGES;+-+- for (i = 0; i < NCLUSTERS; i++) {+- iommu->alloc_info[i].flush = 0;+- iommu->alloc_info[i].next = 0;+- }+-+ /* Setup spinlock. */+ spin_lock_init(&iommu->lock);++@@ -1159,25 +1075,13 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)+ sbus->portid, regs);++ /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */++ sbus_iommu_table_init(iommu, IO_TSB_SIZE);+++ control = upa_readq(iommu->iommu_regs + IOMMU_CONTROL);+ control = ((7UL << 16UL) |+ (0UL << 2UL) |+ (1UL << 1UL) |+ (1UL << 0UL));+-+- /* Using the above configuration we need 1MB iommu page+- * table (128K ioptes * 8 bytes per iopte). This is+- * page order 7 on UltraSparc.+- */+- tsb_base = __get_free_pages(GFP_ATOMIC, get_order(IO_TSB_SIZE));+- if (tsb_base == 0UL) {+- prom_printf("sbus_iommu_init: Fatal error, cannot alloc TSB table.\n");+- prom_halt();+- }+-+- iommu->page_table = (iopte_t *) tsb_base;+- memset(iommu->page_table, 0, IO_TSB_SIZE);+-+ upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL);++ /* Clean out any cruft in the IOMMU using+@@ -1195,7 +1099,7 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)+ upa_readq(iommu->sbus_control_reg);++ /* Give the TSB to SYSIO. */+- upa_writeq(__pa(tsb_base), iommu->iommu_regs + IOMMU_TSBBASE);++ upa_writeq(__pa(iommu->page_table), iommu->iommu_regs + IOMMU_TSBBASE);++ /* Setup streaming buffer, DE=1 SB_EN=1 */+ control = (1UL << 1UL) | (1UL << 0UL);+diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S+index c09ab4b..010a737 100644+--- a/arch/sparc64/kernel/sys32.S++++ b/arch/sparc64/kernel/sys32.S+@@ -91,7 +91,6 @@ SIGN1(sys32_select, compat_sys_select, %o0)+ SIGN1(sys32_mkdir, sys_mkdir, %o1)+ SIGN3(sys32_futex, compat_sys_futex, %o1, %o2, %o5)+ SIGN1(sys32_sysfs, compat_sys_sysfs, %o0)+-SIGN3(sys32_ipc, compat_sys_ipc, %o1, %o2, %o3)+ SIGN2(sys32_sendfile, compat_sys_sendfile, %o0, %o1)+ SIGN2(sys32_sendfile64, compat_sys_sendfile64, %o0, %o1)+ SIGN1(sys32_prctl, sys_prctl, %o0)+diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S+index 9a80267..46f870b 100644+--- a/arch/sparc64/kernel/systbls.S++++ b/arch/sparc64/kernel/systbls.S+@@ -62,7 +62,7 @@ sys_call_table32:+ /*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir+ .word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64+ /*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo+- .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex++ .word compat_sys_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex+ /*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid+ .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16+ /*230*/ .word sys32_select, compat_sys_time, sys32_splice, compat_sys_stime, compat_sys_statfs64+diff --git a/arch/sparc64/kernel/tsb.S b/arch/sparc64/kernel/tsb.S+index eedf94f..10adb2f 100644+--- a/arch/sparc64/kernel/tsb.S++++ b/arch/sparc64/kernel/tsb.S+@@ -546,6 +546,7 @@ NGtsb_init:+ subcc %o1, 0x100, %o1+ bne,pt %xcc, 1b+ add %o0, 0x100, %o0++ membar #Sync+ retl+ wr %g2, 0x0, %asi+ .size NGtsb_init, .-NGtsb_init+diff --git a/arch/sparc64/lib/NGbzero.S b/arch/sparc64/lib/NGbzero.S+index e86baec..f10e452 100644+--- a/arch/sparc64/lib/NGbzero.S++++ b/arch/sparc64/lib/NGbzero.S+@@ -88,6 +88,7 @@ NGbzero_loop:+ bne,pt %xcc, NGbzero_loop+ add %o0, 64, %o0+++ membar #Sync+ wr %o4, 0x0, %asi+ brz,pn %o1, NGbzero_done+ NGbzero_medium:+diff --git a/arch/sparc64/lib/NGmemcpy.S b/arch/sparc64/lib/NGmemcpy.S+index 8e522b3..66063a9 100644+--- a/arch/sparc64/lib/NGmemcpy.S++++ b/arch/sparc64/lib/NGmemcpy.S+@@ -247,6 +247,8 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */+ /* fall through */++ 60:++ membar #Sync+++ /* %o2 contains any final bytes still needed to be copied+ * over. If anything is left, we copy it one byte at a time.+ */+diff --git a/arch/sparc64/lib/NGpage.S b/arch/sparc64/lib/NGpage.S+index 7d7c3bb..8ce3a0c 100644+--- a/arch/sparc64/lib/NGpage.S++++ b/arch/sparc64/lib/NGpage.S+@@ -41,6 +41,7 @@ NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */+ subcc %g7, 64, %g7+ bne,pt %xcc, 1b+ add %o0, 32, %o0++ membar #Sync+ retl+ nop++@@ -63,6 +64,7 @@ NGclear_user_page: /* %o0=dest, %o1=vaddr */+ subcc %g7, 64, %g7+ bne,pt %xcc, 1b+ add %o0, 32, %o0++ membar #Sync+ retl+ nop++diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c+index 33fd0b2..00677b5 100644+--- a/arch/sparc64/mm/hugetlbpage.c++++ b/arch/sparc64/mm/hugetlbpage.c+@@ -248,6 +248,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,+ if (!pte_present(*ptep) && pte_present(entry))+ mm->context.huge_pte_count++;+++ addr &= HPAGE_MASK;+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {+ set_pte_at(mm, addr, ptep, entry);+ ptep++;+@@ -266,6 +267,8 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,+ if (pte_present(entry))+ mm->context.huge_pte_count--;+++ addr &= HPAGE_MASK;+++ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {+ pte_clear(mm, addr, ptep);+ addr += PAGE_SIZE;+diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c+index 054822a..5391cd5 100644+--- a/arch/sparc64/mm/init.c++++ b/arch/sparc64/mm/init.c+@@ -59,8 +59,10 @@ 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];++#endif++ #define MAX_BANKS 32++@@ -1301,7 +1303,12 @@ static void __init tsb_phys_patch(void)+ }++ /* Don't mark as init, we give this to the Hypervisor. */+-static struct hv_tsb_descr ktsb_descr[2];++#ifndef CONFIG_DEBUG_PAGEALLOC++#define NUM_KTSB_DESCR 2++#else++#define NUM_KTSB_DESCR 1++#endif++static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR];+ extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];++ static void __init sun4v_ktsb_init(void)+@@ -1340,6 +1347,7 @@ static void __init sun4v_ktsb_init(void)+ ktsb_descr[0].tsb_base = ktsb_pa;+ ktsb_descr[0].resv = 0;+++#ifndef CONFIG_DEBUG_PAGEALLOC+ /* Second KTSB for 4MB/256MB mappings. */+ ktsb_pa = (kern_base ++ ((unsigned long)&swapper_4m_tsb[0] - KERNBASE));+@@ -1352,6 +1360,7 @@ static void __init sun4v_ktsb_init(void)+ ktsb_descr[1].ctx_idx = 0;+ ktsb_descr[1].tsb_base = ktsb_pa;+ ktsb_descr[1].resv = 0;++#endif+ }++ void __cpuinit sun4v_ktsb_register(void)+@@ -1364,7 +1373,7 @@ void __cpuinit sun4v_ktsb_register(void)+ pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE);++ func = HV_FAST_MMU_TSB_CTX0;+- arg0 = 2;++ arg0 = NUM_KTSB_DESCR;+ arg1 = pa;+ __asm__ __volatile__("ta %6"+ : "=&r" (func), "=&r" (arg0), "=&r" (arg1)+@@ -1393,7 +1402,9 @@ void __init paging_init(void)++ /* Invalidate both kernel TSBs. */+ memset(swapper_tsb, 0x40, sizeof(swapper_tsb));++#ifndef CONFIG_DEBUG_PAGEALLOC+ memset(swapper_4m_tsb, 0x40, sizeof(swapper_4m_tsb));++#endif++ if (tlb_type == hypervisor)+ sun4v_pgprot_init();+@@ -1725,8 +1736,13 @@ static void __init sun4u_pgprot_init(void)+ pg_iobits = (_PAGE_VALID | _PAGE_PRESENT_4U | __DIRTY_BITS_4U |+ __ACCESS_BITS_4U | _PAGE_E_4U);+++#ifdef CONFIG_DEBUG_PAGEALLOC++ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^++ 0xfffff80000000000;++#else+ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^+ 0xfffff80000000000;++#endif+ kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |+ _PAGE_P_4U | _PAGE_W_4U);++@@ -1769,13 +1785,23 @@ static void __init sun4v_pgprot_init(void)+ _PAGE_E = _PAGE_E_4V;+ _PAGE_CACHE = _PAGE_CACHE_4V;+++#ifdef CONFIG_DEBUG_PAGEALLOC++ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^++ 0xfffff80000000000;++#else+ kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^+ 0xfffff80000000000;++#endif+ kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |+ _PAGE_P_4V | _PAGE_W_4V);+++#ifdef CONFIG_DEBUG_PAGEALLOC++ kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^++ 0xfffff80000000000;++#else+ kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^+ 0xfffff80000000000;++#endif+ kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |+ _PAGE_P_4V | _PAGE_W_4V);++diff --git a/arch/um/include/os.h b/arch/um/include/os.h+index 13a86bd..4e9a13e 100644+--- a/arch/um/include/os.h++++ b/arch/um/include/os.h+@@ -341,4 +341,6 @@ extern void maybe_sigio_broken(int fd, int read);+ extern void sig_handler_common_skas(int sig, void *sc_ptr);+ extern void user_signal(int sig, union uml_pt_regs *regs, int pid);+++extern int os_arch_prctl(int pid, int code, unsigned long *addr);+++ #endif+diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h+index 66cb400..62403bd 100644+--- a/arch/um/include/sysdep-x86_64/ptrace.h++++ b/arch/um/include/sysdep-x86_64/ptrace.h+@@ -104,10 +104,6 @@ union uml_pt_regs {+ #endif+ #ifdef UML_CONFIG_MODE_SKAS+ struct skas_regs {+- /* x86_64 ptrace uses sizeof(user_regs_struct) as its register+- * file size, while i386 uses FRAME_SIZE. Therefore, we need+- * to use UM_FRAME_SIZE here instead of HOST_FRAME_SIZE.+- */+ unsigned long regs[MAX_REG_NR];+ unsigned long fp[HOST_FP_SIZE];+ struct faultinfo faultinfo;+diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c+index 5a99dd3..13c6cb5 100644+--- a/arch/um/os-Linux/elf_aux.c++++ b/arch/um/os-Linux/elf_aux.c+@@ -40,6 +40,9 @@ __init void scan_elf_aux( char **envp)+ switch ( auxv->a_type ) {+ case AT_SYSINFO:+ __kernel_vsyscall = auxv->a_un.a_val;++ /* See if the page is under TASK_SIZE */++ if (__kernel_vsyscall < (unsigned long) envp)++ __kernel_vsyscall = 0;+ break;+ case AT_SYSINFO_EHDR:+ vsyscall_ehdr = auxv->a_un.a_val;+diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c+index 925a652..b2e1fd8 100644+--- a/arch/um/os-Linux/sigio.c++++ b/arch/um/os-Linux/sigio.c+@@ -97,20 +97,22 @@ static int write_sigio_thread(void *unused)++ static int need_poll(struct pollfds *polls, int n)+ {+- if(n <= polls->size){+- polls->used = n;++ struct pollfd *new;++++ if(n <= polls->size)+ return 0;+- }+- kfree(polls->poll);+- polls->poll = um_kmalloc_atomic(n * sizeof(struct pollfd));+- if(polls->poll == NULL){++++ new = um_kmalloc_atomic(n * sizeof(struct pollfd));++ if(new == NULL){+ printk("need_poll : failed to allocate new pollfds\n");+- polls->size = 0;+- polls->used = 0;+ return -ENOMEM;+ }++++ memcpy(new, polls->poll, polls->used * sizeof(struct pollfd));++ kfree(polls->poll);++++ polls->poll = new;+ polls->size = n;+- polls->used = n;+ return 0;+ }++@@ -171,15 +173,15 @@ int add_sigio_fd(int fd)+ goto out;+ }++- n = current_poll.used + 1;+- err = need_poll(&next_poll, n);++ n = current_poll.used;++ err = need_poll(&next_poll, n + 1);+ if(err)+ goto out;++- for(i = 0; i < current_poll.used; i++)+- next_poll.poll[i] = current_poll.poll[i];+-+- next_poll.poll[n - 1] = *p;++ memcpy(next_poll.poll, current_poll.poll,++ current_poll.used * sizeof(struct pollfd));++ next_poll.poll[n] = *p;++ next_poll.used = n + 1;+ update_thread();+ out:+ sigio_unlock();+@@ -214,6 +216,7 @@ int ignore_sigio_fd(int fd)+ if(p->fd != fd)