Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 26 Feb 2008 15:49:36 +0000 (07:49 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 26 Feb 2008 15:49:36 +0000 (07:49 -0800)
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  Revert "power_state: get rid of write-only variable in SATA"
  make atapi_dmadir static

38 files changed:
Documentation/debugging-via-ohci1394.txt
arch/um/kernel/process.c
arch/x86/Kconfig.cpu
arch/x86/boot/memory.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/transmeta.c
arch/x86/kernel/entry_64.S
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/hpet.c
arch/x86/kernel/process_64.c
arch/x86/kernel/setup_64.c
arch/x86/kernel/smpboot_64.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/tsc_32.c
arch/x86/kernel/vsyscall_64.c
arch/x86/lguest/boot.c
arch/x86/mm/init_64.c
arch/x86/mm/pageattr.c
arch/x86/vdso/Makefile
drivers/firewire/fw-cdev.c
drivers/firewire/fw-device.c
drivers/firewire/fw-device.h
drivers/firewire/fw-sbp2.c
drivers/ieee1394/sbp2.c
drivers/ieee1394/sbp2.h
fs/proc/base.c
include/asm-x86/futex.h
include/asm-x86/lguest.h
include/asm-x86/nops.h
include/asm-x86/page_64.h
include/linux/sched.h
kernel/lockdep.c
kernel/printk.c
kernel/sched.c
kernel/sched_fair.c

index de4804e8b396eb29000b37dd8fa575f5cd7dee8d..c360d4e91b4892d6be5a6ed5efcb981d4a3ad19f 100644 (file)
@@ -36,14 +36,15 @@ available (notebooks) or too slow for extensive debug information (like ACPI).
 Drivers
 -------
 
-The OHCI-1394 drivers in drivers/firewire and drivers/ieee1394 initialize
-the OHCI-1394 controllers to a working state and can be used to enable
-physical DMA. By default you only have to load the driver, and physical
-DMA access will be granted to all remote nodes, but it can be turned off
-when using the ohci1394 driver.
-
-Because these drivers depend on the PCI enumeration to be completed, an
-initialization routine which can runs pretty early (long before console_init(),
+The ohci1394 driver in drivers/ieee1394 initializes the OHCI-1394 controllers
+to a working state and enables physical DMA by default for all remote nodes.
+This can be turned off by ohci1394's module parameter phys_dma=0.
+
+The alternative firewire-ohci driver in drivers/firewire uses filtered physical
+DMA, hence is not yet suitable for remote debugging.
+
+Because ohci1394 depends on the PCI enumeration to be completed, an
+initialization routine which runs pretty early (long before console_init()
 which makes the printk buffer appear on the console can be called) was written.
 
 To activate it, enable CONFIG_PROVIDE_OHCI1394_DMA_INIT (Kernel hacking menu:
index fc50d2f959d12f44bc6c41171f3cc030d6ad38fa..e8cb9ff183e9fe1da41020bc39ffe22b43ef56c7 100644 (file)
@@ -128,8 +128,6 @@ void *get_current(void)
        return current;
 }
 
-extern void schedule_tail(struct task_struct *prev);
-
 /*
  * This is called magically, by its address being stuffed in a jmp_buf
  * and being longjmp-d to.
index e09a6b73a1aab5c3fc6a353e22af4936b047416f..6d50064db182303dd27402b2e6c1c84d4502971b 100644 (file)
@@ -377,6 +377,19 @@ config X86_OOSTORE
        def_bool y
        depends on (MWINCHIP3D || MWINCHIP2 || MWINCHIPC6) && MTRR
 
+#
+# P6_NOPs are a relatively minor optimization that require a family >=
+# 6 processor, except that it is broken on certain VIA chips.
+# Furthermore, AMD chips prefer a totally different sequence of NOPs
+# (which work on all CPUs).  As a result, disallow these if we're
+# compiling X86_GENERIC but not X86_64 (these NOPs do work on all
+# x86-64 capable chips); the list of processors in the right-hand clause
+# are the cores that benefit from this optimization.
+#
+config X86_P6_NOP
+       def_bool y
+       depends on (X86_64 || !X86_GENERIC) && (M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || MCORE2 || PENTIUM4)
+
 config X86_TSC
        def_bool y
        depends on ((MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ) || X86_64
@@ -390,6 +403,7 @@ config X86_CMOV
 config X86_MINIMUM_CPU_FAMILY
        int
        default "64" if X86_64
+       default "6" if X86_32 && X86_P6_NOP
        default "4" if X86_32 && (X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK)
        default "3"
 
index 378353956b5dfc86469b66419b9680e1770a7410..e77d89f9e8aa23c13751bee268718e8ed7ee54a7 100644 (file)
@@ -37,6 +37,12 @@ static int detect_memory_e820(void)
                      "=m" (*desc)
                    : "D" (desc), "d" (SMAP), "a" (0xe820));
 
+               /* BIOSes which terminate the chain with CF = 1 as opposed
+                  to %ebx = 0 don't always report the SMAP signature on
+                  the final, failing, probe. */
+               if (err)
+                       break;
+
                /* Some BIOSes stop returning SMAP in the middle of
                   the search loop.  We don't know exactly how the BIOS
                   screwed up the map at that point, we might have a
@@ -47,9 +53,6 @@ static int detect_memory_e820(void)
                        break;
                }
 
-               if (err)
-                       break;
-
                count++;
                desc++;
        } while (next && count < E820MAX);
index a33d53017997df4849660cccbab4f45a223a2bd3..8ea040124f7dc930de83225dbe45d9c642e7f196 100644 (file)
@@ -128,13 +128,11 @@ void foo(void)
        OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
 #endif
 
-#ifdef CONFIG_LGUEST_GUEST
+#if defined(CONFIG_LGUEST) || defined(CONFIG_LGUEST_GUEST) || defined(CONFIG_LGUEST_MODULE)
        BLANK();
        OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
        OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir);
-#endif
 
-#ifdef CONFIG_LGUEST
        BLANK();
        OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc);
        OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc);
index f86a3c4a2669909be340d195a6ee93201c53cdf9..a38aafaefc230b4bfc49c34c98fc2c443fff8318 100644 (file)
@@ -504,7 +504,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 
        /* Clear all flags overriden by options */
        for (i = 0; i < NCAPINTS; i++)
-               c->x86_capability[i] ^= cleared_cpu_caps[i];
+               c->x86_capability[i] &= ~cleared_cpu_caps[i];
 
        /* Init Machine Check Exception if available. */
        mcheck_init(c);
index b6e136f23d3d3219094bc9fdadaeaba048f01b96..be83336fddba9c6c3629bbe1748aa42480a6e707 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include <asm/msr.h>
+#include <asm/kvm_para.h>
 #include "mtrr.h"
 
 u32 num_var_ranges = 0;
@@ -649,6 +650,7 @@ static __init int amd_special_default_mtrr(void)
 
 /**
  * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
+ * @end_pfn: ending page frame number
  *
  * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
  * memory configurations.  This routine checks that the highest MTRR matches
@@ -688,8 +690,11 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
 
        /* kvm/qemu doesn't have mtrr set right, don't trim them all */
        if (!highest_pfn) {
-               printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n");
-               WARN_ON(1);
+               if (!kvm_para_available()) {
+                       printk(KERN_WARNING
+                               "WARNING: strange, CPU MTRRs all blank?\n");
+                       WARN_ON(1);
+               }
                return 0;
        }
 
index 200fb3f9ebfbda2ec232deec234ded94128f4cfb..e8b422c1c51267419275e5db474fbd2b5e237ea3 100644 (file)
@@ -76,13 +76,6 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
        /* All Transmeta CPUs have a constant TSC */
        set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
        
-       /* If we can run i686 user-space code, call us an i686 */
-#define USER686 ((1 << X86_FEATURE_TSC)|\
-                (1 << X86_FEATURE_CX8)|\
-                (1 << X86_FEATURE_CMOV))
-        if (c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686)
-               c->x86 = 6;
-
 #ifdef CONFIG_SYSCTL
        /* randomize_va_space slows us down enormously;
           it probably triggers retranslation of x86->native bytecode */
index 2ad9a1bc6a73fafd6ea8e34b9117877eb2e736dd..c20c9e7e08dd2a644860dabc206ae1fb843ea173 100644 (file)
@@ -453,6 +453,7 @@ ENTRY(stub_execve)
        CFI_REGISTER rip, r11
        SAVE_REST
        FIXUP_TOP_OF_STACK %r11
+       movq %rsp, %rcx
        call sys_execve
        RESTORE_TOP_OF_STACK %r11
        movq %rax,RAX(%rsp)
@@ -1036,15 +1037,16 @@ ENDPROC(child_rip)
  *     rdi: name, rsi: argv, rdx: envp
  *
  * We want to fallback into:
- *     extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs regs)
+ *     extern long sys_execve(char *name, char **argv,char **envp, struct pt_regs *regs)
  *
  * do_sys_execve asm fallback arguments:
- *     rdi: name, rsi: argv, rdx: envp, fake frame on the stack
+ *     rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
  */
 ENTRY(kernel_execve)
        CFI_STARTPROC
        FAKE_STACK_FRAME $0
        SAVE_ALL        
+       movq %rsp,%rcx
        call sys_execve
        movq %rax, RAX(%rsp)    
        RESTORE_REST
index 25eb98540a41e067f7593753a51b8430fd8930df..fd8ca53943a8e0f01b86bb0157d5027de0bcf5bd 100644 (file)
@@ -606,7 +606,7 @@ ENTRY(_stext)
 .section ".bss.page_aligned","wa"
        .align PAGE_SIZE_asm
 #ifdef CONFIG_X86_PAE
-ENTRY(swapper_pg_pmd)
+swapper_pg_pmd:
        .fill 1024*KPMDS,4,0
 #else
 ENTRY(swapper_pg_dir)
index eb415043a9297d742f3df5d9a1de10fa35d0b69b..a007454133a33743b60fce4ebd3c90e8c32ee85e 100644 (file)
@@ -379,18 +379,24 @@ NEXT_PAGE(level2_ident_pgt)
        /* Since I easily can, map the first 1G.
         * Don't set NX because code runs from these pages.
         */
-       PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
+       PMDS(0, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
 
 NEXT_PAGE(level2_kernel_pgt)
-       /* 40MB kernel mapping. The kernel code cannot be bigger than that.
-          When you change this change KERNEL_TEXT_SIZE in page.h too. */
-       /* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
-       PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL, KERNEL_TEXT_SIZE/PMD_SIZE)
-       /* Module mapping starts here */
-       .fill   (PTRS_PER_PMD - (KERNEL_TEXT_SIZE/PMD_SIZE)),8,0
+       /*
+        * 128 MB kernel mapping. We spend a full page on this pagetable
+        * anyway.
+        *
+        * The kernel code+data+bss must not be bigger than that.
+        *
+        * (NOTE: at +128MB starts the module area, see MODULES_VADDR.
+        *  If you want to increase this then increase MODULES_VADDR
+        *  too.)
+        */
+       PMDS(0, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL,
+               KERNEL_IMAGE_SIZE/PMD_SIZE)
 
 NEXT_PAGE(level2_spare_pgt)
-       .fill   512,8,0
+       .fill   512, 8, 0
 
 #undef PMDS
 #undef NEXT_PAGE
index 429d084e014d4b11a829bbf01f53fdc860e276e2..235fd6c77504c9baedcfddd1610b143910e97e21 100644 (file)
@@ -368,8 +368,8 @@ static int hpet_clocksource_register(void)
        return 0;
 }
 
-/*
- * Try to setup the HPET timer
+/**
+ * hpet_enable - Try to setup the HPET timer. Returns 1 on success.
  */
 int __init hpet_enable(void)
 {
index b0cc8f0136d8096e9e4cdad316787f89d4f55a8c..43f287744f9f4351328f3cec21de5095815c526a 100644 (file)
@@ -730,16 +730,16 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
  */
 asmlinkage
 long sys_execve(char __user *name, char __user * __user *argv,
-               char __user * __user *envp, struct pt_regs regs)
+               char __user * __user *envp, struct pt_regs *regs)
 {
        long error;
        char * filename;
 
        filename = getname(name);
        error = PTR_ERR(filename);
-       if (IS_ERR(filename)) 
+       if (IS_ERR(filename))
                return error;
-       error = do_execve(filename, argv, envp, &regs); 
+       error = do_execve(filename, argv, envp, regs);
        putname(filename);
        return error;
 }
index 6fd804f0782145be3b45c223590c5c287a9bdb57..7637dc91c79bebac16365bbcff3b480c408584ef 100644 (file)
@@ -1021,7 +1021,7 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
 
        /* Clear all flags overriden by options */
        for (i = 0; i < NCAPINTS; i++)
-               c->x86_capability[i] ^= cleared_cpu_caps[i];
+               c->x86_capability[i] &= ~cleared_cpu_caps[i];
 
 #ifdef CONFIG_X86_MCE
        mcheck_init(c);
index d53bd6fcb42877106dea1c2e8500c31f2614f15a..0880f2c388a901fd318ac39856e4105b98e4d09d 100644 (file)
@@ -554,10 +554,10 @@ static int __cpuinit do_boot_cpu(int cpu, int apicid)
        int timeout;
        unsigned long start_rip;
        struct create_idle c_idle = {
-               .work = __WORK_INITIALIZER(c_idle.work, do_fork_idle),
                .cpu = cpu,
                .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
        };
+       INIT_WORK(&c_idle.work, do_fork_idle);
 
        /* allocate memory for gdts of secondary cpus. Hotplug is considered */
        if (!cpu_gdt_descr[cpu].address &&
index 02f0f61f5b1131a511851546393ef06665787507..c28c342c162f0a90d3ad6e50ba0fb1d5ecd132a7 100644 (file)
@@ -25,6 +25,8 @@ static int save_stack_stack(void *data, char *name)
 static void save_stack_address(void *data, unsigned long addr, int reliable)
 {
        struct stack_trace *trace = data;
+       if (!reliable)
+               return;
        if (trace->skip > 0) {
                trace->skip--;
                return;
@@ -37,6 +39,8 @@ static void
 save_stack_address_nosched(void *data, unsigned long addr, int reliable)
 {
        struct stack_trace *trace = (struct stack_trace *)data;
+       if (!reliable)
+               return;
        if (in_sched_functions(addr))
                return;
        if (trace->skip > 0) {
index 43517e324be83e73096fe28a39ec5275c9a378e0..f14cfd9d1f94c1a634833da25e86eea9cb43b864 100644 (file)
@@ -28,7 +28,8 @@ EXPORT_SYMBOL_GPL(tsc_khz);
 static int __init tsc_setup(char *str)
 {
        printk(KERN_WARNING "notsc: Kernel compiled with CONFIG_X86_TSC, "
-                               "cannot disable TSC.\n");
+                               "cannot disable TSC completely.\n");
+       mark_tsc_unstable("user disabled TSC");
        return 1;
 }
 #else
index 3f82427745802f0e30ff19ff5ed5aee7e50d7fa2..b6be812fac0502cd2caccc19dcec0a147a0dc3fa 100644 (file)
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 #define __syscall_clobber "r11","cx","memory"
-#define __pa_vsymbol(x)                        \
-       ({unsigned long v;              \
-       extern char __vsyscall_0;       \
-         asm("" : "=r" (v) : "0" (x)); \
-         ((v - VSYSCALL_START) + __pa_symbol(&__vsyscall_0)); })
 
 /*
  * vsyscall_gtod_data contains data that is :
@@ -102,7 +97,7 @@ static __always_inline void do_get_tz(struct timezone * tz)
 static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
 {
        int ret;
-       asm volatile("vsysc2: syscall"
+       asm volatile("syscall"
                : "=a" (ret)
                : "0" (__NR_gettimeofday),"D" (tv),"S" (tz)
                : __syscall_clobber );
@@ -112,7 +107,7 @@ static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
 static __always_inline long time_syscall(long *t)
 {
        long secs;
-       asm volatile("vsysc1: syscall"
+       asm volatile("syscall"
                : "=a" (secs)
                : "0" (__NR_time),"D" (t) : __syscall_clobber);
        return secs;
@@ -227,50 +222,10 @@ long __vsyscall(3) venosys_1(void)
 }
 
 #ifdef CONFIG_SYSCTL
-
-#define SYSCALL 0x050f
-#define NOP2    0x9090
-
-/*
- * NOP out syscall in vsyscall page when not needed.
- */
-static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
-                        void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-       extern u16 vsysc1, vsysc2;
-       u16 __iomem *map1;
-       u16 __iomem *map2;
-       int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
-       if (!write)
-               return ret;
-       /* gcc has some trouble with __va(__pa()), so just do it this
-          way. */
-       map1 = ioremap(__pa_vsymbol(&vsysc1), 2);
-       if (!map1)
-               return -ENOMEM;
-       map2 = ioremap(__pa_vsymbol(&vsysc2), 2);
-       if (!map2) {
-               ret = -ENOMEM;
-               goto out;
-       }
-       if (!vsyscall_gtod_data.sysctl_enabled) {
-               writew(SYSCALL, map1);
-               writew(SYSCALL, map2);
-       } else {
-               writew(NOP2, map1);
-               writew(NOP2, map2);
-       }
-       iounmap(map2);
-out:
-       iounmap(map1);
-       return ret;
-}
-
 static ctl_table kernel_table2[] = {
        { .procname = "vsyscall64",
          .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int),
-         .mode = 0644,
-         .proc_handler = vsyscall_sysctl_change },
+         .mode = 0644 },
        {}
 };
 
@@ -279,7 +234,6 @@ static ctl_table kernel_root_table2[] = {
          .child = kernel_table2 },
        {}
 };
-
 #endif
 
 /* Assume __initcall executes before all user space. Hopefully kmod
index 5afdde4895dcefe823e0e500df57d977a7ffa350..cccb38a59653bff74271593004f995a457645b54 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/lguest_launcher.h>
 #include <linux/virtio_console.h>
 #include <linux/pm.h>
+#include <asm/lguest.h>
 #include <asm/paravirt.h>
 #include <asm/param.h>
 #include <asm/page.h>
  * behaving in simplified but equivalent ways.  In particular, the Guest is the
  * same kernel as the Host (or at least, built from the same source code). :*/
 
-/* Declarations for definitions in lguest_guest.S */
-extern char lguest_noirq_start[], lguest_noirq_end[];
-extern const char lgstart_cli[], lgend_cli[];
-extern const char lgstart_sti[], lgend_sti[];
-extern const char lgstart_popf[], lgend_popf[];
-extern const char lgstart_pushf[], lgend_pushf[];
-extern const char lgstart_iret[], lgend_iret[];
-extern void lguest_iret(void);
-
 struct lguest_data lguest_data = {
        .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
        .noirq_start = (u32)lguest_noirq_start,
@@ -489,7 +481,7 @@ static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
 {
        *pmdp = pmdval;
        lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
-                  (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+                  (__pa(pmdp)&(PAGE_SIZE-1)), 0);
 }
 
 /* There are a couple of legacy places where the kernel sets a PTE, but we
index bb652f5a93fb9c6e73e1fa09dd97617d9c41c574..a02a14f0f324f9a3392810a46d587dfcda23a157 100644 (file)
@@ -172,8 +172,9 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot)
 }
 
 /*
- * The head.S code sets up the kernel high mapping from:
- * __START_KERNEL_map to __START_KERNEL_map + KERNEL_TEXT_SIZE
+ * The head.S code sets up the kernel high mapping:
+ *
+ *   from __START_KERNEL_map to __START_KERNEL_map + size (== _end-_text)
  *
  * phys_addr holds the negative offset to the kernel, which is added
  * to the compile time generated pmds. This results in invalid pmds up
@@ -515,14 +516,6 @@ void __init mem_init(void)
 
        /* clear_bss() already clear the empty_zero_page */
 
-       /* temporary debugging - double check it's true: */
-       {
-               int i;
-
-               for (i = 0; i < 1024; i++)
-                       WARN_ON_ONCE(empty_zero_page[i]);
-       }
-
        reservedpages = 0;
 
        /* this will put all low memory onto the freelists */
index 464d8fc21ce69b67d8d8bf057f5a57ef6a84c677..14e48b5a94ba193c1cb4acc667482e05905d373e 100644 (file)
@@ -44,6 +44,12 @@ static inline unsigned long highmap_end_pfn(void)
 
 #endif
 
+#ifdef CONFIG_DEBUG_PAGEALLOC
+# define debug_pagealloc 1
+#else
+# define debug_pagealloc 0
+#endif
+
 static inline int
 within(unsigned long addr, unsigned long start, unsigned long end)
 {
@@ -355,45 +361,48 @@ out_unlock:
 
 static LIST_HEAD(page_pool);
 static unsigned long pool_size, pool_pages, pool_low;
-static unsigned long pool_used, pool_failed, pool_refill;
+static unsigned long pool_used, pool_failed;
 
-static void cpa_fill_pool(void)
+static void cpa_fill_pool(struct page **ret)
 {
-       struct page *p;
        gfp_t gfp = GFP_KERNEL;
+       unsigned long flags;
+       struct page *p;
 
-       /* Do not allocate from interrupt context */
-       if (in_irq() || irqs_disabled())
-               return;
        /*
-        * Check unlocked. I does not matter when we have one more
-        * page in the pool. The bit lock avoids recursive pool
-        * allocations:
+        * Avoid recursion (on debug-pagealloc) and also signal
+        * our priority to get to these pagetables:
         */
-       if (pool_pages >= pool_size || test_and_set_bit_lock(0, &pool_refill))
+       if (current->flags & PF_MEMALLOC)
                return;
+       current->flags |= PF_MEMALLOC;
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
        /*
-        * We could do:
-        * gfp = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
-        * but this fails on !PREEMPT kernels
+        * Allocate atomically from atomic contexts:
         */
-       gfp =  GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
-#endif
+       if (in_atomic() || irqs_disabled() || debug_pagealloc)
+               gfp =  GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
 
-       while (pool_pages < pool_size) {
+       while (pool_pages < pool_size || (ret && !*ret)) {
                p = alloc_pages(gfp, 0);
                if (!p) {
                        pool_failed++;
                        break;
                }
-               spin_lock_irq(&pgd_lock);
+               /*
+                * If the call site needs a page right now, provide it:
+                */
+               if (ret && !*ret) {
+                       *ret = p;
+                       continue;
+               }
+               spin_lock_irqsave(&pgd_lock, flags);
                list_add(&p->lru, &page_pool);
                pool_pages++;
-               spin_unlock_irq(&pgd_lock);
+               spin_unlock_irqrestore(&pgd_lock, flags);
        }
-       clear_bit_unlock(0, &pool_refill);
+
+       current->flags &= ~PF_MEMALLOC;
 }
 
 #define SHIFT_MB               (20 - PAGE_SHIFT)
@@ -414,11 +423,15 @@ void __init cpa_init(void)
         * GiB. Shift MiB to Gib and multiply the result by
         * POOL_PAGES_PER_GB:
         */
-       gb = ((si.totalram >> SHIFT_MB) + ROUND_MB_GB) >> SHIFT_MB_GB;
-       pool_size = POOL_PAGES_PER_GB * gb;
+       if (debug_pagealloc) {
+               gb = ((si.totalram >> SHIFT_MB) + ROUND_MB_GB) >> SHIFT_MB_GB;
+               pool_size = POOL_PAGES_PER_GB * gb;
+       } else {
+               pool_size = 1;
+       }
        pool_low = pool_size;
 
-       cpa_fill_pool();
+       cpa_fill_pool(NULL);
        printk(KERN_DEBUG
               "CPA: page pool initialized %lu of %lu pages preallocated\n",
               pool_pages, pool_size);
@@ -440,16 +453,20 @@ static int split_large_page(pte_t *kpte, unsigned long address)
        spin_lock_irqsave(&pgd_lock, flags);
        if (list_empty(&page_pool)) {
                spin_unlock_irqrestore(&pgd_lock, flags);
-               return -ENOMEM;
+               base = NULL;
+               cpa_fill_pool(&base);
+               if (!base)
+                       return -ENOMEM;
+               spin_lock_irqsave(&pgd_lock, flags);
+       } else {
+               base = list_first_entry(&page_pool, struct page, lru);
+               list_del(&base->lru);
+               pool_pages--;
+
+               if (pool_pages < pool_low)
+                       pool_low = pool_pages;
        }
 
-       base = list_first_entry(&page_pool, struct page, lru);
-       list_del(&base->lru);
-       pool_pages--;
-
-       if (pool_pages < pool_low)
-               pool_low = pool_pages;
-
        /*
         * Check for races, another CPU might have split this page
         * up for us already:
@@ -734,7 +751,8 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages,
                cpa_flush_all(cache);
 
 out:
-       cpa_fill_pool();
+       cpa_fill_pool(NULL);
+
        return ret;
 }
 
@@ -897,7 +915,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
         * Try to refill the page pool here. We can do this only after
         * the tlb flush.
         */
-       cpa_fill_pool();
+       cpa_fill_pool(NULL);
 }
 
 #ifdef CONFIG_HIBERNATION
index f385a4b4a484e36d3262ca154b96dcfd596b7510..b8bd0c4aa02e4d0bae958c2fec0fa492c49ca583 100644 (file)
@@ -48,7 +48,7 @@ obj-$(VDSO64-y)                       += vdso-syms.lds
 # Match symbols in the DSO that look like VDSO*; produce a file of constants.
 #
 sed-vdsosym := -e 's/^00*/0/' \
-       -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p'
+       -e 's/^\([[:xdigit:]]*\) . \(VDSO[[:alnum:]_]*\)$$/\2 = 0x\1;/p'
 quiet_cmd_vdsosym = VDSOSYM $@
       cmd_vdsosym = $(NM) $< | sed -n $(sed-vdsosym) | LC_ALL=C sort > $@
 
index 7e73cbaa4121047ffe6eb7c5f137357e0739c58e..46bc197a047fe84329f4ec868e351ae0438cac2e 100644 (file)
@@ -109,15 +109,17 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
        struct client *client;
        unsigned long flags;
 
-       device = fw_device_from_devt(inode->i_rdev);
+       device = fw_device_get_by_devt(inode->i_rdev);
        if (device == NULL)
                return -ENODEV;
 
        client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (client == NULL)
+       if (client == NULL) {
+               fw_device_put(device);
                return -ENOMEM;
+       }
 
-       client->device = fw_device_get(device);
+       client->device = device;
        INIT_LIST_HEAD(&client->event_list);
        INIT_LIST_HEAD(&client->resource_list);
        spin_lock_init(&client->lock);
@@ -644,6 +646,10 @@ static int ioctl_create_iso_context(struct client *client, void *buffer)
        struct fw_cdev_create_iso_context *request = buffer;
        struct fw_iso_context *context;
 
+       /* We only support one context at this time. */
+       if (client->iso_context != NULL)
+               return -EBUSY;
+
        if (request->channel > 63)
                return -EINVAL;
 
@@ -790,8 +796,9 @@ static int ioctl_start_iso(struct client *client, void *buffer)
 {
        struct fw_cdev_start_iso *request = buffer;
 
-       if (request->handle != 0)
+       if (client->iso_context == NULL || request->handle != 0)
                return -EINVAL;
+
        if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
                if (request->tags == 0 || request->tags > 15)
                        return -EINVAL;
@@ -808,7 +815,7 @@ static int ioctl_stop_iso(struct client *client, void *buffer)
 {
        struct fw_cdev_stop_iso *request = buffer;
 
-       if (request->handle != 0)
+       if (client->iso_context == NULL || request->handle != 0)
                return -EINVAL;
 
        return fw_iso_context_stop(client->iso_context);
index de9066e69adfbeea440d31cec1c0945f337db728..2ab13e0f3469c2f3ccd4b68d120be57f4107c3a6 100644 (file)
@@ -358,12 +358,9 @@ static ssize_t
 guid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct fw_device *device = fw_device(dev);
-       u64 guid;
 
-       guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
-
-       return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
-                       (unsigned long long)guid);
+       return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n",
+                       device->config_rom[3], device->config_rom[4]);
 }
 
 static struct device_attribute fw_device_attributes[] = {
@@ -610,12 +607,14 @@ static DECLARE_RWSEM(idr_rwsem);
 static DEFINE_IDR(fw_device_idr);
 int fw_cdev_major;
 
-struct fw_device *fw_device_from_devt(dev_t devt)
+struct fw_device *fw_device_get_by_devt(dev_t devt)
 {
        struct fw_device *device;
 
        down_read(&idr_rwsem);
        device = idr_find(&fw_device_idr, MINOR(devt));
+       if (device)
+               fw_device_get(device);
        up_read(&idr_rwsem);
 
        return device;
@@ -627,13 +626,14 @@ static void fw_device_shutdown(struct work_struct *work)
                container_of(work, struct fw_device, work.work);
        int minor = MINOR(device->device.devt);
 
-       down_write(&idr_rwsem);
-       idr_remove(&fw_device_idr, minor);
-       up_write(&idr_rwsem);
-
        fw_device_cdev_remove(device);
        device_for_each_child(&device->device, NULL, shutdown_unit);
        device_unregister(&device->device);
+
+       down_write(&idr_rwsem);
+       idr_remove(&fw_device_idr, minor);
+       up_write(&idr_rwsem);
+       fw_device_put(device);
 }
 
 static struct device_type fw_device_type = {
@@ -682,10 +682,13 @@ static void fw_device_init(struct work_struct *work)
        }
 
        err = -ENOMEM;
+
+       fw_device_get(device);
        down_write(&idr_rwsem);
        if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
                err = idr_get_new(&fw_device_idr, device, &minor);
        up_write(&idr_rwsem);
+
        if (err < 0)
                goto error;
 
@@ -717,13 +720,22 @@ static void fw_device_init(struct work_struct *work)
         */
        if (atomic_cmpxchg(&device->state,
                    FW_DEVICE_INITIALIZING,
-                   FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
+                   FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) {
                fw_device_shutdown(&device->work.work);
-       else
-               fw_notify("created new fw device %s "
-                         "(%d config rom retries, S%d00)\n",
-                         device->device.bus_id, device->config_rom_retries,
-                         1 << device->max_speed);
+       } else {
+               if (device->config_rom_retries)
+                       fw_notify("created device %s: GUID %08x%08x, S%d00, "
+                                 "%d config ROM retries\n",
+                                 device->device.bus_id,
+                                 device->config_rom[3], device->config_rom[4],
+                                 1 << device->max_speed,
+                                 device->config_rom_retries);
+               else
+                       fw_notify("created device %s: GUID %08x%08x, S%d00\n",
+                                 device->device.bus_id,
+                                 device->config_rom[3], device->config_rom[4],
+                                 1 << device->max_speed);
+       }
 
        /*
         * Reschedule the IRM work if we just finished reading the
@@ -741,7 +753,9 @@ static void fw_device_init(struct work_struct *work)
        idr_remove(&fw_device_idr, minor);
        up_write(&idr_rwsem);
  error:
-       put_device(&device->device);
+       fw_device_put(device);          /* fw_device_idr's reference */
+
+       put_device(&device->device);    /* our reference */
 }
 
 static int update_unit(struct device *dev, void *data)
index 0854fe2bc11085943d0b7edcdef5884d8996c60c..43808c02793e27682892da07ecfd1f5750a396e4 100644 (file)
@@ -77,13 +77,13 @@ fw_device_is_shutdown(struct fw_device *device)
 }
 
 struct fw_device *fw_device_get(struct fw_device *device);
+struct fw_device *fw_device_get_by_devt(dev_t devt);
 void fw_device_put(struct fw_device *device);
 int fw_device_enable_phys_dma(struct fw_device *device);
 
 void fw_device_cdev_update(struct fw_device *device);
 void fw_device_cdev_remove(struct fw_device *device);
 
-struct fw_device *fw_device_from_devt(dev_t devt);
 extern int fw_cdev_major;
 
 struct fw_unit {
index 19ece9b6d7425906d6cff48cee2ebfba172f5141..5259491580fccc8fa47a42fcad98b469441522e6 100644 (file)
  * and many others.
  */
 
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/mod_devicetable.h>
-#include <linux/device.h>
 #include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/blkdev.h>
 #include <linux/string.h>
 #include <linux/stringify.h>
 #include <linux/timer.h>
@@ -47,9 +48,9 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 
-#include "fw-transaction.h"
-#include "fw-topology.h"
 #include "fw-device.h"
+#include "fw-topology.h"
+#include "fw-transaction.h"
 
 /*
  * So far only bridges from Oxford Semiconductor are known to support
@@ -82,6 +83,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
  *   Don't use this with devices which don't have this bug.
  *
+ * - delay inquiry
+ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
+ *
  * - override internal blacklist
  *   Instead of adding to the built-in blacklist, use only the workarounds
  *   specified in the module load parameter.
@@ -91,6 +95,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
 #define SBP2_WORKAROUND_INQUIRY_36     0x2
 #define SBP2_WORKAROUND_MODE_SENSE_8   0x4
 #define SBP2_WORKAROUND_FIX_CAPACITY   0x8
+#define SBP2_WORKAROUND_DELAY_INQUIRY  0x10
+#define SBP2_INQUIRY_DELAY             12
 #define SBP2_WORKAROUND_OVERRIDE       0x100
 
 static int sbp2_param_workarounds;
@@ -100,6 +106,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
        ", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
        ", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
        ", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+       ", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
        ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
        ", or a combination)");
 
@@ -132,6 +139,7 @@ struct sbp2_logical_unit {
        int generation;
        int retries;
        struct delayed_work work;
+       bool blocked;
 };
 
 /*
@@ -141,16 +149,18 @@ struct sbp2_logical_unit {
 struct sbp2_target {
        struct kref kref;
        struct fw_unit *unit;
+       const char *bus_id;
+       struct list_head lu_list;
 
        u64 management_agent_address;
        int directory_id;
        int node_id;
        int address_high;
-
-       unsigned workarounds;
-       struct list_head lu_list;
-
+       unsigned int workarounds;
        unsigned int mgt_orb_timeout;
+
+       int dont_block; /* counter for each logical unit */
+       int blocked;    /* ditto */
 };
 
 /*
@@ -160,7 +170,7 @@ struct sbp2_target {
  */
 #define SBP2_MIN_LOGIN_ORB_TIMEOUT     5000U   /* Timeout in ms */
 #define SBP2_MAX_LOGIN_ORB_TIMEOUT     40000U  /* Timeout in ms */
-#define SBP2_ORB_TIMEOUT               2000    /* Timeout in ms */
+#define SBP2_ORB_TIMEOUT               2000U   /* Timeout in ms */
 #define SBP2_ORB_NULL                  0x80000000
 #define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
 
@@ -297,7 +307,7 @@ struct sbp2_command_orb {
 static const struct {
        u32 firmware_revision;
        u32 model;
-       unsigned workarounds;
+       unsigned int workarounds;
 } sbp2_workarounds_table[] = {
        /* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
                .firmware_revision      = 0x002800,
@@ -305,6 +315,11 @@ static const struct {
                .workarounds            = SBP2_WORKAROUND_INQUIRY_36 |
                                          SBP2_WORKAROUND_MODE_SENSE_8,
        },
+       /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
+               .firmware_revision      = 0x002800,
+               .model                  = 0x000000,
+               .workarounds            = SBP2_WORKAROUND_DELAY_INQUIRY,
+       },
        /* Initio bridges, actually only needed for some older ones */ {
                .firmware_revision      = 0x000200,
                .model                  = ~0,
@@ -501,6 +516,9 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
        unsigned int timeout;
        int retval = -ENOMEM;
 
+       if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device))
+               return 0;
+
        orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
        if (orb == NULL)
                return -ENOMEM;
@@ -553,20 +571,20 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
 
        retval = -EIO;
        if (sbp2_cancel_orbs(lu) == 0) {
-               fw_error("orb reply timed out, rcode=0x%02x\n",
-                        orb->base.rcode);
+               fw_error("%s: orb reply timed out, rcode=0x%02x\n",
+                        lu->tgt->bus_id, orb->base.rcode);
                goto out;
        }
 
        if (orb->base.rcode != RCODE_COMPLETE) {
-               fw_error("management write failed, rcode 0x%02x\n",
-                        orb->base.rcode);
+               fw_error("%s: management write failed, rcode 0x%02x\n",
+                        lu->tgt->bus_id, orb->base.rcode);
                goto out;
        }
 
        if (STATUS_GET_RESPONSE(orb->status) != 0 ||
            STATUS_GET_SBP_STATUS(orb->status) != 0) {
-               fw_error("error status: %d:%d\n",
+               fw_error("%s: error status: %d:%d\n", lu->tgt->bus_id,
                         STATUS_GET_RESPONSE(orb->status),
                         STATUS_GET_SBP_STATUS(orb->status));
                goto out;
@@ -590,29 +608,147 @@ sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
 
 static void
 complete_agent_reset_write(struct fw_card *card, int rcode,
-                          void *payload, size_t length, void *data)
+                          void *payload, size_t length, void *done)
+{
+       complete(done);
+}
+
+static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
 {
-       struct fw_transaction *t = data;
+       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       DECLARE_COMPLETION_ONSTACK(done);
+       struct fw_transaction t;
+       static u32 z;
+
+       fw_send_request(device->card, &t, TCODE_WRITE_QUADLET_REQUEST,
+                       lu->tgt->node_id, lu->generation, device->max_speed,
+                       lu->command_block_agent_address + SBP2_AGENT_RESET,
+                       &z, sizeof(z), complete_agent_reset_write, &done);
+       wait_for_completion(&done);
+}
 
-       kfree(t);
+static void
+complete_agent_reset_write_no_wait(struct fw_card *card, int rcode,
+                                  void *payload, size_t length, void *data)
+{
+       kfree(data);
 }
 
-static int sbp2_agent_reset(struct sbp2_logical_unit *lu)
+static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
 {
        struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
        struct fw_transaction *t;
-       static u32 zero;
+       static u32 z;
 
-       t = kzalloc(sizeof(*t), GFP_ATOMIC);
+       t = kmalloc(sizeof(*t), GFP_ATOMIC);
        if (t == NULL)
-               return -ENOMEM;
+               return;
 
        fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
                        lu->tgt->node_id, lu->generation, device->max_speed,
                        lu->command_block_agent_address + SBP2_AGENT_RESET,
-                       &zero, sizeof(zero), complete_agent_reset_write, t);
+                       &z, sizeof(z), complete_agent_reset_write_no_wait, t);
+}
 
-       return 0;
+static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation)
+{
+       struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card;
+       unsigned long flags;
+
+       /* serialize with comparisons of lu->generation and card->generation */
+       spin_lock_irqsave(&card->lock, flags);
+       lu->generation = generation;
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
+{
+       /*
+        * We may access dont_block without taking card->lock here:
+        * All callers of sbp2_allow_block() and all callers of sbp2_unblock()
+        * are currently serialized against each other.
+        * And a wrong result in sbp2_conditionally_block()'s access of
+        * dont_block is rather harmless, it simply misses its first chance.
+        */
+       --lu->tgt->dont_block;
+}
+
+/*
+ * Blocks lu->tgt if all of the following conditions are met:
+ *   - Login, INQUIRY, and high-level SCSI setup of all of the target's
+ *     logical units have been finished (indicated by dont_block == 0).
+ *   - lu->generation is stale.
+ *
+ * Note, scsi_block_requests() must be called while holding card->lock,
+ * otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to
+ * unblock the target.
+ */
+static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
+{
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct Scsi_Host *shost =
+               container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (!tgt->dont_block && !lu->blocked &&
+           lu->generation != card->generation) {
+               lu->blocked = true;
+               if (++tgt->blocked == 1) {
+                       scsi_block_requests(shost);
+                       fw_notify("blocked %s\n", lu->tgt->bus_id);
+               }
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/*
+ * Unblocks lu->tgt as soon as all its logical units can be unblocked.
+ * Note, it is harmless to run scsi_unblock_requests() outside the
+ * card->lock protected section.  On the other hand, running it inside
+ * the section might clash with shost->host_lock.
+ */
+static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
+{
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct Scsi_Host *shost =
+               container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+       unsigned long flags;
+       bool unblock = false;
+
+       spin_lock_irqsave(&card->lock, flags);
+       if (lu->blocked && lu->generation == card->generation) {
+               lu->blocked = false;
+               unblock = --tgt->blocked == 0;
+       }
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       if (unblock) {
+               scsi_unblock_requests(shost);
+               fw_notify("unblocked %s\n", lu->tgt->bus_id);
+       }
+}
+
+/*
+ * Prevents future blocking of tgt and unblocks it.
+ * Note, it is harmless to run scsi_unblock_requests() outside the
+ * card->lock protected section.  On the other hand, running it inside
+ * the section might clash with shost->host_lock.
+ */
+static void sbp2_unblock(struct sbp2_target *tgt)
+{
+       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct Scsi_Host *shost =
+               container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
+       unsigned long flags;
+
+       spin_lock_irqsave(&card->lock, flags);
+       ++tgt->dont_block;
+       spin_unlock_irqrestore(&card->lock, flags);
+
+       scsi_unblock_requests(shost);
 }
 
 static void sbp2_release_target(struct kref *kref)
@@ -621,23 +757,24 @@ static void sbp2_release_target(struct kref *kref)
        struct sbp2_logical_unit *lu, *next;
        struct Scsi_Host *shost =
                container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
-       struct fw_device *device = fw_device(tgt->unit->device.parent);
+
+       /* prevent deadlocks */
+       sbp2_unblock(tgt);
 
        list_for_each_entry_safe(lu, next, &tgt->lu_list, link) {
-               if (lu->sdev)
+               if (lu->sdev) {
                        scsi_remove_device(lu->sdev);
-
-               if (!fw_device_is_shutdown(device))
-                       sbp2_send_management_orb(lu, tgt->node_id,
-                                       lu->generation, SBP2_LOGOUT_REQUEST,
-                                       lu->login_id, NULL);
+                       scsi_device_put(lu->sdev);
+               }
+               sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
+                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
 
                fw_core_remove_address_handler(&lu->address_handler);
                list_del(&lu->link);
                kfree(lu);
        }
        scsi_remove_host(shost);
-       fw_notify("released %s\n", tgt->unit->device.bus_id);
+       fw_notify("released %s\n", tgt->bus_id);
 
        put_device(&tgt->unit->device);
        scsi_host_put(shost);
@@ -666,33 +803,43 @@ static void sbp2_login(struct work_struct *work)
 {
        struct sbp2_logical_unit *lu =
                container_of(work, struct sbp2_logical_unit, work.work);
-       struct Scsi_Host *shost =
-               container_of((void *)lu->tgt, struct Scsi_Host, hostdata[0]);
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_device *device = fw_device(tgt->unit->device.parent);
+       struct Scsi_Host *shost;
        struct scsi_device *sdev;
        struct scsi_lun eight_bytes_lun;
-       struct fw_unit *unit = lu->tgt->unit;
-       struct fw_device *device = fw_device(unit->device.parent);
        struct sbp2_login_response response;
        int generation, node_id, local_node_id;
 
+       if (fw_device_is_shutdown(device))
+               goto out;
+
        generation    = device->generation;
        smp_rmb();    /* node_id must not be older than generation */
        node_id       = device->node_id;
        local_node_id = device->card->node_id;
 
+       /* If this is a re-login attempt, log out, or we might be rejected. */
+       if (lu->sdev)
+               sbp2_send_management_orb(lu, device->node_id, generation,
+                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+
        if (sbp2_send_management_orb(lu, node_id, generation,
                                SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) {
-               if (lu->retries++ < 5)
+               if (lu->retries++ < 5) {
                        sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
-               else
-                       fw_error("failed to login to %s LUN %04x\n",
-                                unit->device.bus_id, lu->lun);
+               } else {
+                       fw_error("%s: failed to login to LUN %04x\n",
+                                tgt->bus_id, lu->lun);
+                       /* Let any waiting I/O fail from now on. */
+                       sbp2_unblock(lu->tgt);
+               }
                goto out;
        }
 
-       lu->generation        = generation;
-       lu->tgt->node_id      = node_id;
-       lu->tgt->address_high = local_node_id << 16;
+       tgt->node_id      = node_id;
+       tgt->address_high = local_node_id << 16;
+       sbp2_set_generation(lu, generation);
 
        /* Get command block agent offset and login id. */
        lu->command_block_agent_address =
@@ -700,8 +847,8 @@ static void sbp2_login(struct work_struct *work)
                response.command_block_agent.low;
        lu->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
 
-       fw_notify("logged in to %s LUN %04x (%d retries)\n",
-                 unit->device.bus_id, lu->lun, lu->retries);
+       fw_notify("%s: logged in to LUN %04x (%d retries)\n",
+                 tgt->bus_id, lu->lun, lu->retries);
 
 #if 0
        /* FIXME: The linux1394 sbp2 does this last step. */
@@ -711,26 +858,62 @@ static void sbp2_login(struct work_struct *work)
        PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
        sbp2_agent_reset(lu);
 
+       /* This was a re-login. */
+       if (lu->sdev) {
+               sbp2_cancel_orbs(lu);
+               sbp2_conditionally_unblock(lu);
+               goto out;
+       }
+
+       if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
+               ssleep(SBP2_INQUIRY_DELAY);
+
        memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun));
        eight_bytes_lun.scsi_lun[0] = (lu->lun >> 8) & 0xff;
        eight_bytes_lun.scsi_lun[1] = lu->lun & 0xff;
+       shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
 
        sdev = __scsi_add_device(shost, 0, 0,
                                 scsilun_to_int(&eight_bytes_lun), lu);
-       if (IS_ERR(sdev)) {
-               sbp2_send_management_orb(lu, node_id, generation,
-                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
-               /*
-                * Set this back to sbp2_login so we fall back and
-                * retry login on bus reset.
-                */
-               PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
-       } else {
-               lu->sdev = sdev;
+       /*
+        * FIXME:  We are unable to perform reconnects while in sbp2_login().
+        * Therefore __scsi_add_device() will get into trouble if a bus reset
+        * happens in parallel.  It will either fail or leave us with an
+        * unusable sdev.  As a workaround we check for this and retry the
+        * whole login and SCSI probing.
+        */
+
+       /* Reported error during __scsi_add_device() */
+       if (IS_ERR(sdev))
+               goto out_logout_login;
+
+       /* Unreported error during __scsi_add_device() */
+       smp_rmb(); /* get current card generation */
+       if (generation != device->card->generation) {
+               scsi_remove_device(sdev);
                scsi_device_put(sdev);
+               goto out_logout_login;
        }
+
+       /* No error during __scsi_add_device() */
+       lu->sdev = sdev;
+       sbp2_allow_block(lu);
+       goto out;
+
+ out_logout_login:
+       smp_rmb(); /* generation may have changed */
+       generation = device->generation;
+       smp_rmb(); /* node_id must not be older than generation */
+
+       sbp2_send_management_orb(lu, device->node_id, generation,
+                                SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
+       /*
+        * If a bus reset happened, sbp2_update will have requeued
+        * lu->work already.  Reset the work from reconnect to login.
+        */
+       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
  out:
-       sbp2_target_put(lu->tgt);
+       sbp2_target_put(tgt);
 }
 
 static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
@@ -755,6 +938,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
        lu->sdev = NULL;
        lu->lun  = lun_entry & 0xffff;
        lu->retries = 0;
+       lu->blocked = false;
+       ++tgt->dont_block;
        INIT_LIST_HEAD(&lu->orb_list);
        INIT_DELAYED_WORK(&lu->work, sbp2_login);
 
@@ -813,7 +998,7 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
                        if (timeout > tgt->mgt_orb_timeout)
                                fw_notify("%s: config rom contains %ds "
                                          "management ORB timeout, limiting "
-                                         "to %ds\n", tgt->unit->device.bus_id,
+                                         "to %ds\n", tgt->bus_id,
                                          timeout / 1000,
                                          tgt->mgt_orb_timeout / 1000);
                        break;
@@ -836,12 +1021,12 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
                                  u32 firmware_revision)
 {
        int i;
-       unsigned w = sbp2_param_workarounds;
+       unsigned int w = sbp2_param_workarounds;
 
        if (w)
                fw_notify("Please notify linux1394-devel@lists.sourceforge.net "
                          "if you need the workarounds parameter for %s\n",
-                         tgt->unit->device.bus_id);
+                         tgt->bus_id);
 
        if (w & SBP2_WORKAROUND_OVERRIDE)
                goto out;
@@ -863,8 +1048,7 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
        if (w)
                fw_notify("Workarounds for %s: 0x%x "
                          "(firmware_revision 0x%06x, model_id 0x%06x)\n",
-                         tgt->unit->device.bus_id,
-                         w, firmware_revision, model);
+                         tgt->bus_id, w, firmware_revision, model);
        tgt->workarounds = w;
 }
 
@@ -888,6 +1072,7 @@ static int sbp2_probe(struct device *dev)
        tgt->unit = unit;
        kref_init(&tgt->kref);
        INIT_LIST_HEAD(&tgt->lu_list);
+       tgt->bus_id = unit->device.bus_id;
 
        if (fw_device_enable_phys_dma(device) < 0)
                goto fail_shost_put;
@@ -938,10 +1123,13 @@ static void sbp2_reconnect(struct work_struct *work)
 {
        struct sbp2_logical_unit *lu =
                container_of(work, struct sbp2_logical_unit, work.work);
-       struct fw_unit *unit = lu->tgt->unit;
-       struct fw_device *device = fw_device(unit->device.parent);
+       struct sbp2_target *tgt = lu->tgt;
+       struct fw_device *device = fw_device(tgt->unit->device.parent);
        int generation, node_id, local_node_id;
 
+       if (fw_device_is_shutdown(device))
+               goto out;
+
        generation    = device->generation;
        smp_rmb();    /* node_id must not be older than generation */
        node_id       = device->node_id;
@@ -950,10 +1138,17 @@ static void sbp2_reconnect(struct work_struct *work)
        if (sbp2_send_management_orb(lu, node_id, generation,
                                     SBP2_RECONNECT_REQUEST,
                                     lu->login_id, NULL) < 0) {
-               if (lu->retries++ >= 5) {
-                       fw_error("failed to reconnect to %s\n",
-                                unit->device.bus_id);
-                       /* Fall back and try to log in again. */
+               /*
+                * If reconnect was impossible even though we are in the
+                * current generation, fall back and try to log in again.
+                *
+                * We could check for "Function rejected" status, but
+                * looking at the bus generation as simpler and more general.
+                */
+               smp_rmb(); /* get current card generation */
+               if (generation == device->card->generation ||
+                   lu->retries++ >= 5) {
+                       fw_error("%s: failed to reconnect\n", tgt->bus_id);
                        lu->retries = 0;
                        PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
                }
@@ -961,17 +1156,18 @@ static void sbp2_reconnect(struct work_struct *work)
                goto out;
        }
 
-       lu->generation        = generation;
-       lu->tgt->node_id      = node_id;
-       lu->tgt->address_high = local_node_id << 16;
+       tgt->node_id      = node_id;
+       tgt->address_high = local_node_id << 16;
+       sbp2_set_generation(lu, generation);
 
-       fw_notify("reconnected to %s LUN %04x (%d retries)\n",
-                 unit->device.bus_id, lu->lun, lu->retries);
+       fw_notify("%s: reconnected to LUN %04x (%d retries)\n",
+                 tgt->bus_id, lu->lun, lu->retries);
 
        sbp2_agent_reset(lu);
        sbp2_cancel_orbs(lu);
+       sbp2_conditionally_unblock(lu);
  out:
-       sbp2_target_put(lu->tgt);
+       sbp2_target_put(tgt);
 }
 
 static void sbp2_update(struct fw_unit *unit)
@@ -986,6 +1182,7 @@ static void sbp2_update(struct fw_unit *unit)
         * Iteration over tgt->lu_list is therefore safe here.
         */
        list_for_each_entry(lu, &tgt->lu_list, link) {
+               sbp2_conditionally_block(lu);
                lu->retries = 0;
                sbp2_queue_work(lu, 0);
        }
@@ -1063,7 +1260,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
 
        if (status != NULL) {
                if (STATUS_GET_DEAD(*status))
-                       sbp2_agent_reset(orb->lu);
+                       sbp2_agent_reset_no_wait(orb->lu);
 
                switch (STATUS_GET_RESPONSE(*status)) {
                case SBP2_STATUS_REQUEST_COMPLETE:
@@ -1089,6 +1286,7 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
                 * or when sending the write (less likely).
                 */
                result = DID_BUS_BUSY << 16;
+               sbp2_conditionally_block(orb->lu);
        }
 
        dma_unmap_single(device->card->device, orb->base.request_bus,
@@ -1197,7 +1395,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
        struct sbp2_logical_unit *lu = cmd->device->hostdata;
        struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
        struct sbp2_command_orb *orb;
-       unsigned max_payload;
+       unsigned int max_payload;
        int retval = SCSI_MLQUEUE_HOST_BUSY;
 
        /*
@@ -1275,6 +1473,10 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
 {
        struct sbp2_logical_unit *lu = sdev->hostdata;
 
+       /* (Re-)Adding logical units via the SCSI stack is not supported. */
+       if (!lu)
+               return -ENOSYS;
+
        sdev->allow_restart = 1;
 
        /*
@@ -1319,7 +1521,7 @@ static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
 {
        struct sbp2_logical_unit *lu = cmd->device->hostdata;
 
-       fw_notify("sbp2_scsi_abort\n");
+       fw_notify("%s: sbp2_scsi_abort\n", lu->tgt->bus_id);
        sbp2_agent_reset(lu);
        sbp2_cancel_orbs(lu);
 
index 28e155a9e2a5a6bc8e424e2e1dc235f94fac2c26..9e2b1964d71add2103a735164cc7560de5ca3b38 100644 (file)
@@ -183,6 +183,9 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
  *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
  *   Don't use this with devices which don't have this bug.
  *
+ * - delay inquiry
+ *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
+ *
  * - override internal blacklist
  *   Instead of adding to the built-in blacklist, use only the workarounds
  *   specified in the module load parameter.
@@ -195,6 +198,7 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
        ", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)
        ", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)
        ", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
+       ", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
        ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
        ", or a combination)");
 
@@ -357,6 +361,11 @@ static const struct {
                .workarounds            = SBP2_WORKAROUND_INQUIRY_36 |
                                          SBP2_WORKAROUND_MODE_SENSE_8,
        },
+       /* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
+               .firmware_revision      = 0x002800,
+               .model_id               = 0x000000,
+               .workarounds            = SBP2_WORKAROUND_DELAY_INQUIRY,
+       },
        /* Initio bridges, actually only needed for some older ones */ {
                .firmware_revision      = 0x000200,
                .model_id               = SBP2_ROM_VALUE_WILDCARD,
@@ -914,6 +923,9 @@ static int sbp2_start_device(struct sbp2_lu *lu)
        sbp2_agent_reset(lu, 1);
        sbp2_max_speed_and_size(lu);
 
+       if (lu->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY)
+               ssleep(SBP2_INQUIRY_DELAY);
+
        error = scsi_add_device(lu->shost, 0, lu->ud->id, 0);
        if (error) {
                SBP2_ERR("scsi_add_device failed");
@@ -1962,6 +1974,9 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
 {
        struct sbp2_lu *lu = (struct sbp2_lu *)sdev->host->hostdata[0];
 
+       if (sdev->lun != 0 || sdev->id != lu->ud->id || sdev->channel != 0)
+               return -ENODEV;
+
        lu->sdev = sdev;
        sdev->allow_restart = 1;
 
index d2ecb0d8a1bba4e577eef7c03dbcbb8df5ee0eee..80d8e097b0651487a17d8b6e1fd5105ce79706aa 100644 (file)
@@ -343,6 +343,8 @@ enum sbp2lu_state_types {
 #define SBP2_WORKAROUND_INQUIRY_36     0x2
 #define SBP2_WORKAROUND_MODE_SENSE_8   0x4
 #define SBP2_WORKAROUND_FIX_CAPACITY   0x8
+#define SBP2_WORKAROUND_DELAY_INQUIRY  0x10
+#define SBP2_INQUIRY_DELAY             12
 #define SBP2_WORKAROUND_OVERRIDE       0x100
 
 #endif /* SBP2_H */
index 96ee899d65020e76e5c0c8d49b0683c74214ebed..91a1bd67ac1d6dd58da1d3db5c0691cdb7ea7525 100644 (file)
@@ -314,9 +314,12 @@ static int proc_pid_schedstat(struct task_struct *task, char *buffer)
 static int lstats_show_proc(struct seq_file *m, void *v)
 {
        int i;
-       struct task_struct *task = m->private;
-       seq_puts(m, "Latency Top version : v0.1\n");
+       struct inode *inode = m->private;
+       struct task_struct *task = get_proc_task(inode);
 
+       if (!task)
+               return -ESRCH;
+       seq_puts(m, "Latency Top version : v0.1\n");
        for (i = 0; i < 32; i++) {
                if (task->latency_record[i].backtrace[0]) {
                        int q;
@@ -341,32 +344,24 @@ static int lstats_show_proc(struct seq_file *m, void *v)
                }
 
        }
+       put_task_struct(task);
        return 0;
 }
 
 static int lstats_open(struct inode *inode, struct file *file)
 {
-       int ret;
-       struct seq_file *m;
-       struct task_struct *task = get_proc_task(inode);
-
-       ret = single_open(file, lstats_show_proc, NULL);
-       if (!ret) {
-               m = file->private_data;
-               m->private = task;
-       }
-       return ret;
+       return single_open(file, lstats_show_proc, inode);
 }
 
 static ssize_t lstats_write(struct file *file, const char __user *buf,
                            size_t count, loff_t *offs)
 {
-       struct seq_file *m;
-       struct task_struct *task;
+       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
 
-       m = file->private_data;
-       task = m->private;
+       if (!task)
+               return -ESRCH;
        clear_all_latency_tracing(task);
+       put_task_struct(task);
 
        return count;
 }
index cd9f894dd2d7c778fe4d85fdeb0f83168a16804d..c9952ea9f6980cdb3620470ff285c59e28f8acd2 100644 (file)
@@ -102,6 +102,13 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
 static inline int
 futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
 {
+
+#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_BSWAP)
+       /* Real i386 machines have no cmpxchg instruction */
+       if (boot_cpu_data.x86 == 3)
+               return -ENOSYS;
+#endif
+
        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
                return -EFAULT;
 
index 4d9367b72976a1601897af8ce3f448ad58245c11..9b17571e9bc35f3aaf68c4eb451ae4fa384578d7 100644 (file)
 /* Found in switcher.S */
 extern unsigned long default_idt_entries[];
 
+/* Declarations for definitions in lguest_guest.S */
+extern char lguest_noirq_start[], lguest_noirq_end[];
+extern const char lgstart_cli[], lgend_cli[];
+extern const char lgstart_sti[], lgend_sti[];
+extern const char lgstart_popf[], lgend_popf[];
+extern const char lgstart_pushf[], lgend_pushf[];
+extern const char lgstart_iret[], lgend_iret[];
+
+extern void lguest_iret(void);
+extern void lguest_init(void);
+
 struct lguest_regs
 {
        /* Manually saved part. */
index fec025c7f58cf0b375f94dc4335ca39fdf113125..e3b2bce0aff8e741305068fd41602e06cbf26ba4 100644 (file)
@@ -3,17 +3,29 @@
 
 /* Define nops for use with alternative() */
 
-/* generic versions from gas */
-#define GENERIC_NOP1   ".byte 0x90\n"
-#define GENERIC_NOP2           ".byte 0x89,0xf6\n"
-#define GENERIC_NOP3        ".byte 0x8d,0x76,0x00\n"
-#define GENERIC_NOP4        ".byte 0x8d,0x74,0x26,0x00\n"
-#define GENERIC_NOP5        GENERIC_NOP1 GENERIC_NOP4
-#define GENERIC_NOP6   ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP7   ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP8   GENERIC_NOP1 GENERIC_NOP7
+/* generic versions from gas
+   1: nop
+   2: movl %esi,%esi
+   3: leal 0x00(%esi),%esi
+   4: leal 0x00(,%esi,1),%esi
+   6: leal 0x00000000(%esi),%esi
+   7: leal 0x00000000(,%esi,1),%esi
+*/
+#define GENERIC_NOP1 ".byte 0x90\n"
+#define GENERIC_NOP2 ".byte 0x89,0xf6\n"
+#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n"
+#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n"
+#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4
+#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n"
+#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"
+#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7
 
-/* Opteron 64bit nops */
+/* Opteron 64bit nops
+   1: nop
+   2: osp nop
+   3: osp osp nop
+   4: osp osp osp nop
+*/
 #define K8_NOP1 GENERIC_NOP1
 #define K8_NOP2        ".byte 0x66,0x90\n"
 #define K8_NOP3        ".byte 0x66,0x66,0x90\n"
 #define K8_NOP7        K8_NOP4 K8_NOP3
 #define K8_NOP8        K8_NOP4 K8_NOP4
 
-/* K7 nops */
-/* uses eax dependencies (arbitary choice) */
-#define K7_NOP1  GENERIC_NOP1
+/* K7 nops
+   uses eax dependencies (arbitary choice)
+   1: nop
+   2: movl %eax,%eax
+   3: leal (,%eax,1),%eax
+   4: leal 0x00(,%eax,1),%eax
+   6: leal 0x00000000(%eax),%eax
+   7: leal 0x00000000(,%eax,1),%eax
+*/
+#define K7_NOP1        GENERIC_NOP1
 #define K7_NOP2        ".byte 0x8b,0xc0\n"
 #define K7_NOP3        ".byte 0x8d,0x04,0x20\n"
 #define K7_NOP4        ".byte 0x8d,0x44,0x20,0x00\n"
 #define K7_NOP5        K7_NOP4 ASM_NOP1
 #define K7_NOP6        ".byte 0x8d,0x80,0,0,0,0\n"
-#define K7_NOP7        ".byte 0x8D,0x04,0x05,0,0,0,0\n"
-#define K7_NOP8        K7_NOP7 ASM_NOP1
+#define K7_NOP7        ".byte 0x8D,0x04,0x05,0,0,0,0\n"
+#define K7_NOP8        K7_NOP7 ASM_NOP1
 
-/* P6 nops */
-/* uses eax dependencies (Intel-recommended choice) */
+/* P6 nops
+   uses eax dependencies (Intel-recommended choice)
+   1: nop
+   2: osp nop
+   3: nopl (%eax)
+   4: nopl 0x00(%eax)
+   5: nopl 0x00(%eax,%eax,1)
+   6: osp nopl 0x00(%eax,%eax,1)
+   7: nopl 0x00000000(%eax)
+   8: nopl 0x00000000(%eax,%eax,1)
+*/
 #define P6_NOP1        GENERIC_NOP1
 #define P6_NOP2        ".byte 0x66,0x90\n"
 #define P6_NOP3        ".byte 0x0f,0x1f,0x00\n"
@@ -63,9 +91,7 @@
 #define ASM_NOP6 K7_NOP6
 #define ASM_NOP7 K7_NOP7
 #define ASM_NOP8 K7_NOP8
-#elif defined(CONFIG_M686) || defined(CONFIG_MPENTIUMII) || \
-      defined(CONFIG_MPENTIUMIII) || defined(CONFIG_MPENTIUMM) || \
-      defined(CONFIG_MCORE2) || defined(CONFIG_PENTIUM4)
+#elif defined(CONFIG_X86_P6_NOP)
 #define ASM_NOP1 P6_NOP1
 #define ASM_NOP2 P6_NOP2
 #define ASM_NOP3 P6_NOP3
index f7393bc516eff1c1d25ad799f0441f734a151280..143546073b958097eef072e4d8849b820995232b 100644 (file)
 #define __PHYSICAL_MASK_SHIFT  46
 #define __VIRTUAL_MASK_SHIFT   48
 
-#define KERNEL_TEXT_SIZE  (40*1024*1024)
-#define KERNEL_TEXT_START _AC(0xffffffff80000000, UL)
+/*
+ * Kernel image size is limited to 128 MB (see level2_kernel_pgt in
+ * arch/x86/kernel/head_64.S), and it is mapped here:
+ */
+#define KERNEL_IMAGE_SIZE      (128*1024*1024)
+#define KERNEL_IMAGE_START     _AC(0xffffffff80000000, UL)
 
 #ifndef __ASSEMBLY__
 void clear_page(void *page);
index e217d188a102bec8b15693f6a871945f823431be..2c9621f8bf872a2224482e509069226f9d08fd30 100644 (file)
@@ -242,6 +242,7 @@ struct task_struct;
 
 extern void sched_init(void);
 extern void sched_init_smp(void);
+extern asmlinkage void schedule_tail(struct task_struct *prev);
 extern void init_idle(struct task_struct *idle, int cpu);
 extern void init_idle_bootup_task(struct task_struct *idle);
 
@@ -1189,7 +1190,7 @@ struct task_struct {
        int softirq_context;
 #endif
 #ifdef CONFIG_LOCKDEP
-# define MAX_LOCK_DEPTH 30UL
+# define MAX_LOCK_DEPTH 48UL
        u64 curr_chain_key;
        int lockdep_depth;
        struct held_lock held_locks[MAX_LOCK_DEPTH];
index 3574379f4d62d2d04c9431c0c2172dc044d0ca66..81a4e4a3f087adfc650eb6baf2c05147f209e062 100644 (file)
@@ -779,6 +779,10 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
         * parallel walking of the hash-list safe:
         */
        list_add_tail_rcu(&class->hash_entry, hash_head);
+       /*
+        * Add it to the global list of classes:
+        */
+       list_add_tail_rcu(&class->lock_entry, &all_lock_classes);
 
        if (verbose(class)) {
                graph_unlock();
@@ -2282,10 +2286,6 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
                        return 0;
                break;
        case LOCK_USED:
-               /*
-                * Add it to the global list of classes:
-                */
-               list_add_tail_rcu(&this->class->lock_entry, &all_lock_classes);
                debug_atomic_dec(&nr_unused_locks);
                break;
        default:
index bee36100f110ab75617ad4dce16beac9e1434f76..9adc2a473e6e0f59bbc41350422d415e8f17a7ec 100644 (file)
@@ -666,7 +666,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
        }
        /* Emit the output into the temporary buffer */
        printed_len += vscnprintf(printk_buf + printed_len,
-                                 sizeof(printk_buf), fmt, args);
+                                 sizeof(printk_buf) - printed_len, fmt, args);
 
        /*
         * Copy the output into log_buf.  If the caller didn't provide
index b387a8de26a5f9ca8b6e2e9d3ad33f66fbf65882..f06950c8a6ce17b95624bccc63ecfb399d2eb40c 100644 (file)
@@ -668,6 +668,8 @@ const_debug unsigned int sysctl_sched_nr_migrate = 32;
  */
 unsigned int sysctl_sched_rt_period = 1000000;
 
+static __read_mostly int scheduler_running;
+
 /*
  * part of the period that we allow rt tasks to run in us.
  * default: 0.95s
@@ -689,14 +691,16 @@ unsigned long long cpu_clock(int cpu)
        unsigned long flags;
        struct rq *rq;
 
-       local_irq_save(flags);
-       rq = cpu_rq(cpu);
        /*
         * Only call sched_clock() if the scheduler has already been
         * initialized (some code might call cpu_clock() very early):
         */
-       if (rq->idle)
-               update_rq_clock(rq);
+       if (unlikely(!scheduler_running))
+               return 0;
+
+       local_irq_save(flags);
+       rq = cpu_rq(cpu);
+       update_rq_clock(rq);
        now = rq->clock;
        local_irq_restore(flags);
 
@@ -3885,7 +3889,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev)
 asmlinkage void __sched schedule(void)
 {
        struct task_struct *prev, *next;
-       long *switch_count;
+       unsigned long *switch_count;
        struct rq *rq;
        int cpu;
 
@@ -7284,6 +7288,8 @@ void __init sched_init(void)
         * During early bootup we pretend to be a normal task:
         */
        current->sched_class = &fair_sched_class;
+
+       scheduler_running = 1;
 }
 
 #ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
index 6c091d6e159d01fb23c0dd786495c533cb005c5b..c8e6492c5925f0dea503d48d04b9a12a6f0ade51 100644 (file)
@@ -202,17 +202,12 @@ static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
 
 static inline struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
 {
-       struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
-       struct sched_entity *se = NULL;
-       struct rb_node *parent;
+       struct rb_node *last = rb_last(&cfs_rq->tasks_timeline);
 
-       while (*link) {
-               parent = *link;
-               se = rb_entry(parent, struct sched_entity, run_node);
-               link = &parent->rb_right;
-       }
+       if (!last)
+               return NULL;
 
-       return se;
+       return rb_entry(last, struct sched_entity, run_node);
 }
 
 /**************************************************************