diff options
146 files changed, 2195 insertions, 588 deletions
diff --git a/Documentation/HOWTO b/Documentation/HOWTO index f5395af88a4..40ada93b820 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -234,7 +234,7 @@ process is as follows: Linus, usually the patches that have already been included in the -next kernel for a few weeks. The preferred way to submit big changes is using git (the kernel's source management tool, more information - can be found at http://git.or.cz/) but plain patches are also just + can be found at http://git-scm.com/) but plain patches are also just fine. - After two weeks a -rc1 kernel is released it is now possible to push only patches that do not include new features that could affect the diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt index fd588ff0e29..a1ca5924faf 100644 --- a/Documentation/cgroups/cgroups.txt +++ b/Documentation/cgroups/cgroups.txt @@ -235,8 +235,7 @@ containing the following files describing that cgroup: - cgroup.procs: list of tgids in the cgroup. This list is not guaranteed to be sorted or free of duplicate tgids, and userspace should sort/uniquify the list if this property is required. - Writing a tgid into this file moves all threads with that tgid into - this cgroup. + This is a read-only file, for now. - notify_on_release flag: run the release agent on exit? - release_agent: the path to use for release notifications (this file exists in the top cgroup only) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e2202e93b14..839b21b0699 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1194,7 +1194,7 @@ and is between 256 and 4096 characters. It is defined in the file libata.force= [LIBATA] Force configurations. The format is comma separated list of "[ID:]VAL" where ID is - PORT[:DEVICE]. PORT and DEVICE are decimal numbers + PORT[.DEVICE]. PORT and DEVICE are decimal numbers matching port, link or device. Basically, it matches the ATA ID string printed on console by libata. If the whole ID part is omitted, the last PORT and DEVICE diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt index 5effa5bd993..e213f45cf9d 100644 --- a/Documentation/stable_kernel_rules.txt +++ b/Documentation/stable_kernel_rules.txt @@ -18,16 +18,15 @@ Rules on what kind of patches are accepted, and which ones are not, into the - It cannot contain any "trivial" fixes in it (spelling changes, whitespace cleanups, etc). - It must follow the Documentation/SubmittingPatches rules. - - It or an equivalent fix must already exist in Linus' tree. Quote the - respective commit ID in Linus' tree in your patch submission to -stable. + - It or an equivalent fix must already exist in Linus' tree (upstream). Procedure for submitting patches to the -stable tree: - Send the patch, after verifying that it follows the above rules, to - stable@kernel.org. - - To have the patch automatically included in the stable tree, add the - the tag + stable@kernel.org. You must note the upstream commit ID in the changelog + of your submission. + - To have the patch automatically included in the stable tree, add the tag Cc: stable@kernel.org in the sign-off area. Once the patch is merged it will be applied to the stable tree without anything else needing to be done by the author diff --git a/MAINTAINERS b/MAINTAINERS index a0e3c3a47a5..183887518fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1960,7 +1960,7 @@ F: lib/kobj* DRM DRIVERS M: David Airlie <airlied@linux.ie> -L: dri-devel@lists.sourceforge.net +L: dri-devel@lists.freedesktop.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git S: Maintained F: drivers/gpu/drm/ @@ -4791,12 +4791,11 @@ F: drivers/s390/crypto/ S390 ZFCP DRIVER M: Christof Schmitt <christof.schmitt@de.ibm.com> -M: Martin Peschke <mp3@de.ibm.com> +M: Swen Schillig <swen@vnet.ibm.com> M: linux390@de.ibm.com L: linux-s390@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ S: Supported -F: Documentation/s390/zfcpdump.txt F: drivers/s390/scsi/zfcp_* S390 IUCV NETWORK LAYER diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index 73c5c2b05f6..7f3c0a2e60c 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -1802,7 +1802,8 @@ static int kvm_ia64_sync_dirty_log(struct kvm *kvm, { struct kvm_memory_slot *memslot; int r, i; - long n, base; + long base; + unsigned long n; unsigned long *dirty_bitmap = (unsigned long *)(kvm->arch.vm_base + offsetof(struct kvm_vm_data, kvm_mem_dirty_log)); @@ -1815,7 +1816,7 @@ static int kvm_ia64_sync_dirty_log(struct kvm *kvm, if (!memslot->dirty_bitmap) goto out; - n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; + n = kvm_dirty_bitmap_bytes(memslot); base = memslot->base_gfn / BITS_PER_LONG; for (i = 0; i < n/sizeof(long); ++i) { @@ -1831,7 +1832,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) { int r; - int n; + unsigned long n; struct kvm_memory_slot *memslot; int is_dirty = 0; @@ -1850,7 +1851,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, if (is_dirty) { kvm_flush_remote_tlbs(kvm); memslot = &kvm->memslots->memslots[log->slot]; - n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; + n = kvm_dirty_bitmap_bytes(memslot); memset(memslot->dirty_bitmap, 0, n); } r = 0; diff --git a/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h index ef229387361..01a8716c5fc 100644 --- a/arch/m68k/include/asm/mcfuart.h +++ b/arch/m68k/include/asm/mcfuart.h @@ -212,5 +212,10 @@ struct mcf_platform_uart { #define MCFUART_URF_RXS 0xc0 /* Receiver status */ #endif +#if defined(CONFIG_M5272) +#define MCFUART_TXFIFOSIZE 25 +#else +#define MCFUART_TXFIFOSIZE 1 +#endif /****************************************************************************/ #endif /* mcfuart_h */ diff --git a/arch/m68knommu/Makefile b/arch/m68knommu/Makefile index ce404bc9ccb..14042574ac2 100644 --- a/arch/m68knommu/Makefile +++ b/arch/m68knommu/Makefile @@ -94,7 +94,7 @@ cflags-$(CONFIG_M520x) := $(call cc-option,-mcpu=5208,-m5200) cflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307) cflags-$(CONFIG_M5249) := $(call cc-option,-mcpu=5249,-m5200) cflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307) -cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5271,-m5200) +cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5272,-m5307) cflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307) cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307) cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200) diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S index 56043ade394..aff6f57ef8b 100644 --- a/arch/m68knommu/kernel/entry.S +++ b/arch/m68knommu/kernel/entry.S @@ -145,6 +145,6 @@ ENTRY(ret_from_user_signal) trap #0 ENTRY(ret_from_user_rt_signal) - move #__NR_rt_sigreturn,%d0 + movel #__NR_rt_sigreturn,%d0 trap #0 diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c index 1143f77caca..6f22970d8c2 100644 --- a/arch/m68knommu/platform/68360/ints.c +++ b/arch/m68knommu/platform/68360/ints.c @@ -107,7 +107,6 @@ void init_IRQ(void) _ramvec[vba+CPMVEC_PIO_PC7] = inthandler; /* pio - pc7 */ _ramvec[vba+CPMVEC_PIO_PC6] = inthandler; /* pio - pc6 */ _ramvec[vba+CPMVEC_TIMER3] = inthandler; /* timer 3 */ - _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* reserved */ _ramvec[vba+CPMVEC_PIO_PC5] = inthandler; /* pio - pc5 */ _ramvec[vba+CPMVEC_PIO_PC4] = inthandler; /* pio - pc4 */ _ramvec[vba+CPMVEC_RESERVED2] = inthandler; /* reserved */ diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 25da07fd9f7..604af29b71e 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -1004,7 +1004,8 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_vcpu *vcpu; ulong ga, ga_end; int is_dirty = 0; - int r, n; + int r; + unsigned long n; mutex_lock(&kvm->slots_lock); @@ -1022,7 +1023,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, kvm_for_each_vcpu(n, vcpu, kvm) kvmppc_mmu_pte_pflush(vcpu, ga, ga_end); - n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; + n = kvm_dirty_bitmap_bytes(memslot); memset(memslot->dirty_bitmap, 0, n); } diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index 4a76d9480cc..533f35751ae 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h @@ -29,6 +29,7 @@ struct vdso_data { __u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */ __u32 tz_dsttime; /* Type of dst correction 0x34 */ __u32 ectg_available; + __u32 ntp_mult; /* NTP adjusted multiplier 0x3C */ }; struct vdso_per_cpu_data { diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 08db736dded..a09408952ed 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c @@ -61,6 +61,7 @@ int main(void) DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest)); DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available)); + DEFINE(__VDSO_NTP_MULT, offsetof(struct vdso_data, ntp_mult)); DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base)); DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time)); /* constants used by the vdso */ diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S index b354427e03b..c56d3f56d02 100644 --- a/arch/s390/kernel/swsusp_asm64.S +++ b/arch/s390/kernel/swsusp_asm64.S @@ -256,6 +256,9 @@ restore_registers: lghi %r2,0 brasl %r14,arch_set_page_states + /* Reinitialize the channel subsystem */ + brasl %r14,channel_subsystem_reinit + /* Return 0 */ lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15) lghi %r2,0 diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index fba6dec156b..d906bf19c14 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -221,6 +221,7 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock, vdso_data->xtime_clock_nsec = wall_time->tv_nsec; vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec; vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec; + vdso_data->ntp_mult = mult; smp_wmb(); ++vdso_data->tb_update_count; } diff --git a/arch/s390/kernel/vdso32/clock_gettime.S b/arch/s390/kernel/vdso32/clock_gettime.S index 4a98909a831..96964395427 100644 --- a/arch/s390/kernel/vdso32/clock_gettime.S +++ b/arch/s390/kernel/vdso32/clock_gettime.S @@ -38,13 +38,13 @@ __kernel_clock_gettime: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,2f ahi %r0,-1 -2: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ +2: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ lr %r2,%r0 - lhi %r0,1000 + l %r0,__VDSO_NTP_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 3f - ahi %r0,1000 + a %r0,__VDSO_NTP_MULT(%r5) 3: alr %r0,%r2 srdl %r0,12 al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ @@ -86,13 +86,13 @@ __kernel_clock_gettime: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,12f ahi %r0,-1 -12: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ +12: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ lr %r2,%r0 - lhi %r0,1000 + l %r0,__VDSO_NTP_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 13f - ahi %r0,1000 + a %r0,__VDSO_NTP_MULT(%r5) 13: alr %r0,%r2 srdl %r0,12 al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ diff --git a/arch/s390/kernel/vdso32/gettimeofday.S b/arch/s390/kernel/vdso32/gettimeofday.S index ad8acfc949f..2d3633175e3 100644 --- a/arch/s390/kernel/vdso32/gettimeofday.S +++ b/arch/s390/kernel/vdso32/gettimeofday.S @@ -35,13 +35,13 @@ __kernel_gettimeofday: sl %r1,__VDSO_XTIME_STAMP+4(%r5) brc 3,3f ahi %r0,-1 -3: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */ +3: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */ st %r0,24(%r15) - lhi %r0,1000 + l %r0,__VDSO_NTP_MULT(%r5) ltr %r1,%r1 mr %r0,%r0 jnm 4f - ahi %r0,1000 + a %r0,__VDSO_NTP_MULT(%r5) 4: al %r0,24(%r15) srdl %r0,12 al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */ diff --git a/arch/s390/kernel/vdso64/clock_gettime.S b/arch/s390/kernel/vdso64/clock_gettime.S index 49106c6e6f8..f40467884a0 100644 --- a/arch/s390/kernel/vdso64/clock_gettime.S +++ b/arch/s390/kernel/vdso64/clock_gettime.S @@ -36,7 +36,7 @@ __kernel_clock_gettime: stck 48(%r15) /* Store TOD clock */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - mghi %r1,1000 + msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ lg %r0,__VDSO_XTIME_SEC(%r5) @@ -64,7 +64,7 @@ __kernel_clock_gettime: stck 48(%r15) /* Store TOD clock */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - mghi %r1,1000 + msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */ lg %r0,__VDSO_XTIME_SEC(%r5) diff --git a/arch/s390/kernel/vdso64/gettimeofday.S b/arch/s390/kernel/vdso64/gettimeofday.S index f873e75634e..36ee674722e 100644 --- a/arch/s390/kernel/vdso64/gettimeofday.S +++ b/arch/s390/kernel/vdso64/gettimeofday.S @@ -31,7 +31,7 @@ __kernel_gettimeofday: stck 48(%r15) /* Store TOD clock */ lg %r1,48(%r15) sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */ - mghi %r1,1000 + msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */ srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */ alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime.tv_nsec */ lg %r0,__VDSO_XTIME_SEC(%r5) /* xtime.tv_sec */ diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 64cda95f59c..7a656bd8bd3 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -6,6 +6,7 @@ #include "linux/irqreturn.h" #include "linux/kd.h" #include "linux/sched.h" +#include "linux/slab.h" #include "chan_kern.h" #include "irq_kern.h" #include "irq_user.h" diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 06d6ccf0e44..b6b1096152a 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -8,7 +8,6 @@ #include <errno.h> #include <sched.h> #include <linux/limits.h> -#include <linux/slab.h> #include <sys/socket.h> #include <sys/wait.h> #include "kern_constants.h" diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index 1cbed97b59c..dfdb4dba232 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -22,6 +22,7 @@ */ #include <linux/dmi.h> +#include <linux/module.h> #include <asm/div64.h> #include <asm/vmware.h> #include <asm/x86_init.h> @@ -101,6 +102,7 @@ int vmware_platform(void) return 0; } +EXPORT_SYMBOL(vmware_platform); /* * VMware hypervisor takes care of exporting a reliable TSC to the guest. diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 48aeee8eefb..19a8906bcaa 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1490,8 +1490,8 @@ static int mmu_zap_unsync_children(struct kvm *kvm, for_each_sp(pages, sp, parents, i) { kvm_mmu_zap_page(kvm, sp); mmu_pages_clear_parents(&parents); + zapped++; } - zapped += pages.nr; kvm_mmu_pages_init(parent, &parents, &pages); } @@ -1542,14 +1542,16 @@ void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages) */ if (used_pages > kvm_nr_mmu_pages) { - while (used_pages > kvm_nr_mmu_pages) { + while (used_pages > kvm_nr_mmu_pages && + !list_empty(&kvm->arch.active_mmu_pages)) { struct kvm_mmu_page *page; page = container_of(kvm->arch.active_mmu_pages.prev, struct kvm_mmu_page, link); - kvm_mmu_zap_page(kvm, page); + used_pages -= kvm_mmu_zap_page(kvm, page); used_pages--; } + kvm_nr_mmu_pages = used_pages; kvm->arch.n_free_mmu_pages = 0; } else @@ -1596,7 +1598,8 @@ static void mmu_unshadow(struct kvm *kvm, gfn_t gfn) && !sp->role.invalid) { pgprintk("%s: zap %lx %x\n", __func__, gfn, sp->role.word); - kvm_mmu_zap_page(kvm, sp); + if (kvm_mmu_zap_page(kvm, sp)) + nn = bucket->first; } } } diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 445c59411ed..2ba58206812 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -706,29 +706,28 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) if (err) goto free_svm; + err = -ENOMEM; page = alloc_page(GFP_KERNEL); - if (!page) { - err = -ENOMEM; + if (!page) goto uninit; - } - err = -ENOMEM; msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER); if (!msrpm_pages) - goto uninit; + goto free_page1; nested_msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER); if (!nested_msrpm_pages) - goto uninit; - - svm->msrpm = page_address(msrpm_pages); - svm_vcpu_init_msrpm(svm->msrpm); + goto free_page2; hsave_page = alloc_page(GFP_KERNEL); if (!hsave_page) - goto uninit; + goto free_page3; + svm->nested.hsave = page_address(hsave_page); + svm->msrpm = page_address(msrpm_pages); + svm_vcpu_init_msrpm(svm->msrpm); + svm->nested.msrpm = page_address(nested_msrpm_pages); svm->vmcb = page_address(page); @@ -744,6 +743,12 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) return &svm->vcpu; +free_page3: + __free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER); +free_page2: + __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER); +free_page1: + __free_page(page); uninit: kvm_vcpu_uninit(&svm->vcpu); free_svm: diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 686492ed307..bc933cfb4e6 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -77,6 +77,8 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO); #define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE) #define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE) +#define RMODE_GUEST_OWNED_EFLAGS_BITS (~(X86_EFLAGS_IOPL | X86_EFLAGS_VM)) + /* * These 2 parameters are used to config the controls for Pause-Loop Exiting: * ple_gap: upper bound on the amount of time between two successive @@ -131,7 +133,7 @@ struct vcpu_vmx { } host_state; struct { int vm86_active; - u8 save_iopl; + ulong save_rflags; struct kvm_save_segment { u16 selector; unsigned long base; @@ -818,18 +820,23 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) { - unsigned long rflags; + unsigned long rflags, save_rflags; rflags = vmcs_readl(GUEST_RFLAGS); - if (to_vmx(vcpu)->rmode.vm86_active) - rflags &= ~(unsigned long)(X86_EFLAGS_IOPL | X86_EFLAGS_VM); + if (to_vmx(vcpu)->rmode.vm86_active) { + rflags &= RMODE_GUEST_OWNED_EFLAGS_BITS; + save_rflags = to_vmx(vcpu)->rmode.save_rflags; + rflags |= save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS; + } return rflags; } static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) { - if (to_vmx(vcpu)->rmode.vm86_active) + if (to_vmx(vcpu)->rmode.vm86_active) { + to_vmx(vcpu)->rmode.save_rflags = rflags; rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM; + } vmcs_writel(GUEST_RFLAGS, rflags); } @@ -1483,8 +1490,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu) vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar); flags = vmcs_readl(GUEST_RFLAGS); - flags &= ~(X86_EFLAGS_IOPL | X86_EFLAGS_VM); - flags |= (vmx->rmode.save_iopl << IOPL_SHIFT); + flags &= RMODE_GUEST_OWNED_EFLAGS_BITS; + flags |= vmx->rmode.save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS; vmcs_writel(GUEST_RFLAGS, flags); vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) | @@ -1557,8 +1564,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu) vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); flags = vmcs_readl(GUEST_RFLAGS); - vmx->rmode.save_iopl - = (flags & X86_EFLAGS_IOPL) >> IOPL_SHIFT; + vmx->rmode.save_rflags = flags; flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 24cd0ee896e..3c4ca98ad27 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -433,8 +433,6 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) #ifdef CONFIG_X86_64 if (cr0 & 0xffffffff00000000UL) { - printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", - cr0, kvm_read_cr0(vcpu)); kvm_inject_gp(vcpu, 0); return; } @@ -443,14 +441,11 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) cr0 &= ~CR0_RESERVED_BITS; if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) { - printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n"); kvm_inject_gp(vcpu, 0); return; } if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) { - printk(KERN_DEBUG "set_cr0: #GP, set PG flag " - "and a clear PE flag\n"); kvm_inject_gp(vcpu, 0); return; } @@ -461,15 +456,11 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) int cs_db, cs_l; if (!is_pae(vcpu)) { - printk(KERN_DEBUG "set_cr0: #GP, start paging " - "in long mode while PAE is disabled\n"); kvm_inject_gp(vcpu, 0); return; } kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); if (cs_l) { - printk(KERN_DEBUG "set_cr0: #GP, start paging " - "in long mode while CS.L == 1\n"); kvm_inject_gp(vcpu, 0); return; @@ -477,8 +468,6 @@ void kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) } else #endif if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3)) { - printk(KERN_DEBUG "set_cr0: #GP, pdptrs " - "reserved bits\n"); kvm_inject_gp(vcpu, 0); return; } @@ -505,28 +494,23 @@ void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE; if (cr4 & CR4_RESERVED_BITS) { - printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); kvm_inject_gp(vcpu, 0); return; } if (is_long_mode(vcpu)) { if (!(cr4 & X86_CR4_PAE)) { - printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while " - "in long mode\n"); kvm_inject_gp(vcpu, 0); return; } } else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE) && ((cr4 ^ old_cr4) & pdptr_bits) && !load_pdptrs(vcpu, vcpu->arch.cr3)) { - printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); kvm_inject_gp(vcpu, 0); return; } if (cr4 & X86_CR4_VMXE) { - printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n"); kvm_inject_gp(vcpu, 0); return; } @@ -547,21 +531,16 @@ void kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) if (is_long_mode(vcpu)) { if (cr3 & CR3_L_MODE_RESERVED_BITS) { - printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); kvm_inject_gp(vcpu, 0); return; } } else { if (is_pae(vcpu)) { if (cr3 & CR3_PAE_RESERVED_BITS) { - printk(KERN_DEBUG - "set_cr3: #GP, reserved bits\n"); kvm_inject_gp(vcpu, 0); return; } if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) { - printk(KERN_DEBUG "set_cr3: #GP, pdptrs " - "reserved bits\n"); kvm_inject_gp(vcpu, 0); return; } @@ -593,7 +572,6 @@ EXPORT_SYMBOL_GPL(kvm_set_cr3); void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) { if (cr8 & CR8_RESERVED_BITS) { - printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); kvm_inject_gp(vcpu, 0); return; } @@ -649,15 +627,12 @@ static u32 emulated_msrs[] = { static void set_efer(struct kvm_vcpu *vcpu, u64 efer) { if (efer & efer_reserved_bits) { - printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n", - efer); kvm_inject_gp(vcpu, 0); return; } if (is_paging(vcpu) && (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) { - printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n"); kvm_inject_gp(vcpu, 0); return; } @@ -667,7 +642,6 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0); if (!feat || !(feat->edx & bit(X86_FEATURE_FXSR_OPT))) { - printk(KERN_DEBUG "set_efer: #GP, enable FFXSR w/o CPUID capability\n"); kvm_inject_gp(vcpu, 0); return; } @@ -678,7 +652,6 @@ static void set_efer(struct kvm_vcpu *vcpu, u64 efer) feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0); if (!feat || !(feat->ecx & bit(X86_FEATURE_SVM))) { - printk(KERN_DEBUG "set_efer: #GP, enable SVM w/o SVM\n"); kvm_inject_gp(vcpu, 0); return; } @@ -967,9 +940,13 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 data) if (msr >= MSR_IA32_MC0_CTL && msr < MSR_IA32_MC0_CTL + 4 * bank_num) { u32 offset = msr - MSR_IA32_MC0_CTL; - /* only 0 or all 1s can be written to IA32_MCi_CTL */ + /* only 0 or all 1s can be written to IA32_MCi_CTL + * some Linux kernels though clear bit 10 in bank 4 to + * workaround a BIOS/GART TBL issue on AMD K8s, ignore + * this to avoid an uncatched #GP in the guest + */ if ((offset & 0x3) == 0 && - data != 0 && data != ~(u64)0) + data != 0 && (data | (1 << 10)) != ~(u64)0) return -1; vcpu->arch.mce_banks[offset] = data; break; @@ -2635,8 +2612,9 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm, int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) { - int r, n, i; + int r, i; struct kvm_memory_slot *memslot; + unsigned long n; unsigned long is_dirty = 0; unsigned long *dirty_bitmap = NULL; @@ -2651,7 +2629,7 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, if (!memslot->dirty_bitmap) goto out; - n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; + n = kvm_dirty_bitmap_bytes(memslot); r = -ENOMEM; dirty_bitmap = vmalloc(n); @@ -4483,7 +4461,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) kvm_set_cr8(vcpu, kvm_run->cr8); if (vcpu->arch.pio.cur_count) { + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); r = complete_pio(vcpu); + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); if (r) goto out; } @@ -5146,6 +5126,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) int ret = 0; u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR); u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR); + u32 desc_limit; old_tss_base = kvm_mmu_gva_to_gpa_write(vcpu, old_tss_base, NULL); @@ -5168,7 +5149,10 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason) } } - if (!nseg_desc.p || get_desc_limit(&nseg_desc) < 0x67) { + desc_limit = get_desc_limit(&nseg_desc); + if (!nseg_desc.p || + ((desc_limit < 0x67 && (nseg_desc.type & 8)) || + desc_limit < 0x2b)) { kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc); return 1; } diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index c7b1ebfb7da..44f83ce0247 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -66,14 +66,44 @@ resource_to_addr(struct acpi_resource *resource, struct acpi_resource_address64 *addr) { acpi_status status; - - status = acpi_resource_to_address64(resource, addr); - if (ACPI_SUCCESS(status) && - (addr->resource_type == ACPI_MEMORY_RANGE || - addr->resource_type == ACPI_IO_RANGE) && - addr->address_length > 0 && - addr->producer_consumer == ACPI_PRODUCER) { + struct acpi_resource_memory24 *memory24; + struct acpi_resource_memory32 *memory32; + struct acpi_resource_fixed_memory32 *fixed_memory32; + + memset(addr, 0, sizeof(*addr)); + switch (resource->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + memory24 = &resource->data.memory24; + addr->resource_type = ACPI_MEMORY_RANGE; + addr->minimum = memory24->minimum; + addr->address_length = memory24->address_length; + addr->maximum = addr->minimum + addr->address_length - 1; + return AE_OK; + case ACPI_RESOURCE_TYPE_MEMORY32: + memory32 = &resource->data.memory32; + addr->resource_type = ACPI_MEMORY_RANGE; + addr->minimum = memory32->minimum; + addr->address_length = memory32->address_length; + addr->maximum = addr->minimum + addr->address_length - 1; return AE_OK; + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + fixed_memory32 = &resource->data.fixed_memory32; + addr->resource_type = ACPI_MEMORY_RANGE; + addr->minimum = fixed_memory32->address; + addr->address_length = fixed_memory32->address_length; + addr->maximum = addr->minimum + addr->address_length - 1; + return AE_OK; + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + status = acpi_resource_to_address64(resource, addr); + if (ACPI_SUCCESS(status) && + (addr->resource_type == ACPI_MEMORY_RANGE || + addr->resource_type == ACPI_IO_RANGE) && + addr->address_length > 0) { + return AE_OK; + } + break; } return AE_ERROR; } diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 9f6cfac0f2c..228740f356c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -879,6 +879,8 @@ static void ata_eh_set_pending(struct ata_port *ap, int fastdrain) void ata_qc_schedule_eh(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + struct request_queue *q = qc->scsicmd->device->request_queue; + unsigned long flags; WARN_ON(!ap->ops->error_handler); @@ -890,7 +892,9 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) * Note that ATA_QCFLAG_FAILED is unconditionally set after * this function completes. */ + spin_lock_irqsave(q->queue_lock, flags); blk_abort_request(qc->scsicmd->request); + spin_unlock_irqrestore(q->queue_lock, flags); } /** @@ -1624,6 +1628,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) } /* okay, this error is ours */ + memset(&tf, 0, sizeof(tf)); rc = ata_eh_read_log_10h(dev, &tag, &tf); if (rc) { ata_link_printk(link, KERN_ERR, "failed to read log page 10h " diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 3c3172d3c34..4164dd244dd 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -424,6 +424,8 @@ static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420), PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), + PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x3e520e17), + PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10), PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e), PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), @@ -444,6 +446,8 @@ static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x9351e59d), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47), PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index 3784a47865b..8f5aebfb29d 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -190,7 +190,7 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, for (try = 0; try < 5; try++) { new = allocate ? old - bandwidth : old + bandwidth; if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL) - break; + return -EBUSY; data[0] = cpu_to_be32(old); data[1] = cpu_to_be32(new); @@ -218,7 +218,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation, u32 channels_mask, u64 offset, bool allocate, __be32 data[2]) { __be32 c, all, old; - int i, retry = 5; + int i, ret = -EIO, retry = 5; old = all = allocate ? cpu_to_be32(~0) : 0; @@ -226,6 +226,8 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation, if (!(channels_mask & 1 << i)) continue; + ret = -EBUSY; + c = cpu_to_be32(1 << (31 - i)); if ((old & c) != (all & c)) continue; @@ -251,12 +253,16 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation, /* 1394-1995 IRM, fall through to retry. */ default: - if (retry--) + if (retry) { + retry--; i--; + } else { + ret = -EIO; + } } } - return -EIO; + return ret; } static void deallocate_channel(struct fw_card *card, int irm_id, diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 0cf4d7f562c..94b16e0340a 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1158,7 +1158,7 @@ static void handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr) { struct fw_packet response; - int tcode, length, ext_tcode, sel; + int tcode, length, ext_tcode, sel, try; __be32 *payload, lock_old; u32 lock_arg, lock_data; @@ -1185,21 +1185,26 @@ static void handle_local_lock(struct fw_ohci *ohci, reg_write(ohci, OHCI1394_CSRCompareData, lock_arg); reg_write(ohci, OHCI1394_CSRControl, sel); - if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) - lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData)); - else - fw_notify("swap not done yet\n"); + for (try = 0; try < 20; try++) + if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) { + lock_old = cpu_to_be32(reg_read(ohci, + OHCI1394_CSRData)); + fw_fill_response(&response, packet->header, + RCODE_COMPLETE, + &lock_old, sizeof(lock_old)); + goto out; + } + + fw_error("swap not done (CSR lock timeout)\n"); + fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0); - fw_fill_response(&response, packet->header, - RCODE_COMPLETE, &lock_old, sizeof(lock_old)); out: fw_core_handle_response(&ohci->card, &response); } static void handle_local_request(struct context *ctx, struct fw_packet *packet) { - u64 offset; - u32 csr; + u64 offset, csr; if (ctx == &ctx->ohci->at_request_ctx) { packet->ack = ACK_PENDING; diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2dc93939507..c3cfafcbfe7 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1357,6 +1357,8 @@ static void i915_setup_compression(struct drm_device *dev, int size) dev_priv->cfb_size = size; + dev_priv->compressed_fb = compressed_fb; + if (IS_GM45(dev)) { g4x_disable_fbc(dev); I915_WRITE(DPFC_CB_BASE, compressed_fb->start); @@ -1364,12 +1366,22 @@ static void i915_setup_compression(struct drm_device *dev, int size) i8xx_disable_fbc(dev); I915_WRITE(FBC_CFB_BASE, cfb_base); I915_WRITE(FBC_LL_BASE, ll_base); + dev_priv->compressed_llb = compressed_llb; } DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base, ll_base, size >> 20); } +static void i915_cleanup_compression(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + drm_mm_put_block(dev_priv->compressed_fb); + if (!IS_GM45(dev)) + drm_mm_put_block(dev_priv->compressed_llb); +} + /* true = enable decode, false = disable decoder */ static unsigned int i915_vga_set_decode(void *cookie, bool state) { @@ -1787,6 +1799,8 @@ int i915_driver_unload(struct drm_device *dev) mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); mutex_unlock(&dev->struct_mutex); + if (I915_HAS_FBC(dev) && i915_powersave) + i915_cleanup_compression(dev); drm_mm_takedown(&dev_priv->vram); i915_gem_lastclose(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0af3dcc85ce..cc03537bb88 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -69,7 +69,8 @@ const static struct intel_device_info intel_845g_info = { }; const static struct intel_device_info intel_i85x_info = { - .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1, + .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1, + .cursor_needs_physical = 1, }; const static struct intel_device_info intel_i865g_info = { @@ -151,7 +152,7 @@ const static struct pci_device_id pciidlist[] = { INTEL_VGA_DEVICE(0x3577, &intel_i830_info), INTEL_VGA_DEVICE(0x2562, &intel_845g_info), INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), - INTEL_VGA_DEVICE(0x35e8, &intel_i85x_info), + INTEL_VGA_DEVICE(0x358e, &intel_i85x_info), INTEL_VGA_DEVICE(0x2572, &intel_i865g_info), INTEL_VGA_DEVICE(0x2582, &intel_i915g_info), INTEL_VGA_DEVICE(0x258a, &intel_i915g_info), diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6960849522f..6e4790065d9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -195,6 +195,7 @@ struct intel_overlay; struct intel_device_info { u8 is_mobile : 1; u8 is_i8xx : 1; + u8 is_i85x : 1; u8 is_i915g : 1; u8 is_i9xx : 1; u8 is_i945gm : 1; @@ -235,11 +236,14 @@ typedef struct drm_i915_private { drm_dma_handle_t *status_page_dmah; void *hw_status_page; + void *seqno_page; dma_addr_t dma_status_page; uint32_t counter; unsigned int status_gfx_addr; + unsigned int seqno_gfx_addr; drm_local_map_t hws_map; struct drm_gem_object *hws_obj; + struct drm_gem_object *seqno_obj; struct drm_gem_object *pwrctx; struct resource mch_res; @@ -630,6 +634,9 @@ typedef struct drm_i915_private { u8 max_delay; enum no_fbc_reason no_fbc_reason; + + struct drm_mm_node *compressed_fb; + struct drm_mm_node *compressed_llb; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ @@ -1070,7 +1077,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define IS_I830(dev) ((dev)->pci_device == 0x3577) #define IS_845G(dev) ((dev)->pci_device == 0x2562) -#define IS_I85X(dev) ((dev)->pci_device == 0x3582) +#define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x) #define IS_I865G(dev) ((dev)->pci_device == 0x2572) #define IS_GEN2(dev) (INTEL_INFO(dev)->is_i8xx) #define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g) @@ -1135,6 +1142,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \ IS_GEN6(dev)) +#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 80871c62a57..ef3d91dda71 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1588,6 +1588,13 @@ i915_gem_process_flushing_list(struct drm_device *dev, } } +#define PIPE_CONTROL_FLUSH(addr) \ + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ + PIPE_CONTROL_DEPTH_STALL); \ + OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \ + OUT_RING(0); \ + OUT_RING(0); \ + /** * Creates a new sequence number, emitting a write of it to the status page * plus an interrupt, which will trigger i915_user_interrupt_handler. @@ -1622,13 +1629,47 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (dev_priv->mm.next_gem_seqno == 0) dev_priv->mm.next_gem_seqno++; - BEGIN_LP_RING(4); - OUT_RING(MI_STORE_DWORD_INDEX); - OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - OUT_RING(seqno); + if (HAS_PIPE_CONTROL(dev)) { + u32 scratch_addr = dev_priv->seqno_gfx_addr + 128; - OUT_RING(MI_USER_INTERRUPT); - ADVANCE_LP_RING(); + /* + * Workaround qword write incoherence by flushing the + * PIPE_NOTIFY buffers out to memory before requesting + * an interrupt. + */ + BEGIN_LP_RING(32); + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; /* write to separate cachelines */ + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + scratch_addr += 128; + PIPE_CONTROL_FLUSH(scratch_addr); + OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | + PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | + PIPE_CONTROL_NOTIFY); + OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT); + OUT_RING(seqno); + OUT_RING(0); + ADVANCE_LP_RING(); + } else { + BEGIN_LP_RING(4); + OUT_RING(MI_STORE_DWORD_INDEX); + OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + OUT_RING(seqno); + + OUT_RING(MI_USER_INTERRUPT); + ADVANCE_LP_RING(); + } DRM_DEBUG_DRIVER("%d\n", seqno); @@ -1752,7 +1793,10 @@ i915_get_gem_seqno(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX); + if (HAS_PIPE_CONTROL(dev)) + return ((volatile u32 *)(dev_priv->seqno_page))[0]; + else + return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX); } /** @@ -2362,6 +2406,12 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg) pitch_val = obj_priv->stride / tile_width; pitch_val = ffs(pitch_val) - 1; + if (obj_priv->tiling_mode == I915_TILING_Y && + HAS_128_BYTE_Y_TILING(dev)) + WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL); + else + WARN_ON(pitch_val > I915_FENCE_MAX_PITCH_VAL); + val = obj_priv->gtt_offset; if (obj_priv->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; @@ -4546,6 +4596,49 @@ i915_gem_idle(struct drm_device *dev) return 0; } +/* + * 965+ support PIPE_CONTROL commands, which provide finer grained control + * over cache flushing. + */ +static int +i915_gem_init_pipe_control(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + int ret; + + obj = drm_gem_object_alloc(dev, 4096); + if (obj == NULL) { + DRM_ERROR("Failed to allocate seqno page\n"); + ret = -ENOMEM; + goto err; + } + obj_priv = to_intel_bo(obj); + obj_priv->agp_type = AGP_USER_CACHED_MEMORY; + + ret = i915_gem_object_pin(obj, 4096); + if (ret) + goto err_unref; + + dev_priv->seqno_gfx_addr = obj_priv->gtt_offset; + dev_priv->seqno_page = kmap(obj_priv->pages[0]); + if (dev_priv->seqno_page == NULL) + goto err_unpin; + + dev_priv->seqno_obj = obj; + memset(dev_priv->seqno_page, 0, PAGE_SIZE); + + return 0; + +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(obj); +err: + return ret; +} + static int i915_gem_init_hws(struct drm_device *dev) { @@ -4563,7 +4656,8 @@ i915_gem_init_hws(struct drm_device *dev) obj = drm_gem_object_alloc(dev, 4096); if (obj == NULL) { DRM_ERROR("Failed to allocate status page\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } obj_priv = to_intel_bo(obj); obj_priv->agp_type = AGP_USER_CACHED_MEMORY; @@ -4571,7 +4665,7 @@ i915_gem_init_hws(struct drm_device *dev) ret = i915_gem_object_pin(obj, 4096); if (ret != 0) { drm_gem_object_unreference(obj); - return ret; + goto err_unref; } dev_priv->status_gfx_addr = obj_priv->gtt_offset; @@ -4580,10 +4674,16 @@ i915_gem_init_hws(struct drm_device *dev) if (dev_priv->hw_status_page == NULL) { DRM_ERROR("Failed to map status page.\n"); memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); - i915_gem_object_unpin(obj); - drm_gem_object_unreference(obj); - return -EINVAL; + ret = -EINVAL; + goto err_unpin; } + + if (HAS_PIPE_CONTROL(dev)) { + ret = i915_gem_init_pipe_control(dev); + if (ret) + goto err_unpin; + } + dev_priv->hws_obj = obj; memset(dev_priv->hw_status_page, 0, PAGE_SIZE); if (IS_GEN6(dev)) { @@ -4596,6 +4696,30 @@ i915_gem_init_hws(struct drm_device *dev) DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr); return 0; + +err_unpin: + i915_gem_object_unpin(obj); +err_unref: + drm_gem_object_unreference(obj); +err: + return 0; +} + +static void +i915_gem_cleanup_pipe_control(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_gem_object *obj; + struct drm_i915_gem_object *obj_priv; + + obj = dev_priv->seqno_obj; + obj_priv = to_intel_bo(obj); + kunmap(obj_priv->pages[0]); + i915_gem_object_unpin(obj); + drm_gem_object_unreference(obj); + dev_priv->seqno_obj = NULL; + + dev_priv->seqno_page = NULL; } static void @@ -4619,6 +4743,9 @@ i915_gem_cleanup_hws(struct drm_device *dev) memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map)); dev_priv->hw_status_page = NULL; + if (HAS_PIPE_CONTROL(dev)) + i915_gem_cleanup_pipe_control(dev); + /* Write high address into HWS_PGA when disabling. */ I915_WRITE(HWS_PGA, 0x1ffff000); } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 449157f7161..4bdccefcf2c 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -202,21 +202,17 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) * reg, so dont bother to check the size */ if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) return false; - } else if (IS_I9XX(dev)) { - uint32_t pitch_val = ffs(stride / tile_width) - 1; - - /* XXX: For Y tiling, FENCE_MAX_PITCH_VAL is actually 6 (8KB) - * instead of 4 (2KB) on 945s. - */ - if (pitch_val > I915_FENCE_MAX_PITCH_VAL || - size > (I830_FENCE_MAX_SIZE_VAL << 20)) + } else if (IS_GEN3(dev) || IS_GEN2(dev)) { + if (stride > 8192) return false; - } else { - uint32_t pitch_val = ffs(stride / tile_width) - 1; - if (pitch_val > I830_FENCE_MAX_PITCH_VAL || - size > (I830_FENCE_MAX_SIZE_VAL << 19)) - return false; + if (IS_GEN3(dev)) { + if (size > I830_FENCE_MAX_SIZE_VAL << 20) + return false; + } else { + if (size > I830_FENCE_MAX_SIZE_VAL << 19) + return false; + } } /* 965+ just needs multiples of tile width */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6421481d622..2b8b969d0c1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -349,7 +349,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev) READ_BREADCRUMB(dev_priv); } - if (gt_iir & GT_USER_INTERRUPT) { + if (gt_iir & GT_PIPE_NOTIFY) { u32 seqno = i915_get_gem_seqno(dev); dev_priv->mm.irq_gem_seqno = seqno; trace_i915_gem_request_complete(dev, seqno); @@ -1005,7 +1005,7 @@ void i915_user_irq_get(struct drm_device *dev) spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) { if (HAS_PCH_SPLIT(dev)) - ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT); + ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); else i915_enable_irq(dev_priv, I915_USER_INTERRUPT); } @@ -1021,7 +1021,7 @@ void i915_user_irq_put(struct drm_device *dev) BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0); if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { if (HAS_PCH_SPLIT(dev)) - ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT); + ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY); else i915_disable_irq(dev_priv, I915_USER_INTERRUPT); } @@ -1305,7 +1305,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; - u32 render_mask = GT_USER_INTERRUPT; + u32 render_mask = GT_PIPE_NOTIFY; u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/i915_opregion.c index 7cc8410239c..8fcc75c1aa2 100644 --- a/drivers/gpu/drm/i915/i915_opregion.c +++ b/drivers/gpu/drm/i915/i915_opregion.c @@ -382,8 +382,57 @@ static void intel_didl_outputs(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; struct drm_connector *connector; + acpi_handle handle; + struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; + unsigned long long device_id; + acpi_status status; int i = 0; + handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) + return; + + if (acpi_is_video_device(acpi_dev)) + acpi_video_bus = acpi_dev; + else { + list_for_each_entry(acpi_cdev, &acpi_dev->children, node) { + if (acpi_is_video_device(acpi_cdev)) { + acpi_video_bus = acpi_cdev; + break; + } + } + } + + if (!acpi_video_bus) { + printk(KERN_WARNING "No ACPI video bus found\n"); + return; + } + + list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { + if (i >= 8) { + dev_printk (KERN_ERR, &dev->pdev->dev, + "More than 8 outputs detected\n"); + return; + } + status = + acpi_evaluate_integer(acpi_cdev->handle, "_ADR", + NULL, &device_id); + if (ACPI_SUCCESS(status)) { + if (!device_id) + goto blind_set; + opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f); + i++; + } + } + +end: + /* If fewer than 8 outputs, the list must be null terminated */ + if (i < 8) + opregion->acpi->didl[i] = 0; + return; + +blind_set: + i = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; if (i >= 8) { @@ -416,10 +465,7 @@ static void intel_didl_outputs(struct drm_device *dev) opregion->acpi->didl[i] |= (1<<31) | output_type | i; i++; } - - /* If fewer than 8 outputs, the list must be null terminated */ - if (i < 8) - opregion->acpi->didl[i] = 0; + goto end; } int intel_opregion_init(struct drm_device *dev, int resume) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cbbf59f56df..4cbc5210fd3 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -230,6 +230,16 @@ #define ASYNC_FLIP (1<<22) #define DISPLAY_PLANE_A (0<<20) #define DISPLAY_PLANE_B (1<<20) +#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2) +#define PIPE_CONTROL_QW_WRITE (1<<14) +#define PIPE_CONTROL_DEPTH_STALL (1<<13) +#define PIPE_CONTROL_WC_FLUSH (1<<12) +#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */ +#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */ +#define PIPE_CONTROL_ISP_DIS (1<<9) +#define PIPE_CONTROL_NOTIFY (1<<8) +#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */ +#define PIPE_CONTROL_STALL_EN (1<<1) /* in addr word, Ironlake+ only */ /* * Fence registers @@ -241,7 +251,7 @@ #define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) #define I830_FENCE_PITCH_SHIFT 4 #define I830_FENCE_REG_VALID (1<<0) -#define I915_FENCE_MAX_PITCH_VAL 0x10 +#define I915_FENCE_MAX_PITCH_VAL 4 #define I830_FENCE_MAX_PITCH_VAL 6 #define I830_FENCE_MAX_SIZE_VAL (1<<8) @@ -2285,6 +2295,7 @@ #define DEIER 0x4400c /* GT interrupt */ +#define GT_PIPE_NOTIFY (1 << 4) #define GT_SYNC_STATUS (1 << 2) #define GT_USER_INTERRUPT (1 << 0) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e7356fb6c91..c7502b6b160 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4853,17 +4853,18 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_wm = g4x_update_wm; else if (IS_I965G(dev)) dev_priv->display.update_wm = i965_update_wm; - else if (IS_I9XX(dev) || IS_MOBILE(dev)) { + else if (IS_I9XX(dev)) { dev_priv->display.update_wm = i9xx_update_wm; dev_priv->display.get_fifo_size = i9xx_get_fifo_size; + } else if (IS_I85X(dev)) { + dev_priv->display.update_wm = i9xx_update_wm; + dev_priv->display.get_fifo_size = i85x_get_fifo_size; } else { - if (IS_I85X(dev)) - dev_priv->display.get_fifo_size = i85x_get_fifo_size; - else if (IS_845G(dev)) + dev_priv->display.update_wm = i830_update_wm; + if (IS_845G(dev)) dev_priv->display.get_fifo_size = i845_get_fifo_size; else dev_priv->display.get_fifo_size = i830_get_fifo_size; - dev_priv->display.update_wm = i830_update_wm; } } diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 75f3fa55663..16c42024072 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -1169,15 +1169,19 @@ static int atk_create_files(struct atk_data *data) int err; list_for_each_entry(s, &data->sensor_list, list) { + sysfs_attr_init(&s->input_attr.attr); err = device_create_file(data->hwmon_dev, &s->input_attr); if (err) return err; + sysfs_attr_init(&s->label_attr.attr); err = device_create_file(data->hwmon_dev, &s->label_attr); if (err) return err; + sysfs_attr_init(&s->limit1_attr.attr); err = device_create_file(data->hwmon_dev, &s->limit1_attr); if (err) return err; + sysfs_attr_init(&s->limit2_attr.attr); err = device_create_file(data->hwmon_dev, &s->limit2_attr); if (err) return err; diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index be475e844c2..c8ab5051667 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c @@ -217,6 +217,10 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted), AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted), AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted), + AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left), + AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), + AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), + AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), { NULL, } /* Laptop models without axis info (yet): * "NC6910" "HP Compaq 6910" diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index f7e27b70237..d1ff9408dc1 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -146,10 +146,10 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy) "<%s> I2C Interrupted\n", __func__); return -EINTR; } - if (time_after(jiffies, orig_jiffies + HZ / 1000)) { + if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C bus is busy\n", __func__); - return -EIO; + return -ETIMEDOUT; } schedule(); } @@ -444,6 +444,8 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, result = i2c_imx_read(i2c_imx, &msgs[i]); else result = i2c_imx_write(i2c_imx, &msgs[i]); + if (result) + goto fail0; } fail0: diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 6bd0f19cd45..389ac6032a7 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -903,6 +903,11 @@ omap_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); + if (cpu_is_omap7xx()) + dev->reg_shift = 1; + else + dev->reg_shift = 2; + if ((r = omap_i2c_get_clocks(dev)) != 0) goto err_iounmap; @@ -926,11 +931,6 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ } - if (cpu_is_omap7xx()) - dev->reg_shift = 1; - else - dev->reg_shift = 2; - /* reset ASAP, clearing any IRQs */ omap_i2c_init(dev); diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 247103372a0..a97e3fec814 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -173,6 +173,9 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) /* We still have something to talk about... */ val = *alg_data->mif.buf++; + if (alg_data->mif.len == 1) + val |= stop_bit; + alg_data->mif.len--; iowrite32(val, I2C_REG_TX(alg_data)); @@ -246,6 +249,9 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) __func__); if (alg_data->mif.len == 1) { + /* Last byte, do not acknowledge next rcv. */ + val |= stop_bit; + /* * Enable interrupt RFDAIE (data in Rx fifo), * and disable DRMIE (need data for Tx) @@ -633,6 +639,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev) */ tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2; + if (tmp > 0x3FF) + tmp = 0x3FF; iowrite32(tmp, I2C_REG_CKH(alg_data)); iowrite32(tmp, I2C_REG_CKL(alg_data)); diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 1f5b38be73b..495be451d32 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -498,7 +498,7 @@ static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) int i = 0; /* Locate the apropriate clock setting */ - while (i < ARRAY_SIZE(stu300_clktable) && + while (i < ARRAY_SIZE(stu300_clktable) - 1 && stu300_clktable[i].rate < clkrate) i++; diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index ab87e4f7cec..defce2877ee 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -409,6 +409,8 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420), PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), + PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x3e520e17), + PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10), PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e), PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), @@ -429,6 +431,8 @@ static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2), PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x9351e59d), + PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47), PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e3e9a36ea3b..58ea0ecae7c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1650,8 +1650,8 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, int previous, int *dd_idx, struct stripe_head *sh) { - long stripe; - unsigned long chunk_number; + sector_t stripe, stripe2; + sector_t chunk_number; unsigned int chunk_offset; int pd_idx, qd_idx; int ddf_layout = 0; @@ -1671,18 +1671,13 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, */ chunk_offset = sector_div(r_sector, sectors_per_chunk); chunk_number = r_sector; - BUG_ON(r_sector != chunk_number); /* * Compute the stripe number */ - stripe = chunk_number / data_disks; - - /* - * Compute the data disk and parity disk indexes inside the stripe - */ - *dd_idx = chunk_number % data_disks; - + stripe = chunk_number; + *dd_idx = sector_div(stripe, data_disks); + stripe2 = stripe; /* * Select the parity disk based on the user selected algorithm. */ @@ -1694,21 +1689,21 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, case 5: switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: - pd_idx = data_disks - stripe % raid_disks; + pd_idx = data_disks - sector_div(stripe2, raid_disks); if (*dd_idx >= pd_idx) (*dd_idx)++; break; case ALGORITHM_RIGHT_ASYMMETRIC: - pd_idx = stripe % raid_disks; + pd_idx = sector_div(stripe2, raid_disks); if (*dd_idx >= pd_idx) (*dd_idx)++; break; case ALGORITHM_LEFT_SYMMETRIC: - pd_idx = data_disks - stripe % raid_disks; + pd_idx = data_disks - sector_div(stripe2, raid_disks); *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; break; case ALGORITHM_RIGHT_SYMMETRIC: - pd_idx = stripe % raid_disks; + pd_idx = sector_div(stripe2, raid_disks); *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; break; case ALGORITHM_PARITY_0: @@ -1728,7 +1723,7 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: - pd_idx = raid_disks - 1 - (stripe % raid_disks); + pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks); qd_idx = pd_idx + 1; if (pd_idx == raid_disks-1) { (*dd_idx)++; /* Q D D D P */ @@ -1737,7 +1732,7 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, (*dd_idx) += 2; /* D D P Q D */ break; case ALGORITHM_RIGHT_ASYMMETRIC: - pd_idx = stripe % raid_disks; + pd_idx = sector_div(stripe2, raid_disks); qd_idx = pd_idx + 1; if (pd_idx == raid_disks-1) { (*dd_idx)++; /* Q D D D P */ @@ -1746,12 +1741,12 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, (*dd_idx) += 2; /* D D P Q D */ break; case ALGORITHM_LEFT_SYMMETRIC: - pd_idx = raid_disks - 1 - (stripe % raid_disks); + pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks); qd_idx = (pd_idx + 1) % raid_disks; *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; break; case ALGORITHM_RIGHT_SYMMETRIC: - pd_idx = stripe % raid_disks; + pd_idx = sector_div(stripe2, raid_disks); qd_idx = (pd_idx + 1) % raid_disks; *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; break; @@ -1770,7 +1765,7 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, /* Exactly the same as RIGHT_ASYMMETRIC, but or * of blocks for computing Q is different. */ - pd_idx = stripe % raid_disks; + pd_idx = sector_div(stripe2, raid_disks); qd_idx = pd_idx + 1; if (pd_idx == raid_disks-1) { (*dd_idx)++; /* Q D D D P */ @@ -1785,7 +1780,8 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, * D D D P Q rather than * Q D D D P */ - pd_idx = raid_disks - 1 - ((stripe + 1) % raid_disks); + stripe2 += 1; + pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks); qd_idx = pd_idx + 1; if (pd_idx == raid_disks-1) { (*dd_idx)++; /* Q D D D P */ @@ -1797,7 +1793,7 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, case ALGORITHM_ROTATING_N_CONTINUE: /* Same as left_symmetric but Q is before P */ - pd_idx = raid_disks - 1 - (stripe % raid_disks); + pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks); qd_idx = (pd_idx + raid_disks - 1) % raid_disks; *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; ddf_layout = 1; @@ -1805,27 +1801,27 @@ static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, case ALGORITHM_LEFT_ASYMMETRIC_6: /* RAID5 left_asymmetric, with Q on last device */ - pd_idx = data_disks - stripe % (raid_disks-1); + pd_idx = data_disks - sector_div(stripe2, raid_disks-1); if (*dd_idx >= pd_idx) (*dd_idx)++; qd_idx = raid_disks - 1; break; case ALGORITHM_RIGHT_ASYMMETRIC_6: - pd_idx = stripe % (raid_disks-1); + pd_idx = sector_div(stripe2, raid_disks-1); if (*dd_idx >= pd_idx) (*dd_idx)++; qd_idx = raid_disks - 1; break; case ALGORITHM_LEFT_SYMMETRIC_6: - pd_idx = data_disks - stripe % (raid_disks-1); + pd_idx = data_disks - sector_div(stripe2, raid_disks-1); *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); qd_idx = raid_disks - 1; break; case ALGORITHM_RIGHT_SYMMETRIC_6: - pd_idx = stripe % (raid_disks-1); + pd_idx = sector_div(stripe2, raid_disks-1); *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); qd_idx = raid_disks - 1; break; @@ -1870,14 +1866,14 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous) : conf->algorithm; sector_t stripe; int chunk_offset; - int chunk_number, dummy1, dd_idx = i; + sector_t chunk_number; + int dummy1, dd_idx = i; sector_t r_sector; struct stripe_head sh2; chunk_offset = sector_div(new_sector, sectors_per_chunk); stripe = new_sector; - BUG_ON(new_sector != stripe); if (i == sh->pd_idx) return 0; @@ -1970,7 +1966,7 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous) } chunk_number = stripe * data_disks + i; - r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset; + r_sector = chunk_number * sectors_per_chunk + chunk_offset; check = raid5_compute_sector(conf, r_sector, previous, &dummy1, &sh2); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2191c8d896a..0d0d625fece 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -311,6 +311,22 @@ config TI_DAC7512 This driver can also be built as a module. If so, the module will be calles ti_dac7512. +config VMWARE_BALLOON + tristate "VMware Balloon Driver" + depends on X86 + help + This is VMware physical memory management driver which acts + like a "balloon" that can be inflated to reclaim physical pages + by reserving them in the guest and invalidating them in the + monitor, freeing up the underlying machine pages so they can + be allocated to other guests. The balloon can also be deflated + to allow the guest to use more physical memory. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called vmware_balloon. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 27c48435541..7b6f7eefdf8 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_C2PORT) += c2port/ obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ obj-y += eeprom/ obj-y += cb710/ +obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o diff --git a/drivers/misc/vmware_balloon.c b/drivers/misc/vmware_balloon.c new file mode 100644 index 00000000000..e7161c4e379 --- /dev/null +++ b/drivers/misc/vmware_balloon.c @@ -0,0 +1,832 @@ +/* + * VMware Balloon driver. + * + * Copyright (C) 2000-2010, VMware, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Maintained by: Dmitry Torokhov <dtor@vmware.com> + */ + +/* + * This is VMware physical memory management driver for Linux. The driver + * acts like a "balloon" that can be inflated to reclaim physical pages by + * reserving them in the guest and invalidating them in the monitor, + * freeing up the underlying machine pages so they can be allocated to + * other guests. The balloon can also be deflated to allow the guest to + * use more physical memory. Higher level policies can control the sizes + * of balloons in VMs in order to manage physical memory resources. + */ + +//#define DEBUG +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/workqueue.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <asm/vmware.h> + +MODULE_AUTHOR("VMware, Inc."); +MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); +MODULE_VERSION("1.2.1.0-K"); +MODULE_ALIAS("dmi:*:svnVMware*:*"); +MODULE_ALIAS("vmware_vmmemctl"); +MODULE_LICENSE("GPL"); + +/* + * Various constants controlling rate of inflaint/deflating balloon, + * measured in pages. + */ + +/* + * Rate of allocating memory when there is no memory pressure + * (driver performs non-sleeping allocations). + */ +#define VMW_BALLOON_NOSLEEP_ALLOC_MAX 16384U + +/* + * Rates of memory allocaton when guest experiences memory pressure + * (driver performs sleeping allocations). + */ +#define VMW_BALLOON_RATE_ALLOC_MIN 512U +#define VMW_BALLOON_RATE_ALLOC_MAX 2048U +#define VMW_BALLOON_RATE_ALLOC_INC 16U + +/* + * Rates for releasing pages while deflating balloon. + */ +#define VMW_BALLOON_RATE_FREE_MIN 512U +#define VMW_BALLOON_RATE_FREE_MAX 16384U +#define VMW_BALLOON_RATE_FREE_INC 16U + +/* + * When guest is under memory pressure, use a reduced page allocation + * rate for next several cycles. + */ +#define VMW_BALLOON_SLOW_CYCLES 4 + +/* + * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't + * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use + * __GFP_NOWARN, to suppress page allocation failure warnings. + */ +#define VMW_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM|__GFP_NOWARN) + +/* + * Use GFP_HIGHUSER when executing in a separate kernel thread + * context and allocation can sleep. This is less stressful to + * the guest memory system, since it allows the thread to block + * while memory is reclaimed, and won't take pages from emergency + * low-memory pools. + */ +#define VMW_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER) + +/* Maximum number of page allocations without yielding processor */ +#define VMW_BALLOON_YIELD_THRESHOLD 1024 + + +/* + * Hypervisor communication port definitions. + */ +#define VMW_BALLOON_HV_PORT 0x5670 +#define VMW_BALLOON_HV_MAGIC 0x456c6d6f +#define VMW_BALLOON_PROTOCOL_VERSION 2 +#define VMW_BALLOON_GUEST_ID 1 /* Linux */ + +#define VMW_BALLOON_CMD_START 0 +#define VMW_BALLOON_CMD_GET_TARGET 1 +#define VMW_BALLOON_CMD_LOCK 2 +#define VMW_BALLOON_CMD_UNLOCK 3 +#define VMW_BALLOON_CMD_GUEST_ID 4 + +/* error codes */ +#define VMW_BALLOON_SUCCESS 0 +#define VMW_BALLOON_FAILURE -1 +#define VMW_BALLOON_ERROR_CMD_INVALID 1 +#define VMW_BALLOON_ERROR_PPN_INVALID 2 +#define VMW_BALLOON_ERROR_PPN_LOCKED 3 +#define VMW_BALLOON_ERROR_PPN_UNLOCKED 4 +#define VMW_BALLOON_ERROR_PPN_PINNED 5 +#define VMW_BALLOON_ERROR_PPN_NOTNEEDED 6 +#define VMW_BALLOON_ERROR_RESET 7 +#define VMW_BALLOON_ERROR_BUSY 8 + +#define VMWARE_BALLOON_CMD(cmd, data, result) \ +({ \ + unsigned long __stat, __dummy1, __dummy2; \ + __asm__ __volatile__ ("inl (%%dx)" : \ + "=a"(__stat), \ + "=c"(__dummy1), \ + "=d"(__dummy2), \ + "=b"(result) : \ + "0"(VMW_BALLOON_HV_MAGIC), \ + "1"(VMW_BALLOON_CMD_##cmd), \ + "2"(VMW_BALLOON_HV_PORT), \ + "3"(data) : \ + "memory"); \ + result &= -1UL; \ + __stat & -1UL; \ +}) + +#ifdef CONFIG_DEBUG_FS +struct vmballoon_stats { + unsigned int timer; + + /* allocation statustics */ + unsigned int alloc; + unsigned int alloc_fail; + unsigned int sleep_alloc; + unsigned int sleep_alloc_fail; + unsigned int refused_alloc; + unsigned int refused_free; + unsigned int free; + + /* monitor operations */ + unsigned int lock; + unsigned int lock_fail; + unsigned int unlock; + unsigned int unlock_fail; + unsigned int target; + unsigned int target_fail; + unsigned int start; + unsigned int start_fail; + unsigned int guest_type; + unsigned int guest_type_fail; +}; + +#define STATS_INC(stat) (stat)++ +#else +#define STATS_INC(stat) +#endif + +struct vmballoon { + + /* list of reserved physical pages */ + struct list_head pages; + + /* transient list of non-balloonable pages */ + struct list_head refused_pages; + + /* balloon size in pages */ + unsigned int size; + unsigned int target; + + /* reset flag */ + bool reset_required; + + /* adjustment rates (pages per second) */ + unsigned int rate_alloc; + unsigned int rate_free; + + /* slowdown page allocations for next few cycles */ + unsigned int slow_allocation_cycles; + +#ifdef CONFIG_DEBUG_FS + /* statistics */ + struct vmballoon_stats stats; + + /* debugfs file exporting statistics */ + struct dentry *dbg_entry; +#endif + + struct sysinfo sysinfo; + + struct delayed_work dwork; +}; + +static struct vmballoon balloon; +static struct workqueue_struct *vmballoon_wq; + +/* + * Send "start" command to the host, communicating supported version + * of the protocol. + */ +static bool vmballoon_send_start(struct vmballoon *b) +{ + unsigned long status, dummy; + + STATS_INC(b->stats.start); + + status = VMWARE_BALLOON_CMD(START, VMW_BALLOON_PROTOCOL_VERSION, dummy); + if (status == VMW_BALLOON_SUCCESS) + return true; + + pr_debug("%s - failed, hv returns %ld\n", __func__, status); + STATS_INC(b->stats.start_fail); + return false; +} + +static bool vmballoon_check_status(struct vmballoon *b, unsigned long status) +{ + switch (status) { + case VMW_BALLOON_SUCCESS: + return true; + + case VMW_BALLOON_ERROR_RESET: + b->reset_required = true; + /* fall through */ + + default: + return false; + } +} + +/* + * Communicate guest type to the host so that it can adjust ballooning + * algorithm to the one most appropriate for the guest. This command + * is normally issued after sending "start" command and is part of + * standard reset sequence. + */ +static bool vmballoon_send_guest_id(struct vmballoon *b) +{ + unsigned long status, dummy; + + status = VMWARE_BALLOON_CMD(GUEST_ID, VMW_BALLOON_GUEST_ID, dummy); + + STATS_INC(b->stats.guest_type); + + if (vmballoon_check_status(b, status)) + return true; + + pr_debug("%s - failed, hv returns %ld\n", __func__, status); + STATS_INC(b->stats.guest_type_fail); + return false; +} + +/* + * Retrieve desired balloon size from the host. + */ +static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) +{ + unsigned long status; + unsigned long target; + unsigned long limit; + u32 limit32; + + /* + * si_meminfo() is cheap. Moreover, we want to provide dynamic + * max balloon size later. So let us call si_meminfo() every + * iteration. + */ + si_meminfo(&b->sysinfo); + limit = b->sysinfo.totalram; + + /* Ensure limit fits in 32-bits */ + limit32 = (u32)limit; + if (limit != limit32) + return false; + + /* update stats */ + STATS_INC(b->stats.target); + + status = VMWARE_BALLOON_CMD(GET_TARGET, limit, target); + if (vmballoon_check_status(b, status)) { + *new_target = target; + return true; + } + + pr_debug("%s - failed, hv returns %ld\n", __func__, status); + STATS_INC(b->stats.target_fail); + return false; +} + +/* + * Notify the host about allocated page so that host can use it without + * fear that guest will need it. Host may reject some pages, we need to + * check the return value and maybe submit a different page. + */ +static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) +{ + unsigned long status, dummy; + u32 pfn32; + + pfn32 = (u32)pfn; + if (pfn32 != pfn) + return false; + + STATS_INC(b->stats.lock); + + status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); + if (vmballoon_check_status(b, status)) + return true; + + pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); + STATS_INC(b->stats.lock_fail); + return false; +} + +/* + * Notify the host that guest intends to release given page back into + * the pool of available (to the guest) pages. + */ +static bool vmballoon_send_unlock_page(struct vmballoon *b, unsigned long pfn) +{ + unsigned long status, dummy; + u32 pfn32; + + pfn32 = (u32)pfn; + if (pfn32 != pfn) + return false; + + STATS_INC(b->stats.unlock); + + status = VMWARE_BALLOON_CMD(UNLOCK, pfn, dummy); + if (vmballoon_check_status(b, status)) + return true; + + pr_debug("%s - ppn %lx, hv returns %ld\n", __func__, pfn, status); + STATS_INC(b->stats.unlock_fail); + return false; +} + +/* + * Quickly release all pages allocated for the balloon. This function is + * called when host decides to "reset" balloon for one reason or another. + * Unlike normal "deflate" we do not (shall not) notify host of the pages + * being released. + */ +static void vmballoon_pop(struct vmballoon *b) +{ + struct page *page, *next; + unsigned int count = 0; + + list_for_each_entry_safe(page, next, &b->pages, lru) { + list_del(&page->lru); + __free_page(page); + STATS_INC(b->stats.free); + b->size--; + + if (++count >= b->rate_free) { + count = 0; + cond_resched(); + } + } +} + +/* + * Perform standard reset sequence by popping the balloon (in case it + * is not empty) and then restarting protocol. This operation normally + * happens when host responds with VMW_BALLOON_ERROR_RESET to a command. + */ +static void vmballoon_reset(struct vmballoon *b) +{ + /* free all pages, skipping monitor unlock */ + vmballoon_pop(b); + + if (vmballoon_send_start(b)) { + b->reset_required = false; + if (!vmballoon_send_guest_id(b)) + pr_err("failed to send guest ID to the host\n"); + } +} + +/* + * Allocate (or reserve) a page for the balloon and notify the host. If host + * refuses the page put it on "refuse" list and allocate another one until host + * is satisfied. "Refused" pages are released at the end of inflation cycle + * (when we allocate b->rate_alloc pages). + */ +static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) +{ + struct page *page; + gfp_t flags; + bool locked = false; + + do { + if (!can_sleep) + STATS_INC(b->stats.alloc); + else + STATS_INC(b->stats.sleep_alloc); + + flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP; + page = alloc_page(flags); + if (!page) { + if (!can_sleep) + STATS_INC(b->stats.alloc_fail); + else + STATS_INC(b->stats.sleep_alloc_fail); + return -ENOMEM; + } + + /* inform monitor */ + locked = vmballoon_send_lock_page(b, page_to_pfn(page)); + if (!locked) { + if (b->reset_required) { + __free_page(page); + return -EIO; + } + + /* place on list of non-balloonable pages, retry allocation */ + list_add(&page->lru, &b->refused_pages); + STATS_INC(b->stats.refused_alloc); + } + } while (!locked); + + /* track allocated page */ + list_add(&page->lru, &b->pages); + + /* update balloon size */ + b->size++; + + return 0; +} + +/* + * Release the page allocated for the balloon. Note that we first notify + * the host so it can make sure the page will be available for the guest + * to use, if needed. + */ +static int vmballoon_release_page(struct vmballoon *b, struct page *page) +{ + if (!vmballoon_send_unlock_page(b, page_to_pfn(page))) + return -EIO; + + list_del(&page->lru); + + /* deallocate page */ + __free_page(page); + STATS_INC(b->stats.free); + + /* update balloon size */ + b->size--; + + return 0; +} + +/* + * Release pages that were allocated while attempting to inflate the + * balloon but were refused by the host for one reason or another. + */ +static void vmballoon_release_refused_pages(struct vmballoon *b) +{ + struct page *page, *next; + + list_for_each_entry_safe(page, next, &b->refused_pages, lru) { + list_del(&page->lru); + __free_page(page); + STATS_INC(b->stats.refused_free); + } +} + +/* + * Inflate the balloon towards its target size. Note that we try to limit + * the rate of allocation to make sure we are not choking the rest of the + * system. + */ +static void vmballoon_inflate(struct vmballoon *b) +{ + unsigned int goal; + unsigned int rate; + unsigned int i; + unsigned int allocations = 0; + int error = 0; + bool alloc_can_sleep = false; + + pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); + + /* + * First try NOSLEEP page allocations to inflate balloon. + * + * If we do not throttle nosleep allocations, we can drain all + * free pages in the guest quickly (if the balloon target is high). + * As a side-effect, draining free pages helps to inform (force) + * the guest to start swapping if balloon target is not met yet, + * which is a desired behavior. However, balloon driver can consume + * all available CPU cycles if too many pages are allocated in a + * second. Therefore, we throttle nosleep allocations even when + * the guest is not under memory pressure. OTOH, if we have already + * predicted that the guest is under memory pressure, then we + * slowdown page allocations considerably. + */ + + goal = b->target - b->size; + /* + * Start with no sleep allocation rate which may be higher + * than sleeping allocation rate. + */ + rate = b->slow_allocation_cycles ? + b->rate_alloc : VMW_BALLOON_NOSLEEP_ALLOC_MAX; + + pr_debug("%s - goal: %d, no-sleep rate: %d, sleep rate: %d\n", + __func__, goal, rate, b->rate_alloc); + + for (i = 0; i < goal; i++) { + + error = vmballoon_reserve_page(b, alloc_can_sleep); + if (error) { + if (error != -ENOMEM) { + /* + * Not a page allocation failure, stop this + * cycle. Maybe we'll get new target from + * the host soon. + */ + break; + } + + if (alloc_can_sleep) { + /* + * CANSLEEP page allocation failed, so guest + * is under severe memory pressure. Quickly + * decrease allocation rate. + */ + b->rate_alloc = max(b->rate_alloc / 2, + VMW_BALLOON_RATE_ALLOC_MIN); + break; + } + + /* + * NOSLEEP page allocation failed, so the guest is + * under memory pressure. Let us slow down page + * allocations for next few cycles so that the guest + * gets out of memory pressure. Also, if we already + * allocated b->rate_alloc pages, let's pause, + * otherwise switch to sleeping allocations. + */ + b->slow_allocation_cycles = VMW_BALLOON_SLOW_CYCLES; + + if (i >= b->rate_alloc) + break; + + alloc_can_sleep = true; + /* Lower rate for sleeping allocations. */ + rate = b->rate_alloc; + } + + if (++allocations > VMW_BALLOON_YIELD_THRESHOLD) { + cond_resched(); + allocations = 0; + } + + if (i >= rate) { + /* We allocated enough pages, let's take a break. */ + break; + } + } + + /* + * We reached our goal without failures so try increasing + * allocation rate. + */ + if (error == 0 && i >= b->rate_alloc) { + unsigned int mult = i / b->rate_alloc; + + b->rate_alloc = + min(b->rate_alloc + mult * VMW_BALLOON_RATE_ALLOC_INC, + VMW_BALLOON_RATE_ALLOC_MAX); + } + + vmballoon_release_refused_pages(b); +} + +/* + * Decrease the size of the balloon allowing guest to use more memory. + */ +static void vmballoon_deflate(struct vmballoon *b) +{ + struct page *page, *next; + unsigned int i = 0; + unsigned int goal; + int error; + + pr_debug("%s - size: %d, target %d\n", __func__, b->size, b->target); + + /* limit deallocation rate */ + goal = min(b->size - b->target, b->rate_free); + + pr_debug("%s - goal: %d, rate: %d\n", __func__, goal, b->rate_free); + + /* free pages to reach target */ + list_for_each_entry_safe(page, next, &b->pages, lru) { + error = vmballoon_release_page(b, page); + if (error) { + /* quickly decrease rate in case of error */ + b->rate_free = max(b->rate_free / 2, + VMW_BALLOON_RATE_FREE_MIN); + return; + } + + if (++i >= goal) + break; + } + + /* slowly increase rate if there were no errors */ + b->rate_free = min(b->rate_free + VMW_BALLOON_RATE_FREE_INC, + VMW_BALLOON_RATE_FREE_MAX); +} + +/* + * Balloon work function: reset protocol, if needed, get the new size and + * adjust balloon as needed. Repeat in 1 sec. + */ +static void vmballoon_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct vmballoon *b = container_of(dwork, struct vmballoon, dwork); + unsigned int target; + + STATS_INC(b->stats.timer); + + if (b->reset_required) + vmballoon_reset(b); + + if (b->slow_allocation_cycles > 0) + b->slow_allocation_cycles--; + + if (vmballoon_send_get_target(b, &target)) { + /* update target, adjust size */ + b->target = target; + + if (b->size < target) + vmballoon_inflate(b); + else if (b->size > target) + vmballoon_deflate(b); + } + + queue_delayed_work(vmballoon_wq, dwork, round_jiffies_relative(HZ)); +} + +/* + * DEBUGFS Interface + */ +#ifdef CONFIG_DEBUG_FS + +static int vmballoon_debug_show(struct seq_file *f, void *offset) +{ + struct vmballoon *b = f->private; + struct vmballoon_stats *stats = &b->stats; + + /* format size info */ + seq_printf(f, + "target: %8d pages\n" + "current: %8d pages\n", + b->target, b->size); + + /* format rate info */ + seq_printf(f, + "rateNoSleepAlloc: %8d pages/sec\n" + "rateSleepAlloc: %8d pages/sec\n" + "rateFree: %8d pages/sec\n", + VMW_BALLOON_NOSLEEP_ALLOC_MAX, + b->rate_alloc, b->rate_free); + + seq_printf(f, + "\n" + "timer: %8u\n" + "start: %8u (%4u failed)\n" + "guestType: %8u (%4u failed)\n" + "lock: %8u (%4u failed)\n" + "unlock: %8u (%4u failed)\n" + "target: %8u (%4u failed)\n" + "primNoSleepAlloc: %8u (%4u failed)\n" + "primCanSleepAlloc: %8u (%4u failed)\n" + "primFree: %8u\n" + "errAlloc: %8u\n" + "errFree: %8u\n", + stats->timer, + stats->start, stats->start_fail, + stats->guest_type, stats->guest_type_fail, + stats->lock, stats->lock_fail, + stats->unlock, stats->unlock_fail, + stats->target, stats->target_fail, + stats->alloc, stats->alloc_fail, + stats->sleep_alloc, stats->sleep_alloc_fail, + stats->free, + stats->refused_alloc, stats->refused_free); + + return 0; +} + +static int vmballoon_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, vmballoon_debug_show, inode->i_private); +} + +static const struct file_operations vmballoon_debug_fops = { + .owner = THIS_MODULE, + .open = vmballoon_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init vmballoon_debugfs_init(struct vmballoon *b) +{ + int error; + + b->dbg_entry = debugfs_create_file("vmmemctl", S_IRUGO, NULL, b, + &vmballoon_debug_fops); + if (IS_ERR(b->dbg_entry)) { + error = PTR_ERR(b->dbg_entry); + pr_err("failed to create debugfs entry, error: %d\n", error); + return error; + } + + return 0; +} + +static void __exit vmballoon_debugfs_exit(struct vmballoon *b) +{ + debugfs_remove(b->dbg_entry); +} + +#else + +static inline int vmballoon_debugfs_init(struct vmballoon *b) +{ + return 0; +} + +static inline void vmballoon_debugfs_exit(struct vmballoon *b) +{ +} + +#endif /* CONFIG_DEBUG_FS */ + +static int __init vmballoon_init(void) +{ + int error; + + /* + * Check if we are running on VMware's hypervisor and bail out + * if we are not. + */ + if (!vmware_platform()) + return -ENODEV; + + vmballoon_wq = create_freezeable_workqueue("vmmemctl"); + if (!vmballoon_wq) { + pr_err("failed to create workqueue\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&balloon.pages); + INIT_LIST_HEAD(&balloon.refused_pages); + + /* initialize rates */ + balloon.rate_alloc = VMW_BALLOON_RATE_ALLOC_MAX; + balloon.rate_free = VMW_BALLOON_RATE_FREE_MAX; + + INIT_DELAYED_WORK(&balloon.dwork, vmballoon_work); + + /* + * Start balloon. + */ + if (!vmballoon_send_start(&balloon)) { + pr_err("failed to send start command to the host\n"); + error = -EIO; + goto fail; + } + + if (!vmballoon_send_guest_id(&balloon)) { + pr_err("failed to send guest ID to the host\n"); + error = -EIO; + goto fail; + } + + error = vmballoon_debugfs_init(&balloon); + if (error) + goto fail; + + queue_delayed_work(vmballoon_wq, &balloon.dwork, 0); + + return 0; + +fail: + destroy_workqueue(vmballoon_wq); + return error; +} +module_init(vmballoon_init); + +static void __exit vmballoon_exit(void) +{ + cancel_delayed_work_sync(&balloon.dwork); + destroy_workqueue(vmballoon_wq); + + vmballoon_debugfs_exit(&balloon); + + /* + * Deallocate all reserved memory, and reset connection with monitor. + * Reset connection before deallocating memory to avoid potential for + * additional spurious resets from guest touching deallocated pages. + */ + vmballoon_send_start(&balloon); + vmballoon_pop(&balloon); +} +module_exit(vmballoon_exit); diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index f59c07427af..d60fc5719fe 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -60,7 +60,13 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) } buf64 = (uint64_t *)buf; while (i < len/8) { - uint64_t x; + /* + * Since GCC has no proper constraint (PR 43518) + * force x variable to r2/r3 registers as ldrd instruction + * requires first register to be even. + */ + register uint64_t x asm ("r2"); + asm volatile ("ldrd\t%0, [%1]" : "=&r" (x) : "r" (io_base)); buf64[i++] = x; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5ea587e59e4..37499127c80 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -679,7 +679,7 @@ static void __pci_start_power_transition(struct pci_dev *dev, pci_power_t state) */ int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state) { - return state > PCI_D0 ? + return state >= PCI_D0 ? pci_platform_power_transition(dev, state) : -EINVAL; } EXPORT_SYMBOL_GPL(__pci_complete_power_transition); @@ -716,10 +716,6 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) */ return 0; - /* Check if we're already there */ - if (dev->current_state == state) - return 0; - __pci_start_power_transition(dev, state); /* This device is quirked not to be put into D3, so diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index aa495ad9bbd..7a711ee314b 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -244,11 +244,17 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev) /* Assert Secondary Bus Reset */ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl); - p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET; + p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET; pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); + /* + * we should send hot reset message for 2ms to allow it time to + * propogate to all downstream ports + */ + msleep(2); + /* De-assert Secondary Bus Reset */ - p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET; + p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); /* diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 882bd8d29fe..c82548afcd5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -174,19 +174,14 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pci_read_config_dword(dev, pos, &sz); pci_write_config_dword(dev, pos, l); - if (!sz) - goto fail; /* BAR not implemented */ - /* * All bits set in sz means the device isn't working properly. - * If it's a memory BAR or a ROM, bit 0 must be clear; if it's - * an io BAR, bit 1 must be clear. + * If the BAR isn't implemented, all bits must be 0. If it's a + * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit + * 1 must be clear. */ - if (sz == 0xffffffff) { - dev_err(&dev->dev, "reg %x: invalid size %#x; broken device?\n", - pos, sz); + if (!sz || sz == 0xffffffff) goto fail; - } /* * I don't know how l can have all bits set. Copied from old code. @@ -249,17 +244,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pos, res); } } else { - u32 size = pci_size(l, sz, mask); + sz = pci_size(l, sz, mask); - if (!size) { - dev_err(&dev->dev, "reg %x: invalid size " - "(l %#x sz %#x mask %#x); broken device?", - pos, l, sz, mask); + if (!sz) goto fail; - } res->start = l; - res->end = l + size; + res->end = l + sz; dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); } diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7bec4588c26..6c3320d7505 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -390,6 +390,7 @@ config EEEPC_WMI depends on ACPI_WMI depends on INPUT depends on EXPERIMENTAL + select INPUT_SPARSEKMAP ---help--- Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 52262b012ab..efe8f638890 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -79,15 +79,15 @@ static uint wapf = 1; module_param(wapf, uint, 0644); MODULE_PARM_DESC(wapf, "WAPF value"); -static uint wlan_status = 1; -static uint bluetooth_status = 1; +static int wlan_status = 1; +static int bluetooth_status = 1; -module_param(wlan_status, uint, 0644); +module_param(wlan_status, int, 0644); MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " "default is 1"); -module_param(bluetooth_status, uint, 0644); +module_param(bluetooth_status, int, 0644); MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " "default is 1"); diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 6ba6c30e5bb..66f53c3c35e 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -217,6 +217,7 @@ static void dell_wmi_notify(u32 value, void *context) if (dell_new_hk_type && (buffer_entry[1] != 0x10)) { printk(KERN_INFO "dell-wmi: Received unknown WMI event" " (0x%x)\n", buffer_entry[1]); + kfree(obj); return; } @@ -234,7 +235,7 @@ static void dell_wmi_notify(u32 value, void *context) key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) { /* Don't report brightness notifications that will also * come via ACPI */ - return; + ; } else { input_report_key(dell_wmi_input_dev, key->keycode, 1); input_sync(dell_wmi_input_dev); diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 54a015785ca..0306174ba87 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -169,7 +169,6 @@ struct eeepc_laptop { struct backlight_device *backlight_device; struct input_dev *inputdev; - struct key_entry *keymap; struct rfkill *wlan_rfkill; struct rfkill *bluetooth_rfkill; @@ -1204,8 +1203,8 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc) static void eeepc_input_exit(struct eeepc_laptop *eeepc) { if (eeepc->inputdev) { + sparse_keymap_free(eeepc->inputdev); input_unregister_device(eeepc->inputdev); - kfree(eeepc->keymap); } } diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 9f8822658fd..b227eb469f4 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -23,6 +23,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -30,22 +32,34 @@ #include <linux/slab.h> #include <linux/input.h> #include <linux/input/sparse-keymap.h> +#include <linux/fb.h> +#include <linux/backlight.h> +#include <linux/platform_device.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#define EEEPC_WMI_FILE "eeepc-wmi" + MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); MODULE_LICENSE("GPL"); #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" +#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); +MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define NOTIFY_BRNUP_MIN 0x11 #define NOTIFY_BRNUP_MAX 0x1f #define NOTIFY_BRNDOWN_MIN 0x20 #define NOTIFY_BRNDOWN_MAX 0x2e +#define EEEPC_WMI_METHODID_DEVS 0x53564544 +#define EEEPC_WMI_METHODID_DSTS 0x53544344 + +#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 + static const struct key_entry eeepc_wmi_keymap[] = { /* Sleep already handled via generic ACPI code */ { KE_KEY, 0x5d, { KEY_WLAN } }, @@ -58,18 +72,198 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_END, 0}, }; -static struct input_dev *eeepc_wmi_input_dev; +struct bios_args { + u32 dev_id; + u32 ctrl_param; +}; + +struct eeepc_wmi { + struct input_dev *inputdev; + struct backlight_device *backlight_device; +}; + +static struct platform_device *platform_device; + +static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) +{ + int err; + + eeepc->inputdev = input_allocate_device(); + if (!eeepc->inputdev) + return -ENOMEM; + + eeepc->inputdev->name = "Eee PC WMI hotkeys"; + eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; + eeepc->inputdev->id.bustype = BUS_HOST; + eeepc->inputdev->dev.parent = &platform_device->dev; + + err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); + if (err) + goto err_free_dev; + + err = input_register_device(eeepc->inputdev); + if (err) + goto err_free_keymap; + + return 0; + +err_free_keymap: + sparse_keymap_free(eeepc->inputdev); +err_free_dev: + input_free_device(eeepc->inputdev); + return err; +} + +static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) +{ + if (eeepc->inputdev) { + sparse_keymap_free(eeepc->inputdev); + input_unregister_device(eeepc->inputdev); + } + + eeepc->inputdev = NULL; +} + +static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *ctrl_param) +{ + struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + u32 tmp; + + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, + 1, EEEPC_WMI_METHODID_DSTS, &input, &output); + + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32)obj->integer.value; + else + tmp = 0; + + if (ctrl_param) + *ctrl_param = tmp; + + kfree(obj); + + return status; + +} + +static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param) +{ + struct bios_args args = { + .dev_id = dev_id, + .ctrl_param = ctrl_param, + }; + struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; + acpi_status status; + + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, + 1, EEEPC_WMI_METHODID_DEVS, &input, NULL); + + return status; +} + +static int read_brightness(struct backlight_device *bd) +{ + static u32 ctrl_param; + acpi_status status; + + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &ctrl_param); + + if (ACPI_FAILURE(status)) + return -1; + else + return ctrl_param & 0xFF; +} + +static int update_bl_status(struct backlight_device *bd) +{ + + static u32 ctrl_param; + acpi_status status; + + ctrl_param = bd->props.brightness; + + status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, ctrl_param); + + if (ACPI_FAILURE(status)) + return -1; + else + return 0; +} + +static const struct backlight_ops eeepc_wmi_bl_ops = { + .get_brightness = read_brightness, + .update_status = update_bl_status, +}; + +static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) +{ + struct backlight_device *bd = eeepc->backlight_device; + int old = bd->props.brightness; + int new; + + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) + new = code - NOTIFY_BRNUP_MIN + 1; + else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) + new = code - NOTIFY_BRNDOWN_MIN; + + bd->props.brightness = new; + backlight_update_status(bd); + backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); + + return old; +} + +static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) +{ + struct backlight_device *bd; + struct backlight_properties props; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = 15; + bd = backlight_device_register(EEEPC_WMI_FILE, + &platform_device->dev, eeepc, + &eeepc_wmi_bl_ops, &props); + if (IS_ERR(bd)) { + pr_err("Could not register backlight device\n"); + return PTR_ERR(bd); + } + + eeepc->backlight_device = bd; + + bd->props.brightness = read_brightness(bd); + bd->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bd); + + return 0; +} + +static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc) +{ + if (eeepc->backlight_device) + backlight_device_unregister(eeepc->backlight_device); + + eeepc->backlight_device = NULL; +} static void eeepc_wmi_notify(u32 value, void *context) { + struct eeepc_wmi *eeepc = context; struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_status status; int code; + int orig_code; status = wmi_get_event_data(value, &response); if (status != AE_OK) { - pr_err("EEEPC WMI: bad event status 0x%x\n", status); + pr_err("bad event status 0x%x\n", status); return; } @@ -77,81 +271,142 @@ static void eeepc_wmi_notify(u32 value, void *context) if (obj && obj->type == ACPI_TYPE_INTEGER) { code = obj->integer.value; + orig_code = code; if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) code = NOTIFY_BRNUP_MIN; - else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) + else if (code >= NOTIFY_BRNDOWN_MIN && + code <= NOTIFY_BRNDOWN_MAX) code = NOTIFY_BRNDOWN_MIN; - if (!sparse_keymap_report_event(eeepc_wmi_input_dev, + if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { + if (!acpi_video_backlight_support()) + eeepc_wmi_backlight_notify(eeepc, orig_code); + } + + if (!sparse_keymap_report_event(eeepc->inputdev, code, 1, true)) - pr_info("EEEPC WMI: Unknown key %x pressed\n", code); + pr_info("Unknown key %x pressed\n", code); } kfree(obj); } -static int eeepc_wmi_input_setup(void) +static int __devinit eeepc_wmi_platform_probe(struct platform_device *device) { + struct eeepc_wmi *eeepc; int err; + acpi_status status; - eeepc_wmi_input_dev = input_allocate_device(); - if (!eeepc_wmi_input_dev) - return -ENOMEM; - - eeepc_wmi_input_dev->name = "Eee PC WMI hotkeys"; - eeepc_wmi_input_dev->phys = "wmi/input0"; - eeepc_wmi_input_dev->id.bustype = BUS_HOST; + eeepc = platform_get_drvdata(device); - err = sparse_keymap_setup(eeepc_wmi_input_dev, eeepc_wmi_keymap, NULL); + err = eeepc_wmi_input_init(eeepc); if (err) - goto err_free_dev; + goto error_input; - err = input_register_device(eeepc_wmi_input_dev); - if (err) - goto err_free_keymap; + if (!acpi_video_backlight_support()) { + err = eeepc_wmi_backlight_init(eeepc); + if (err) + goto error_backlight; + } else + pr_info("Backlight controlled by ACPI video driver\n"); + + status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, + eeepc_wmi_notify, eeepc); + if (ACPI_FAILURE(status)) { + pr_err("Unable to register notify handler - %d\n", + status); + err = -ENODEV; + goto error_wmi; + } return 0; -err_free_keymap: - sparse_keymap_free(eeepc_wmi_input_dev); -err_free_dev: - input_free_device(eeepc_wmi_input_dev); +error_wmi: + eeepc_wmi_backlight_exit(eeepc); +error_backlight: + eeepc_wmi_input_exit(eeepc); +error_input: return err; } +static int __devexit eeepc_wmi_platform_remove(struct platform_device *device) +{ + struct eeepc_wmi *eeepc; + + eeepc = platform_get_drvdata(device); + wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); + eeepc_wmi_backlight_exit(eeepc); + eeepc_wmi_input_exit(eeepc); + + return 0; +} + +static struct platform_driver platform_driver = { + .driver = { + .name = EEEPC_WMI_FILE, + .owner = THIS_MODULE, + }, + .probe = eeepc_wmi_platform_probe, + .remove = __devexit_p(eeepc_wmi_platform_remove), +}; + static int __init eeepc_wmi_init(void) { + struct eeepc_wmi *eeepc; int err; - acpi_status status; - if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID)) { - pr_warning("EEEPC WMI: No known WMI GUID found\n"); + if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || + !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { + pr_warning("No known WMI GUID found\n"); return -ENODEV; } - err = eeepc_wmi_input_setup(); - if (err) - return err; + eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); + if (!eeepc) + return -ENOMEM; - status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, - eeepc_wmi_notify, NULL); - if (ACPI_FAILURE(status)) { - sparse_keymap_free(eeepc_wmi_input_dev); - input_unregister_device(eeepc_wmi_input_dev); - pr_err("EEEPC WMI: Unable to register notify handler - %d\n", - status); - return -ENODEV; + platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); + if (!platform_device) { + pr_warning("Unable to allocate platform device\n"); + err = -ENOMEM; + goto fail_platform; + } + + err = platform_device_add(platform_device); + if (err) { + pr_warning("Unable to add platform device\n"); + goto put_dev; + } + + platform_set_drvdata(platform_device, eeepc); + + err = platform_driver_register(&platform_driver); + if (err) { + pr_warning("Unable to register platform driver\n"); + goto del_dev; } return 0; + +del_dev: + platform_device_del(platform_device); +put_dev: + platform_device_put(platform_device); +fail_platform: + kfree(eeepc); + + return err; } static void __exit eeepc_wmi_exit(void) { - wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); - sparse_keymap_free(eeepc_wmi_input_dev); - input_unregister_device(eeepc_wmi_input_dev); + struct eeepc_wmi *eeepc; + + eeepc = platform_get_drvdata(platform_device); + platform_driver_unregister(&platform_driver); + platform_device_unregister(platform_device); + kfree(eeepc); } module_init(eeepc_wmi_init); diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index a681f5e8f78..ad036dd8da1 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -618,9 +618,12 @@ static int __devexit mc13783_regulator_remove(struct platform_device *pdev) dev_get_platdata(&pdev->dev); int i; + platform_set_drvdata(pdev, NULL); + for (i = 0; i < pdata->num_regulators; i++) regulator_unregister(priv->regulators[i]); + kfree(priv); return 0; } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index bbea90baf98..acf222f91f5 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1899,7 +1899,8 @@ restart: /* Process requests that may be recovered */ if (cqr->status == DASD_CQR_NEED_ERP) { erp_fn = base->discipline->erp_action(cqr); - erp_fn(cqr); + if (IS_ERR(erp_fn(cqr))) + continue; goto restart; } diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 6927e751ce3..6632649dd6a 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2309,7 +2309,7 @@ static struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr) cqr->retries); dasd_block_set_timer(device->block, (HZ << 3)); } - return cqr; + return erp; } ccw = cqr->cpaddr; @@ -2372,6 +2372,9 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr) /* add erp and initialize with default TIC */ erp = dasd_3990_erp_add_erp(cqr); + if (IS_ERR(erp)) + return erp; + /* inspect sense, determine specific ERP if possible */ if (erp != cqr) { @@ -2711,6 +2714,8 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) if (erp == NULL) { /* no matching erp found - set up erp */ erp = dasd_3990_erp_additional_erp(cqr); + if (IS_ERR(erp)) + return erp; } else { /* matching erp found - set all leading erp's to DONE */ erp = dasd_3990_erp_handle_match_erp(cqr, erp); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 18daf16aa35..7217966f7d3 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -638,11 +638,7 @@ static int __init zcore_reipl_init(void) rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); else rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE); - if (rc) { - free_page((unsigned long) ipl_block); - return rc; - } - if (csum_partial(ipl_block, ipl_block->hdr.len, 0) != + if (rc || csum_partial(ipl_block, ipl_block->hdr.len, 0) != ipib_info.checksum) { TRACE("Checksum does not match\n"); free_page((unsigned long) ipl_block); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 4038f5b4f14..ce7cb87479f 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -29,6 +29,7 @@ #include "chsc.h" static void *sei_page; +static DEFINE_SPINLOCK(sda_lock); /** * chsc_error_from_response() - convert a chsc response to an error @@ -832,11 +833,10 @@ void __init chsc_free_sei_area(void) kfree(sei_page); } -int __init -chsc_enable_facility(int operation_code) +int chsc_enable_facility(int operation_code) { int ret; - struct { + static struct { struct chsc_header request; u8 reserved1:4; u8 format:4; @@ -849,33 +849,32 @@ chsc_enable_facility(int operation_code) u32 reserved5:4; u32 format2:4; u32 reserved6:24; - } __attribute__ ((packed)) *sda_area; + } __attribute__ ((packed, aligned(4096))) sda_area; - sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA); - if (!sda_area) - return -ENOMEM; - sda_area->request.length = 0x0400; - sda_area->request.code = 0x0031; - sda_area->operation_code = operation_code; + spin_lock(&sda_lock); + memset(&sda_area, 0, sizeof(sda_area)); + sda_area.request.length = 0x0400; + sda_area.request.code = 0x0031; + sda_area.operation_code = operation_code; - ret = chsc(sda_area); + ret = chsc(&sda_area); if (ret > 0) { ret = (ret == 3) ? -ENODEV : -EBUSY; goto out; } - switch (sda_area->response.code) { + switch (sda_area.response.code) { case 0x0101: ret = -EOPNOTSUPP; break; default: - ret = chsc_error_from_response(sda_area->response.code); + ret = chsc_error_from_response(sda_area.response.code); } if (ret != 0) CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n", - operation_code, sda_area->response.code); + operation_code, sda_area.response.code); out: - free_page((unsigned long)sda_area); + spin_unlock(&sda_lock); return ret; } diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 404f630c27c..3b6f4adc509 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -124,7 +124,7 @@ static int chsc_subchannel_prepare(struct subchannel *sch) * since we don't have a way to clear the subchannel and * cannot disable it with a request running. */ - cc = stsch(sch->schid, &schib); + cc = stsch_err(sch->schid, &schib); if (!cc && scsw_stctl(&schib.scsw)) return -EAGAIN; return 0; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index f736cdcf08a..5feea1a371e 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -361,7 +361,7 @@ int cio_commit_config(struct subchannel *sch) struct schib schib; int ccode, retry, ret = 0; - if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) + if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; for (retry = 0; retry < 5; retry++) { @@ -372,7 +372,7 @@ int cio_commit_config(struct subchannel *sch) return ccode; switch (ccode) { case 0: /* successful */ - if (stsch(sch->schid, &schib) || + if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; if (cio_check_config(sch, &schib)) { @@ -404,7 +404,7 @@ int cio_update_schib(struct subchannel *sch) { struct schib schib; - if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) + if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; memcpy(&sch->schib, &schib, sizeof(schib)); @@ -771,7 +771,7 @@ cio_get_console_sch_no(void) if (console_irq != -1) { /* VM provided us with the irq number of the console. */ schid.sch_no = console_irq; - if (stsch(schid, &console_subchannel.schib) != 0 || + if (stsch_err(schid, &console_subchannel.schib) != 0 || (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !console_subchannel.schib.pmcw.dnv) return -1; @@ -863,10 +863,10 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) cc = 0; for (retry=0;retry<3;retry++) { schib->pmcw.ena = 0; - cc = msch(schid, schib); + cc = msch_err(schid, schib); if (cc) return (cc==3?-ENODEV:-EBUSY); - if (stsch(schid, schib) || !css_sch_is_valid(schib)) + if (stsch_err(schid, schib) || !css_sch_is_valid(schib)) return -ENODEV; if (!schib->pmcw.ena) return 0; @@ -913,7 +913,7 @@ static int stsch_reset(struct subchannel_id schid, struct schib *addr) pgm_check_occured = 0; s390_base_pgm_handler_fn = cio_reset_pgm_check_handler; - rc = stsch(schid, addr); + rc = stsch_err(schid, addr); s390_base_pgm_handler_fn = NULL; /* The program check handler could have changed pgm_check_occured. */ @@ -950,7 +950,7 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) /* No default clear strategy */ break; } - stsch(schid, &schib); + stsch_err(schid, &schib); __disable_subchannel_easy(schid, &schib); } out: @@ -1086,7 +1086,7 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo) schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id; if (!schid.one) return -ENODEV; - if (stsch(schid, &schib)) + if (stsch_err(schid, &schib)) return -ENODEV; if (schib.pmcw.st != SUBCHANNEL_TYPE_IO) return -ENODEV; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 2769da54f2b..511649115bd 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -870,15 +870,10 @@ static int __init css_bus_init(void) /* Try to enable MSS. */ ret = chsc_enable_facility(CHSC_SDA_OC_MSS); - switch (ret) { - case 0: /* Success. */ - max_ssid = __MAX_SSID; - break; - case -ENOMEM: - goto out; - default: + if (ret) max_ssid = 0; - } + else /* Success. */ + max_ssid = __MAX_SSID; ret = slow_subchannel_init(); if (ret) @@ -1048,6 +1043,11 @@ static int __init channel_subsystem_init_sync(void) } subsys_initcall_sync(channel_subsystem_init_sync); +void channel_subsystem_reinit(void) +{ + chsc_enable_facility(CHSC_SDA_OC_MSS); +} + #ifdef CONFIG_PROC_FS static ssize_t cio_settle_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index c56ab94612f..c9b852647f0 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -45,7 +45,7 @@ static void ccw_timeout_log(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); private = to_io_private(sch); orb = &private->orb; - cc = stsch(sch->schid, &schib); + cc = stsch_err(sch->schid, &schib); printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " "device information:\n", get_clock()); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 18564891ea6..b3b1d2f7939 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -2105,7 +2105,8 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) blktrc.inb_usage = req->qdio_req.qdio_inb_usage; blktrc.outb_usage = req->qdio_req.qdio_outb_usage; - if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) { + if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && + !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) { blktrc.flags |= ZFCP_BLK_LAT_VALID; blktrc.channel_lat = lat_in->channel_lat * ticks; blktrc.fabric_lat = lat_in->fabric_lat * ticks; @@ -2157,9 +2158,8 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt); - zfcp_fsf_req_trace(req, scpnt); - skip_fsfstatus: + zfcp_fsf_req_trace(req, scpnt); zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req); scpnt->host_scribble = NULL; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 72617b650a7..e641922f20b 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -169,6 +169,7 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for" "mgmt_invalidate_icds \n"); + spin_unlock(&ctrl->mbox_lock); return -1; } nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index 6cf9dc37d78..6b624e767d3 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -362,6 +362,7 @@ struct bnx2i_hba { u32 num_ccell; int ofld_conns_active; + wait_queue_head_t eh_wait; int max_active_conns; struct iscsi_cid_queue cid_que; @@ -381,6 +382,7 @@ struct bnx2i_hba { spinlock_t lock; /* protects hba structure access */ struct mutex net_dev_lock;/* sync net device access */ + int hba_shutdown_tmo; /* * PCI related info. */ diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index 6d8172e781c..5d9296c599f 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -177,11 +177,22 @@ void bnx2i_stop(void *handle) struct bnx2i_hba *hba = handle; /* check if cleanup happened in GOING_DOWN context */ - clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) iscsi_host_for_each_session(hba->shost, bnx2i_drop_session); + + /* Wait for all endpoints to be torn down, Chip will be reset once + * control returns to network driver. So it is required to cleanup and + * release all connection resources before returning from this routine. + */ + wait_event_interruptible_timeout(hba->eh_wait, + (hba->ofld_conns_active == 0), + hba->hba_shutdown_tmo); + /* This flag should be cleared last so that ep_disconnect() gracefully + * cleans up connection context + */ + clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); } /** diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index f2e9b18fe76..fa68ab34b99 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -820,6 +820,11 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic) spin_lock_init(&hba->lock); mutex_init(&hba->net_dev_lock); + init_waitqueue_head(&hba->eh_wait); + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) + hba->hba_shutdown_tmo = 240 * HZ; + else /* 5706/5708/5709 */ + hba->hba_shutdown_tmo = 30 * HZ; if (iscsi_host_add(shost, &hba->pcidev->dev)) goto free_dump_mem; @@ -1658,8 +1663,8 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, */ hba = bnx2i_check_route(dst_addr); - if (!hba) { - rc = -ENOMEM; + if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) { + rc = -EINVAL; goto check_busy; } @@ -1804,7 +1809,7 @@ static int bnx2i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) (bnx2i_ep->state == EP_STATE_CONNECT_COMPL)), msecs_to_jiffies(timeout_ms)); - if (!rc || (bnx2i_ep->state == EP_STATE_OFLD_FAILED)) + if (bnx2i_ep->state == EP_STATE_OFLD_FAILED) rc = -1; if (rc > 0) @@ -1957,6 +1962,8 @@ return_bnx2i_ep: if (!hba->ofld_conns_active) bnx2i_unreg_dev_all(); + + wake_up_interruptible(&hba->eh_wait); } diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 496764349c4..0435d044c9d 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -188,7 +188,8 @@ MODULE_DEVICE_TABLE(pci,dptids); static int adpt_detect(struct scsi_host_template* sht) { struct pci_dev *pDev = NULL; - adpt_hba* pHba; + adpt_hba *pHba; + adpt_hba *next; PINFO("Detecting Adaptec I2O RAID controllers...\n"); @@ -206,7 +207,8 @@ static int adpt_detect(struct scsi_host_template* sht) } /* In INIT state, Activate IOPs */ - for (pHba = hba_chain; pHba; pHba = pHba->next) { + for (pHba = hba_chain; pHba; pHba = next) { + next = pHba->next; // Activate does get status , init outbound, and get hrt if (adpt_i2o_activate_hba(pHba) < 0) { adpt_i2o_delete_hba(pHba); @@ -243,7 +245,8 @@ rebuild_sys_tab: PDEBUG("HBA's in OPERATIONAL state\n"); printk("dpti: If you have a lot of devices this could take a few minutes.\n"); - for (pHba = hba_chain; pHba; pHba = pHba->next) { + for (pHba = hba_chain; pHba; pHba = next) { + next = pHba->next; printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name); if (adpt_i2o_lct_get(pHba) < 0){ adpt_i2o_delete_hba(pHba); @@ -263,7 +266,8 @@ rebuild_sys_tab: adpt_sysfs_class = NULL; } - for (pHba = hba_chain; pHba; pHba = pHba->next) { + for (pHba = hba_chain; pHba; pHba = next) { + next = pHba->next; if (adpt_scsi_host_alloc(pHba, sht) < 0){ adpt_i2o_delete_hba(pHba); continue; @@ -1229,11 +1233,10 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba) } } pci_dev_put(pHba->pDev); - kfree(pHba); - if (adpt_sysfs_class) device_destroy(adpt_sysfs_class, MKDEV(DPTI_I2O_MAJOR, pHba->unit)); + kfree(pHba); if(hba_count <= 0){ unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index ff5ec5ac1fb..88bad0e81bd 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -323,16 +323,6 @@ static void set_srp_direction(struct scsi_cmnd *cmd, srp_cmd->buf_fmt = fmt; } -static void unmap_sg_list(int num_entries, - struct device *dev, - struct srp_direct_buf *md) -{ - int i; - - for (i = 0; i < num_entries; ++i) - dma_unmap_single(dev, md[i].va, md[i].len, DMA_BIDIRECTIONAL); -} - /** * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format * @cmd: srp_cmd whose additional_data member will be unmapped @@ -350,24 +340,9 @@ static void unmap_cmd_data(struct srp_cmd *cmd, if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC) return; - else if (out_fmt == SRP_DATA_DESC_DIRECT || - in_fmt == SRP_DATA_DESC_DIRECT) { - struct srp_direct_buf *data = - (struct srp_direct_buf *) cmd->add_data; - dma_unmap_single(dev, data->va, data->len, DMA_BIDIRECTIONAL); - } else { - struct srp_indirect_buf *indirect = - (struct srp_indirect_buf *) cmd->add_data; - int num_mapped = indirect->table_desc.len / - sizeof(struct srp_direct_buf); - if (num_mapped <= MAX_INDIRECT_BUFS) { - unmap_sg_list(num_mapped, dev, &indirect->desc_list[0]); - return; - } - - unmap_sg_list(num_mapped, dev, evt_struct->ext_list); - } + if (evt_struct->cmnd) + scsi_dma_unmap(evt_struct->cmnd); } static int map_sg_list(struct scsi_cmnd *cmd, int nseg, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 0ee725ced51..02143af7c1a 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -599,7 +599,7 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock); - if (sock->sk->sk_sleep && waitqueue_active(sock->sk->sk_sleep)) { + if (sock->sk->sk_sleep) { sock->sk->sk_err = EIO; wake_up_interruptible(sock->sk->sk_sleep); } diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index ec3723831e8..d62b3e46792 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -433,7 +433,7 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, dd_data = cmdiocbq->context1; /* normal completion and timeout crossed paths, already done */ if (!dd_data) { - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); return; } @@ -1196,7 +1196,7 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, dd_data = cmdiocbq->context1; /* normal completion and timeout crossed paths, already done */ if (!dd_data) { - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_unlock_irqrestore(&phba->ct_ev_lock, flags); return; } diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 359e9a71a02..1c7ef55966f 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -2393,6 +2393,7 @@ qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) return 0; done: + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (bsg_job->request->msgcode == FC_BSG_HST_CT) kfree(sp->fcport); kfree(sp->ctx); diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 09d6d4b76f3..caeb7d10ae0 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -467,7 +467,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, if (conn_err_detail) *conn_err_detail = mbox_sts[5]; if (tcp_source_port_num) - *tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16; + *tcp_source_port_num = (uint16_t) (mbox_sts[6] >> 16); if (connection_id) *connection_id = (uint16_t) mbox_sts[6] & 0x00FF; status = QLA_SUCCESS; diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index d0b7d2ff9ac..333580bf37c 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1587,7 +1587,7 @@ static int wd7000_host_reset(struct scsi_cmnd *SCpnt) { Adapter *host = (Adapter *) SCpnt->device->host->hostdata; - spin_unlock_irq(SCpnt->device->host->host_lock); + spin_lock_irq(SCpnt->device->host->host_lock); if (wd7000_adapter_reset(host) < 0) { spin_unlock_irq(SCpnt->device->host->host_lock); diff --git a/drivers/serial/mcf.c b/drivers/serial/mcf.c index 7bb5fee639e..b5aaef965f2 100644 --- a/drivers/serial/mcf.c +++ b/drivers/serial/mcf.c @@ -263,6 +263,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, } spin_lock_irqsave(&port->lock, flags); + uart_update_timeout(port, termios->c_cflag, baud); writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR); @@ -379,6 +380,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data) static void mcf_config_port(struct uart_port *port, int flags) { port->type = PORT_MCF; + port->fifosize = MCFUART_TXFIFOSIZE; /* Clear mask, so no surprise interrupts. */ writeb(0, port->membase + MCFUART_UIMR); @@ -424,7 +426,7 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser) /* * Define the basic serial functions we support. */ -static struct uart_ops mcf_uart_ops = { +static const struct uart_ops mcf_uart_ops = { .tx_empty = mcf_tx_empty, .get_mctrl = mcf_get_mctrl, .set_mctrl = mcf_set_mctrl, @@ -443,7 +445,7 @@ static struct uart_ops mcf_uart_ops = { .verify_port = mcf_verify_port, }; -static struct mcf_uart mcf_ports[3]; +static struct mcf_uart mcf_ports[4]; #define MCF_MAXPORTS ARRAY_SIZE(mcf_ports) diff --git a/drivers/staging/dt3155/dt3155_drv.c b/drivers/staging/dt3155/dt3155_drv.c index a67c622869d..e2c44ec6fc4 100644 --- a/drivers/staging/dt3155/dt3155_drv.c +++ b/drivers/staging/dt3155/dt3155_drv.c @@ -57,19 +57,8 @@ MA 02111-1307 USA extern void printques(int); -#ifdef MODULE #include <linux/module.h> #include <linux/interrupt.h> - - -MODULE_LICENSE("GPL"); - -#endif - -#ifndef CONFIG_PCI -#error "DT3155 : Kernel PCI support not enabled (DT3155 drive requires PCI)" -#endif - #include <linux/pci.h> #include <linux/types.h> #include <linux/poll.h> @@ -84,6 +73,9 @@ MODULE_LICENSE("GPL"); #include "dt3155_io.h" #include "allocator.h" + +MODULE_LICENSE("GPL"); + /* Error variable. Zero means no error. */ int dt3155_errno = 0; diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 6a3b5cae3a6..2f3dc4cdf79 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -301,7 +301,7 @@ static int usb_probe_interface(struct device *dev) intf->condition = USB_INTERFACE_BINDING; - /* Bound interfaces are initially active. They are + /* Probed interfaces are initially active. They are * runtime-PM-enabled only if the driver has autosuspend support. * They are sensitive to their children's power states. */ @@ -437,11 +437,11 @@ int usb_driver_claim_interface(struct usb_driver *driver, iface->condition = USB_INTERFACE_BOUND; - /* Bound interfaces are initially active. They are + /* Claimed interfaces are initially inactive (suspended). They are * runtime-PM-enabled only if the driver has autosuspend support. * They are sensitive to their children's power states. */ - pm_runtime_set_active(dev); + pm_runtime_set_suspended(dev); pm_suspend_ignore_children(dev, false); if (driver->supports_autosuspend) pm_runtime_enable(dev); @@ -1170,7 +1170,7 @@ done: static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) { int status = 0; - int i = 0; + int i = 0, n = 0; struct usb_interface *intf; if (udev->state == USB_STATE_NOTATTACHED || @@ -1179,7 +1179,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* Suspend all the interfaces and then udev itself */ if (udev->actconfig) { - for (; i < udev->actconfig->desc.bNumInterfaces; i++) { + n = udev->actconfig->desc.bNumInterfaces; + for (i = n - 1; i >= 0; --i) { intf = udev->actconfig->interface[i]; status = usb_suspend_interface(udev, intf, msg); if (status != 0) @@ -1192,7 +1193,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); - while (--i >= 0) { + while (++i < n) { intf = udev->actconfig->interface[i]; usb_resume_interface(udev, intf, msg, 0); } @@ -1263,13 +1264,47 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) return status; } +static void choose_wakeup(struct usb_device *udev, pm_message_t msg) +{ + int w, i; + struct usb_interface *intf; + + /* Remote wakeup is needed only when we actually go to sleep. + * For things like FREEZE and QUIESCE, if the device is already + * autosuspended then its current wakeup setting is okay. + */ + if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) { + if (udev->state != USB_STATE_SUSPENDED) + udev->do_remote_wakeup = 0; + return; + } + + /* If remote wakeup is permitted, see whether any interface drivers + * actually want it. + */ + w = 0; + if (device_may_wakeup(&udev->dev) && udev->actconfig) { + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + w |= intf->needs_remote_wakeup; + } + } + + /* If the device is autosuspended with the wrong wakeup setting, + * autoresume now so the setting can be changed. + */ + if (udev->state == USB_STATE_SUSPENDED && w != udev->do_remote_wakeup) + pm_runtime_resume(&udev->dev); + udev->do_remote_wakeup = w; +} + /* The device lock is held by the PM core */ int usb_suspend(struct device *dev, pm_message_t msg) { struct usb_device *udev = to_usb_device(dev); do_unbind_rebind(udev, DO_UNBIND); - udev->do_remote_wakeup = device_may_wakeup(&udev->dev); + choose_wakeup(udev, msg); return usb_suspend_both(udev, msg); } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 207e7a85aeb..13ead00aecd 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -543,6 +543,7 @@ static int ehci_init(struct usb_hcd *hcd) */ ehci->periodic_size = DEFAULT_I_TDPS; INIT_LIST_HEAD(&ehci->cached_itd_list); + INIT_LIST_HEAD(&ehci->cached_sitd_list); if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0) return retval; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 19372673bf0..c7178bcde67 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -801,7 +801,7 @@ static int ehci_hub_control ( * this bit; seems too long to spin routinely... */ retval = handshake(ehci, status_reg, - PORT_RESET, 0, 750); + PORT_RESET, 0, 1000); if (retval != 0) { ehci_err (ehci, "port %d reset error %d\n", wIndex + 1, retval); diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index aeda96e0af6..1f3f01eacaf 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -136,7 +136,7 @@ static inline void qh_put (struct ehci_qh *qh) static void ehci_mem_cleanup (struct ehci_hcd *ehci) { - free_cached_itd_list(ehci); + free_cached_lists(ehci); if (ehci->async) qh_put (ehci->async); ehci->async = NULL; diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index a67a0030dd5..40a85833503 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -629,11 +629,13 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) } snprintf(supply, sizeof(supply), "hsusb%d", i); omap->regulator[i] = regulator_get(omap->dev, supply); - if (IS_ERR(omap->regulator[i])) + if (IS_ERR(omap->regulator[i])) { + omap->regulator[i] = NULL; dev_dbg(&pdev->dev, "failed to get ehci port%d regulator\n", i); - else + } else { regulator_enable(omap->regulator[i]); + } } ret = omap_start_ehc(omap, hcd); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a0aaaaff256..805ec633a65 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -510,7 +510,7 @@ static int disable_periodic (struct ehci_hcd *ehci) ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... */ - free_cached_itd_list(ehci); + free_cached_lists(ehci); ehci->next_uframe = -1; return 0; @@ -2139,13 +2139,27 @@ sitd_complete ( (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); } iso_stream_put (ehci, stream); - /* OK to recycle this SITD now that its completion callback ran. */ + done: sitd->urb = NULL; - sitd->stream = NULL; - list_move(&sitd->sitd_list, &stream->free_list); - iso_stream_put(ehci, stream); - + if (ehci->clock_frame != sitd->frame) { + /* OK to recycle this SITD now. */ + sitd->stream = NULL; + list_move(&sitd->sitd_list, &stream->free_list); + iso_stream_put(ehci, stream); + } else { + /* HW might remember this SITD, so we can't recycle it yet. + * Move it to a safe place until a new frame starts. + */ + list_move(&sitd->sitd_list, &ehci->cached_sitd_list); + if (stream->refcount == 2) { + /* If iso_stream_put() were called here, stream + * would be freed. Instead, just prevent reuse. + */ + stream->ep->hcpriv = NULL; + stream->ep = NULL; + } + } return retval; } @@ -2211,9 +2225,10 @@ done: /*-------------------------------------------------------------------------*/ -static void free_cached_itd_list(struct ehci_hcd *ehci) +static void free_cached_lists(struct ehci_hcd *ehci) { struct ehci_itd *itd, *n; + struct ehci_sitd *sitd, *sn; list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) { struct ehci_iso_stream *stream = itd->stream; @@ -2221,6 +2236,13 @@ static void free_cached_itd_list(struct ehci_hcd *ehci) list_move(&itd->itd_list, &stream->free_list); iso_stream_put(ehci, stream); } + + list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) { + struct ehci_iso_stream *stream = sitd->stream; + sitd->stream = NULL; + list_move(&sitd->sitd_list, &stream->free_list); + iso_stream_put(ehci, stream); + } } /*-------------------------------------------------------------------------*/ @@ -2247,7 +2269,7 @@ scan_periodic (struct ehci_hcd *ehci) clock_frame = -1; } if (ehci->clock_frame != clock_frame) { - free_cached_itd_list(ehci); + free_cached_lists(ehci); ehci->clock_frame = clock_frame; } clock %= mod; @@ -2414,7 +2436,7 @@ restart: clock = now; clock_frame = clock >> 3; if (ehci->clock_frame != clock_frame) { - free_cached_itd_list(ehci); + free_cached_lists(ehci); ehci->clock_frame = clock_frame; } } else { diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index b1dce96dd62..556c0b48f3a 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -87,8 +87,9 @@ struct ehci_hcd { /* one per controller */ int next_uframe; /* scan periodic, start here */ unsigned periodic_sched; /* periodic activity count */ - /* list of itds completed while clock_frame was still active */ + /* list of itds & sitds completed while clock_frame was still active */ struct list_head cached_itd_list; + struct list_head cached_sitd_list; unsigned clock_frame; /* per root hub port */ @@ -195,7 +196,7 @@ timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action) clear_bit (action, &ehci->actions); } -static void free_cached_itd_list(struct ehci_hcd *ehci); +static void free_cached_lists(struct ehci_hcd *ehci); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 4aa08d36d07..d22fb4d577b 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -23,7 +23,7 @@ #error "This file is DA8xx bus glue. Define CONFIG_ARCH_DAVINCI_DA8XX." #endif -#define CFGCHIP2 DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG) +#define CFGCHIP2 DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG) static struct clk *usb11_clk; static struct clk *usb20_clk; diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index a9555cb901a..de8ef945b53 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -49,6 +49,7 @@ struct usb_sevsegdev { u16 textlength; u8 shadow_power; /* for PM */ + u8 has_interface_pm; }; /* sysfs_streq can't replace this completely @@ -68,12 +69,16 @@ static void update_display_powered(struct usb_sevsegdev *mydev) { int rc; - if (!mydev->shadow_power && mydev->powered) { + if (mydev->powered && !mydev->has_interface_pm) { rc = usb_autopm_get_interface(mydev->intf); if (rc < 0) return; + mydev->has_interface_pm = 1; } + if (mydev->shadow_power != 1) + return; + rc = usb_control_msg(mydev->udev, usb_sndctrlpipe(mydev->udev, 0), 0x12, @@ -86,8 +91,10 @@ static void update_display_powered(struct usb_sevsegdev *mydev) if (rc < 0) dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); - if (mydev->shadow_power && !mydev->powered) + if (!mydev->powered && mydev->has_interface_pm) { usb_autopm_put_interface(mydev->intf); + mydev->has_interface_pm = 0; + } } static void update_display_mode(struct usb_sevsegdev *mydev) @@ -351,6 +358,10 @@ static int sevseg_probe(struct usb_interface *interface, mydev->intf = interface; usb_set_intfdata(interface, mydev); + /* PM */ + mydev->shadow_power = 1; /* currently active */ + mydev->has_interface_pm = 0; /* have not issued autopm_get */ + /*set defaults */ mydev->textmode = 0x02; /* ascii mode */ mydev->mode_msb = 0x06; /* 6 characters */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 73d5f346d3e..c97a0bb5b6d 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -97,6 +97,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, + { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index d640dc95156..a352d5f3a59 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -134,3 +134,7 @@ /* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ #define SANWA_VENDOR_ID 0x11ad #define SANWA_PRODUCT_ID 0x0001 + +/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ +#define ADLINK_VENDOR_ID 0x0b63 +#define ADLINK_ND6530_PRODUCT_ID 0x6530 diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 0b936206171..7e3bea23600 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -42,6 +42,14 @@ #define CMOTECH_PRODUCT_CDU550 0x5553 #define CMOTECH_PRODUCT_CDX650 0x6512 +/* LG devices */ +#define LG_VENDOR_ID 0x1004 +#define LG_PRODUCT_VX4400_6000 0x6000 /* VX4400/VX6000/Rumor */ + +/* Sanyo devices */ +#define SANYO_VENDOR_ID 0x0474 +#define SANYO_PRODUCT_KATANA_LX 0x0754 /* SCP-3800 (Katana LX) */ + static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) }, @@ -51,6 +59,8 @@ static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_ALLTEL, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU550, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDX650, 0xff, 0xff, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, + { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 9202f94505e..ef0bdb08d78 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -230,6 +230,7 @@ static const struct sierra_iface_info direct_ip_interface_blacklist = { static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */ { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */ + { USB_DEVICE(0x03F0, 0x211D) }, /* HP ev2210 a.k.a MC5725 */ { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 0afe5c71c17..880e990abb0 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -172,7 +172,7 @@ static unsigned int product_5052_count; /* the array dimension is the number of default entries plus */ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ /* null entry */ -static struct usb_device_id ti_id_table_3410[10+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[13+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -180,6 +180,9 @@ static struct usb_device_id ti_id_table_3410[10+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, @@ -192,7 +195,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, }; -static struct usb_device_id ti_id_table_combined[14+2*TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_combined[17+2*TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -200,6 +203,9 @@ static struct usb_device_id ti_id_table_combined[14+2*TI_EXTRA_VID_PID_COUNT+1] { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, @@ -287,6 +293,8 @@ MODULE_FIRMWARE("ti_5052.fw"); MODULE_FIRMWARE("mts_cdma.fw"); MODULE_FIRMWARE("mts_gsm.fw"); MODULE_FIRMWARE("mts_edge.fw"); +MODULE_FIRMWARE("mts_mt9234mu.fw"); +MODULE_FIRMWARE("mts_mt9234zba.fw"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes"); @@ -1687,6 +1695,7 @@ static int ti_download_firmware(struct ti_device *tdev) const struct firmware *fw_p; char buf[32]; + dbg("%s\n", __func__); /* try ID specific firmware first, then try generic firmware */ sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -1703,7 +1712,15 @@ static int ti_download_firmware(struct ti_device *tdev) case MTS_EDGE_PRODUCT_ID: strcpy(buf, "mts_edge.fw"); break; - } + case MTS_MT9234MU_PRODUCT_ID: + strcpy(buf, "mts_mt9234mu.fw"); + break; + case MTS_MT9234ZBA_PRODUCT_ID: + strcpy(buf, "mts_mt9234zba.fw"); + break; + case MTS_MT9234ZBAOLD_PRODUCT_ID: + strcpy(buf, "mts_mt9234zba.fw"); + break; } } if (buf[0] == '\0') { if (tdev->td_is_3410) @@ -1718,7 +1735,7 @@ static int ti_download_firmware(struct ti_device *tdev) return -ENOENT; } if (fw_p->size > TI_FIRMWARE_BUF_SIZE) { - dev_err(&dev->dev, "%s - firmware too large\n", __func__); + dev_err(&dev->dev, "%s - firmware too large %d \n", __func__, fw_p->size); return -ENOENT; } @@ -1730,6 +1747,7 @@ static int ti_download_firmware(struct ti_device *tdev) status = ti_do_download(dev, pipe, buffer, fw_p->size); kfree(buffer); } else { + dbg("%s ENOMEM\n", __func__); status = -ENOMEM; } release_firmware(fw_p); diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index f323c602585..2aac1953993 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -45,6 +45,9 @@ #define MTS_CDMA_PRODUCT_ID 0xF110 #define MTS_GSM_PRODUCT_ID 0xF111 #define MTS_EDGE_PRODUCT_ID 0xF112 +#define MTS_MT9234MU_PRODUCT_ID 0xF114 +#define MTS_MT9234ZBA_PRODUCT_ID 0xF115 +#define MTS_MT9234ZBAOLD_PRODUCT_ID 0x0319 /* Commands */ #define TI_GET_VERSION 0x01 diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index 46e79d34949..7ec24e46b34 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -438,7 +438,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc) old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr); keep_alives = 0; for (cnt = 0; - keep_alives <= WUIE_ELT_MAX && cnt < wusbhc->ports_max; + keep_alives < WUIE_ELT_MAX && cnt < wusbhc->ports_max; cnt++) { unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout); diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 581d2dbf675..ecf405562f5 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -49,6 +49,7 @@ enum { M_MBP_2, /* MacBook Pro 2nd gen */ M_MBP_SR, /* MacBook Pro (Santa Rosa) */ M_MBP_4, /* MacBook Pro, 4th gen */ + M_MBP_5_1, /* MacBook Pro, 5,1th gen */ M_UNKNOWN /* placeholder */ }; @@ -70,6 +71,7 @@ static struct efifb_dmi_info { [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, + [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 }, [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } }; @@ -106,6 +108,7 @@ static struct dmi_system_id __initdata dmi_system_table[] = { EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro5,1", M_MBP_5_1), {}, }; diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 3aed38886f9..bfec7c29486 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -103,7 +103,8 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num) num = min(num, ARRAY_SIZE(vb->pfns)); for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) { - struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY); + struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY | + __GFP_NOMEMALLOC | __GFP_NOWARN); if (!page) { if (printk_ratelimit()) dev_printk(KERN_INFO, &vb->vdev->dev, diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index ef36fca2eed..3a7e9ff8a74 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/sched.h> #include <asm/irq.h> #include <mach/hardware.h> diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 1ed3d554e37..17726a05a0a 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -115,9 +115,8 @@ static struct w1_therm_family_converter w1_therm_families[] = { static inline int w1_DS18B20_convert_temp(u8 rom[9]) { - int t = ((s16)rom[1] << 8) | rom[0]; - t = t*1000/16; - return t; + s16 t = le16_to_cpup((__le16 *)rom); + return t*1000/16; } static inline int w1_DS18S20_convert_temp(u8 rom[9]) diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 5e813a816ce..b3feddc4f7d 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -138,9 +138,9 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) { struct afs_super_info *super; struct vfsmount *mnt; - struct page *page = NULL; + struct page *page; size_t size; - char *buf, *devname = NULL, *options = NULL; + char *buf, *devname, *options; int ret; _enter("{%s}", mntpt->d_name.name); @@ -150,22 +150,22 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) ret = -EINVAL; size = mntpt->d_inode->i_size; if (size > PAGE_SIZE - 1) - goto error; + goto error_no_devname; ret = -ENOMEM; devname = (char *) get_zeroed_page(GFP_KERNEL); if (!devname) - goto error; + goto error_no_devname; options = (char *) get_zeroed_page(GFP_KERNEL); if (!options) - goto error; + goto error_no_options; /* read the contents of the AFS special symlink */ page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); if (IS_ERR(page)) { ret = PTR_ERR(page); - goto error; + goto error_no_page; } ret = -EIO; @@ -196,12 +196,12 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) return mnt; error: - if (page) - page_cache_release(page); - if (devname) - free_page((unsigned long) devname); - if (options) - free_page((unsigned long) options); + page_cache_release(page); +error_no_page: + free_page((unsigned long) options); +error_no_options: + free_page((unsigned long) devname); +error_no_devname: _leave(" = %d", ret); return ERR_PTR(ret); } diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index e0e769bdca5..49566c1687d 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -355,7 +355,7 @@ calc_reloc(unsigned long r, struct lib_info *p, int curid, int internalp) if (!flat_reloc_valid(r, start_brk - start_data + text_len)) { printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)", - (int) r,(int)(start_brk-start_code),(int)text_len); + (int) r,(int)(start_brk-start_data+text_len),(int)text_len); goto failed; } diff --git a/fs/block_dev.c b/fs/block_dev.c index 2a6d0193f13..6dcee88c2e5 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -406,16 +406,23 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) int blkdev_fsync(struct file *filp, struct dentry *dentry, int datasync) { - struct block_device *bdev = I_BDEV(filp->f_mapping->host); + struct inode *bd_inode = filp->f_mapping->host; + struct block_device *bdev = I_BDEV(bd_inode); int error; - error = sync_blockdev(bdev); - if (error) - return error; - + /* + * There is no need to serialise calls to blkdev_issue_flush with + * i_mutex and doing so causes performance issues with concurrent + * O_SYNC writers to a block device. + */ + mutex_unlock(&bd_inode->i_mutex); + error = blkdev_issue_flush(bdev, NULL); if (error == -EOPNOTSUPP) error = 0; + + mutex_lock(&bd_inode->i_mutex); + return error; } EXPORT_SYMBOL(blkdev_fsync); diff --git a/fs/ioctl.c b/fs/ioctl.c index 6c751106c2e..7faefb4da93 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -228,14 +228,23 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) #ifdef CONFIG_BLOCK -#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits) -#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits); +static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) +{ + return (offset >> inode->i_blkbits); +} + +static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) +{ + return (blk << inode->i_blkbits); +} /** * __generic_block_fiemap - FIEMAP for block based inodes (no locking) - * @inode - the inode to map - * @arg - the pointer to userspace where we copy everything to - * @get_block - the fs's get_block function + * @inode: the inode to map + * @fieinfo: the fiemap info struct that will be passed back to userspace + * @start: where to start mapping in the inode + * @len: how much space to map + * @get_block: the fs's get_block function * * This does FIEMAP for block based inodes. Basically it will just loop * through get_block until we hit the number of extents we want to map, or we @@ -250,58 +259,63 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) */ int __generic_block_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, u64 start, - u64 len, get_block_t *get_block) + struct fiemap_extent_info *fieinfo, loff_t start, + loff_t len, get_block_t *get_block) { - struct buffer_head tmp; - unsigned long long start_blk; - long long length = 0, map_len = 0; + struct buffer_head map_bh; + sector_t start_blk, last_blk; + loff_t isize = i_size_read(inode); u64 logical = 0, phys = 0, size = 0; u32 flags = FIEMAP_EXTENT_MERGED; - int ret = 0, past_eof = 0, whole_file = 0; + bool past_eof = false, whole_file = false; + int ret = 0; - if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC))) + ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); + if (ret) return ret; - start_blk = logical_to_blk(inode, start); - - length = (long long)min_t(u64, len, i_size_read(inode)); - if (length < len) - whole_file = 1; + /* + * Either the i_mutex or other appropriate locking needs to be held + * since we expect isize to not change at all through the duration of + * this call. + */ + if (len >= isize) { + whole_file = true; + len = isize; + } - map_len = length; + start_blk = logical_to_blk(inode, start); + last_blk = logical_to_blk(inode, start + len - 1); do { /* * we set b_size to the total size we want so it will map as * many contiguous blocks as possible at once */ - memset(&tmp, 0, sizeof(struct buffer_head)); - tmp.b_size = map_len; + memset(&map_bh, 0, sizeof(struct buffer_head)); + map_bh.b_size = len; - ret = get_block(inode, start_blk, &tmp, 0); + ret = get_block(inode, start_blk, &map_bh, 0); if (ret) break; /* HOLE */ - if (!buffer_mapped(&tmp)) { - length -= blk_to_logical(inode, 1); + if (!buffer_mapped(&map_bh)) { start_blk++; /* - * we want to handle the case where there is an + * We want to handle the case where there is an * allocated block at the front of the file, and then * nothing but holes up to the end of the file properly, * to make sure that extent at the front gets properly * marked with FIEMAP_EXTENT_LAST */ if (!past_eof && - blk_to_logical(inode, start_blk) >= - blk_to_logical(inode, 0)+i_size_read(inode)) + blk_to_logical(inode, start_blk) >= isize) past_eof = 1; /* - * first hole after going past the EOF, this is our + * First hole after going past the EOF, this is our * last extent */ if (past_eof && size) { @@ -309,15 +323,18 @@ int __generic_block_fiemap(struct inode *inode, ret = fiemap_fill_next_extent(fieinfo, logical, phys, size, flags); - break; + } else if (size) { + ret = fiemap_fill_next_extent(fieinfo, logical, + phys, size, flags); + size = 0; } /* if we have holes up to/past EOF then we're done */ - if (length <= 0 || past_eof) + if (start_blk > last_blk || past_eof || ret) break; } else { /* - * we have gone over the length of what we wanted to + * We have gone over the length of what we wanted to * map, and it wasn't the entire file, so add the extent * we got last time and exit. * @@ -331,7 +348,7 @@ int __generic_block_fiemap(struct inode *inode, * are good to go, just add the extent to the fieinfo * and break */ - if (length <= 0 && !whole_file) { + if (start_blk > last_blk && !whole_file) { ret = fiemap_fill_next_extent(fieinfo, logical, phys, size, flags); @@ -351,11 +368,10 @@ int __generic_block_fiemap(struct inode *inode, } logical = blk_to_logical(inode, start_blk); - phys = blk_to_logical(inode, tmp.b_blocknr); - size = tmp.b_size; + phys = blk_to_logical(inode, map_bh.b_blocknr); + size = map_bh.b_size; flags = FIEMAP_EXTENT_MERGED; - length -= tmp.b_size; start_blk += logical_to_blk(inode, size); /* @@ -363,15 +379,13 @@ int __generic_block_fiemap(struct inode *inode, * soon as we find a hole that the last extent we found * is marked with FIEMAP_EXTENT_LAST */ - if (!past_eof && - logical+size >= - blk_to_logical(inode, 0)+i_size_read(inode)) - past_eof = 1; + if (!past_eof && logical + size >= isize) + past_eof = true; } cond_resched(); } while (1); - /* if ret is 1 then we just hit the end of the extent array */ + /* If ret is 1 then we just hit the end of the extent array */ if (ret == 1) ret = 0; diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 9dd126276c9..ed9ba6fe04f 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -61,7 +61,7 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino) inode->i_op = &page_symlink_inode_operations; inode->i_mapping->a_ops = &jfs_aops; } else { - inode->i_op = &jfs_symlink_inode_operations; + inode->i_op = &jfs_fast_symlink_inode_operations; /* * The inline data should be null-terminated, but * don't let on-disk corruption crash the kernel diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 6c4dfcbf3f5..9e2f6a72166 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -196,7 +196,7 @@ int dbMount(struct inode *ipbmap) bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag); bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref); bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel); - bmp->db_agheigth = le32_to_cpu(dbmp_le->dn_agheigth); + bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight); bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth); bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart); bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size); @@ -288,7 +288,7 @@ int dbSync(struct inode *ipbmap) dbmp_le->dn_maxag = cpu_to_le32(bmp->db_maxag); dbmp_le->dn_agpref = cpu_to_le32(bmp->db_agpref); dbmp_le->dn_aglevel = cpu_to_le32(bmp->db_aglevel); - dbmp_le->dn_agheigth = cpu_to_le32(bmp->db_agheigth); + dbmp_le->dn_agheight = cpu_to_le32(bmp->db_agheight); dbmp_le->dn_agwidth = cpu_to_le32(bmp->db_agwidth); dbmp_le->dn_agstart = cpu_to_le32(bmp->db_agstart); dbmp_le->dn_agl2size = cpu_to_le32(bmp->db_agl2size); @@ -1441,7 +1441,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) * tree index of this allocation group within the control page. */ agperlev = - (1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth; + (1 << (L2LPERCTL - (bmp->db_agheight << 1))) / bmp->db_agwidth; ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1)); /* dmap control page trees fan-out by 4 and a single allocation @@ -1460,7 +1460,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) * the subtree to find the leftmost leaf that describes this * free space. */ - for (k = bmp->db_agheigth; k > 0; k--) { + for (k = bmp->db_agheight; k > 0; k--) { for (n = 0, m = (ti << 2) + 1; n < 4; n++) { if (l2nb <= dcp->stree[m + n]) { ti = m + n; @@ -3607,7 +3607,7 @@ void dbFinalizeBmap(struct inode *ipbmap) } /* - * compute db_aglevel, db_agheigth, db_width, db_agstart: + * compute db_aglevel, db_agheight, db_width, db_agstart: * an ag is covered in aglevel dmapctl summary tree, * at agheight level height (from leaf) with agwidth number of nodes * each, which starts at agstart index node of the smmary tree node @@ -3616,9 +3616,9 @@ void dbFinalizeBmap(struct inode *ipbmap) bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize); l2nl = bmp->db_agl2size - (L2BPERDMAP + bmp->db_aglevel * L2LPERCTL); - bmp->db_agheigth = l2nl >> 1; - bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheigth << 1)); - for (i = 5 - bmp->db_agheigth, bmp->db_agstart = 0, n = 1; i > 0; + bmp->db_agheight = l2nl >> 1; + bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheight << 1)); + for (i = 5 - bmp->db_agheight, bmp->db_agstart = 0, n = 1; i > 0; i--) { bmp->db_agstart += n; n <<= 2; diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h index 1a6eb41569b..6dcb906c55d 100644 --- a/fs/jfs/jfs_dmap.h +++ b/fs/jfs/jfs_dmap.h @@ -210,7 +210,7 @@ struct dbmap_disk { __le32 dn_maxag; /* 4: max active alloc group number */ __le32 dn_agpref; /* 4: preferred alloc group (hint) */ __le32 dn_aglevel; /* 4: dmapctl level holding the AG */ - __le32 dn_agheigth; /* 4: height in dmapctl of the AG */ + __le32 dn_agheight; /* 4: height in dmapctl of the AG */ __le32 dn_agwidth; /* 4: width in dmapctl of the AG */ __le32 dn_agstart; /* 4: start tree index at AG height */ __le32 dn_agl2size; /* 4: l2 num of blks per alloc group */ @@ -229,7 +229,7 @@ struct dbmap { int dn_maxag; /* max active alloc group number */ int dn_agpref; /* preferred alloc group (hint) */ int dn_aglevel; /* dmapctl level holding the AG */ - int dn_agheigth; /* height in dmapctl of the AG */ + int dn_agheight; /* height in dmapctl of the AG */ int dn_agwidth; /* width in dmapctl of the AG */ int dn_agstart; /* start tree index at AG height */ int dn_agl2size; /* l2 num of blks per alloc group */ @@ -255,7 +255,7 @@ struct bmap { #define db_agsize db_bmap.dn_agsize #define db_agl2size db_bmap.dn_agl2size #define db_agwidth db_bmap.dn_agwidth -#define db_agheigth db_bmap.dn_agheigth +#define db_agheight db_bmap.dn_agheight #define db_agstart db_bmap.dn_agstart #define db_numag db_bmap.dn_numag #define db_maxlevel db_bmap.dn_maxlevel diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 79e2c79661d..9e6bda30a6e 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -48,5 +48,6 @@ extern const struct file_operations jfs_dir_operations; extern const struct inode_operations jfs_file_inode_operations; extern const struct file_operations jfs_file_operations; extern const struct inode_operations jfs_symlink_inode_operations; +extern const struct inode_operations jfs_fast_symlink_inode_operations; extern const struct dentry_operations jfs_ci_dentry_operations; #endif /* _H_JFS_INODE */ diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 4a3e9f39c21..a9cf8e8675b 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -956,7 +956,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, */ if (ssize <= IDATASIZE) { - ip->i_op = &jfs_symlink_inode_operations; + ip->i_op = &jfs_fast_symlink_inode_operations; i_fastsymlink = JFS_IP(ip)->i_inline; memcpy(i_fastsymlink, name, ssize); @@ -978,7 +978,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, else { jfs_info("jfs_symlink: allocate extent ip:0x%p", ip); - ip->i_op = &page_symlink_inode_operations; + ip->i_op = &jfs_symlink_inode_operations; ip->i_mapping->a_ops = &jfs_aops; /* diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c index 7f24a0bb08c..1aba0039f1c 100644 --- a/fs/jfs/resize.c +++ b/fs/jfs/resize.c @@ -81,6 +81,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) struct inode *iplist[1]; struct jfs_superblock *j_sb, *j_sb2; uint old_agsize; + int agsizechanged = 0; struct buffer_head *bh, *bh2; /* If the volume hasn't grown, get out now */ @@ -333,6 +334,9 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) */ if ((rc = dbExtendFS(ipbmap, XAddress, nblocks))) goto error_out; + + agsizechanged |= (bmp->db_agsize != old_agsize); + /* * the map now has extended to cover additional nblocks: * dn_mapsize = oldMapsize + nblocks; @@ -432,7 +436,7 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) * will correctly identify the new ag); */ /* if new AG size the same as old AG size, done! */ - if (bmp->db_agsize != old_agsize) { + if (agsizechanged) { if ((rc = diExtendFS(ipimap, ipbmap))) goto error_out; diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index 4af1a05aad0..205b946d8e0 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -29,9 +29,21 @@ static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -const struct inode_operations jfs_symlink_inode_operations = { +const struct inode_operations jfs_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jfs_follow_link, + .setattr = jfs_setattr, + .setxattr = jfs_setxattr, + .getxattr = jfs_getxattr, + .listxattr = jfs_listxattr, + .removexattr = jfs_removexattr, +}; + +const struct inode_operations jfs_symlink_inode_operations = { + .readlink = generic_readlink, + .follow_link = page_follow_link_light, + .put_link = page_put_link, + .setattr = jfs_setattr, .setxattr = jfs_setxattr, .getxattr = jfs_getxattr, .listxattr = jfs_listxattr, diff --git a/fs/logfs/gc.c b/fs/logfs/gc.c index 84e36f52fe9..76c242fbe1b 100644 --- a/fs/logfs/gc.c +++ b/fs/logfs/gc.c @@ -459,6 +459,14 @@ static void __logfs_gc_pass(struct super_block *sb, int target) struct logfs_block *block; int round, progress, last_progress = 0; + /* + * Doing too many changes to the segfile at once would result + * in a large number of aliases. Write the journal before + * things get out of hand. + */ + if (super->s_shadow_tree.no_shadowed_segments >= MAX_OBJ_ALIASES) + logfs_write_anchor(sb); + if (no_free_segments(sb) >= target && super->s_no_object_aliases < MAX_OBJ_ALIASES) return; diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index 33bd260b830..fb0a613f885 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c @@ -389,7 +389,10 @@ static void journal_get_erase_count(struct logfs_area *area) static int journal_erase_segment(struct logfs_area *area) { struct super_block *sb = area->a_sb; - struct logfs_segment_header sh; + union { + struct logfs_segment_header sh; + unsigned char c[ALIGN(sizeof(struct logfs_segment_header), 16)]; + } u; u64 ofs; int err; @@ -397,20 +400,21 @@ static int journal_erase_segment(struct logfs_area *area) if (err) return err; - sh.pad = 0; - sh.type = SEG_JOURNAL; - sh.level = 0; - sh.segno = cpu_to_be32(area->a_segno); - sh.ec = cpu_to_be32(area->a_erase_count); - sh.gec = cpu_to_be64(logfs_super(sb)->s_gec); - sh.crc = logfs_crc32(&sh, sizeof(sh), 4); + memset(&u, 0, sizeof(u)); + u.sh.pad = 0; + u.sh.type = SEG_JOURNAL; + u.sh.level = 0; + u.sh.segno = cpu_to_be32(area->a_segno); + u.sh.ec = cpu_to_be32(area->a_erase_count); + u.sh.gec = cpu_to_be64(logfs_super(sb)->s_gec); + u.sh.crc = logfs_crc32(&u.sh, sizeof(u.sh), 4); /* This causes a bug in segment.c. Not yet. */ //logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, 0); ofs = dev_ofs(sb, area->a_segno, 0); - area->a_used_bytes = ALIGN(sizeof(sh), 16); - logfs_buf_write(area, ofs, &sh, sizeof(sh)); + area->a_used_bytes = sizeof(u); + logfs_buf_write(area, ofs, &u, sizeof(u)); return 0; } @@ -494,6 +498,8 @@ static void account_shadows(struct super_block *sb) btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow); btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow); + btree_grim_visitor32(&tree->segment_map, 0, NULL); + tree->no_shadowed_segments = 0; if (li->li_block) { /* @@ -607,9 +613,9 @@ static size_t __logfs_write_je(struct super_block *sb, void *buf, u16 type, if (len == 0) return logfs_write_header(super, header, 0, type); + BUG_ON(len > sb->s_blocksize); compr_len = logfs_compress(buf, data, len, sb->s_blocksize); if (compr_len < 0 || type == JE_ANCHOR) { - BUG_ON(len > sb->s_blocksize); memcpy(data, buf, len); compr_len = len; compr = COMPR_NONE; @@ -661,6 +667,7 @@ static int logfs_write_je_buf(struct super_block *sb, void *buf, u16 type, if (ofs < 0) return ofs; logfs_buf_write(area, ofs, super->s_compressed_je, len); + BUG_ON(super->s_no_je >= MAX_JOURNAL_ENTRIES); super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs); return 0; } diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index b84b0eec602..0a3df1a0c93 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h @@ -257,10 +257,14 @@ struct logfs_shadow { * struct shadow_tree * @new: shadows where old_ofs==0, indexed by new_ofs * @old: shadows where old_ofs!=0, indexed by old_ofs + * @segment_map: bitfield of segments containing shadows + * @no_shadowed_segment: number of segments containing shadows */ struct shadow_tree { struct btree_head64 new; struct btree_head64 old; + struct btree_head32 segment_map; + int no_shadowed_segments; }; struct object_alias_item { @@ -305,13 +309,14 @@ typedef int write_alias_t(struct super_block *sb, u64 ino, u64 bix, level_t level, int child_no, __be64 val); struct logfs_block_ops { void (*write_block)(struct logfs_block *block); - gc_level_t (*block_level)(struct logfs_block *block); void (*free_block)(struct super_block *sb, struct logfs_block*block); int (*write_alias)(struct super_block *sb, struct logfs_block *block, write_alias_t *write_one_alias); }; +#define MAX_JOURNAL_ENTRIES 256 + struct logfs_super { struct mtd_info *s_mtd; /* underlying device */ struct block_device *s_bdev; /* underlying device */ @@ -378,7 +383,7 @@ struct logfs_super { u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */ u64 s_last_version; struct logfs_area *s_journal_area; /* open journal segment */ - __be64 s_je_array[64]; + __be64 s_je_array[MAX_JOURNAL_ENTRIES]; int s_no_je; int s_sum_index; /* for the 12 summaries */ @@ -722,4 +727,10 @@ static inline struct logfs_area *get_area(struct super_block *sb, return logfs_super(sb)->s_area[(__force u8)gc_level]; } +static inline void logfs_mempool_destroy(mempool_t *pool) +{ + if (pool) + mempool_destroy(pool); +} + #endif diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index bff40253dfb..3159db6958e 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c @@ -430,25 +430,6 @@ static void inode_write_block(struct logfs_block *block) } } -static gc_level_t inode_block_level(struct logfs_block *block) -{ - BUG_ON(block->inode->i_ino == LOGFS_INO_MASTER); - return GC_LEVEL(LOGFS_MAX_LEVELS); -} - -static gc_level_t indirect_block_level(struct logfs_block *block) -{ - struct page *page; - struct inode *inode; - u64 bix; - level_t level; - - page = block->page; - inode = page->mapping->host; - logfs_unpack_index(page->index, &bix, &level); - return expand_level(inode->i_ino, level); -} - /* * This silences a false, yet annoying gcc warning. I hate it when my editor * jumps into bitops.h each time I recompile this file. @@ -587,14 +568,12 @@ static void indirect_free_block(struct super_block *sb, static struct logfs_block_ops inode_block_ops = { .write_block = inode_write_block, - .block_level = inode_block_level, .free_block = inode_free_block, .write_alias = inode_write_alias, }; struct logfs_block_ops indirect_block_ops = { .write_block = indirect_write_block, - .block_level = indirect_block_level, .free_block = indirect_free_block, .write_alias = indirect_write_alias, }; @@ -1241,6 +1220,18 @@ static void free_shadow(struct inode *inode, struct logfs_shadow *shadow) mempool_free(shadow, super->s_shadow_pool); } +static void mark_segment(struct shadow_tree *tree, u32 segno) +{ + int err; + + if (!btree_lookup32(&tree->segment_map, segno)) { + err = btree_insert32(&tree->segment_map, segno, (void *)1, + GFP_NOFS); + BUG_ON(err); + tree->no_shadowed_segments++; + } +} + /** * fill_shadow_tree - Propagate shadow tree changes due to a write * @inode: Inode owning the page @@ -1288,6 +1279,8 @@ static void fill_shadow_tree(struct inode *inode, struct page *page, super->s_dirty_used_bytes += shadow->new_len; super->s_dirty_free_bytes += shadow->old_len; + mark_segment(tree, shadow->old_ofs >> super->s_segshift); + mark_segment(tree, shadow->new_ofs >> super->s_segshift); } } @@ -1845,19 +1838,37 @@ static int __logfs_truncate(struct inode *inode, u64 size) return logfs_truncate_direct(inode, size); } -int logfs_truncate(struct inode *inode, u64 size) +/* + * Truncate, by changing the segment file, can consume a fair amount + * of resources. So back off from time to time and do some GC. + * 8 or 2048 blocks should be well within safety limits even if + * every single block resided in a different segment. + */ +#define TRUNCATE_STEP (8 * 1024 * 1024) +int logfs_truncate(struct inode *inode, u64 target) { struct super_block *sb = inode->i_sb; - int err; + u64 size = i_size_read(inode); + int err = 0; - logfs_get_wblocks(sb, NULL, 1); - err = __logfs_truncate(inode, size); - if (!err) - err = __logfs_write_inode(inode, 0); - logfs_put_wblocks(sb, NULL, 1); + size = ALIGN(size, TRUNCATE_STEP); + while (size > target) { + if (size > TRUNCATE_STEP) + size -= TRUNCATE_STEP; + else + size = 0; + if (size < target) + size = target; + + logfs_get_wblocks(sb, NULL, 1); + err = __logfs_truncate(inode, target); + if (!err) + err = __logfs_write_inode(inode, 0); + logfs_put_wblocks(sb, NULL, 1); + } if (!err) - err = vmtruncate(inode, size); + err = vmtruncate(inode, target); /* I don't trust error recovery yet. */ WARN_ON(err); @@ -2251,8 +2262,6 @@ void logfs_cleanup_rw(struct super_block *sb) struct logfs_super *super = logfs_super(sb); destroy_meta_inode(super->s_segfile_inode); - if (super->s_block_pool) - mempool_destroy(super->s_block_pool); - if (super->s_shadow_pool) - mempool_destroy(super->s_shadow_pool); + logfs_mempool_destroy(super->s_block_pool); + logfs_mempool_destroy(super->s_shadow_pool); } diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index 801a3a14162..f77ce2b470b 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c @@ -183,14 +183,8 @@ static int btree_write_alias(struct super_block *sb, struct logfs_block *block, return 0; } -static gc_level_t btree_block_level(struct logfs_block *block) -{ - return expand_level(block->ino, block->level); -} - static struct logfs_block_ops btree_block_ops = { .write_block = btree_write_block, - .block_level = btree_block_level, .free_block = __free_block, .write_alias = btree_write_alias, }; @@ -919,7 +913,7 @@ err: for (i--; i >= 0; i--) free_area(super->s_area[i]); free_area(super->s_journal_area); - mempool_destroy(super->s_alias_pool); + logfs_mempool_destroy(super->s_alias_pool); return -ENOMEM; } diff --git a/fs/logfs/super.c b/fs/logfs/super.c index b60bfac3263..5866ee6e132 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -12,6 +12,7 @@ #include "logfs.h" #include <linux/bio.h> #include <linux/slab.h> +#include <linux/blkdev.h> #include <linux/mtd/mtd.h> #include <linux/statfs.h> #include <linux/buffer_head.h> @@ -137,6 +138,10 @@ static int logfs_sb_set(struct super_block *sb, void *_super) sb->s_fs_info = super; sb->s_mtd = super->s_mtd; sb->s_bdev = super->s_bdev; + if (sb->s_bdev) + sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info; + if (sb->s_mtd) + sb->s_bdi = sb->s_mtd->backing_dev_info; return 0; } @@ -452,6 +457,8 @@ static int logfs_read_sb(struct super_block *sb, int read_only) btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool); btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool); + btree_init_mempool32(&super->s_shadow_tree.segment_map, + super->s_btree_pool); ret = logfs_init_mapping(sb); if (ret) @@ -516,8 +523,8 @@ static void logfs_kill_sb(struct super_block *sb) if (super->s_erase_page) __free_page(super->s_erase_page); super->s_devops->put_device(sb); - mempool_destroy(super->s_btree_pool); - mempool_destroy(super->s_alias_pool); + logfs_mempool_destroy(super->s_btree_pool); + logfs_mempool_destroy(super->s_alias_pool); kfree(super); log_super("LogFS: Finished unmounting\n"); } diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index f8a6075abf5..07930449a95 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -46,8 +46,6 @@ static inline bool is_privroot_deh(struct dentry *dir, struct reiserfs_de_head *deh) { struct dentry *privroot = REISERFS_SB(dir->d_sb)->priv_root; - if (reiserfs_expose_privroot(dir->d_sb)) - return 0; return (dir == dir->d_parent && privroot->d_inode && deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid); } diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 4f9586bb763..e7cc00e636d 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -554,7 +554,7 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th, if (!err && new_size < i_size_read(dentry->d_inode)) { struct iattr newattrs = { .ia_ctime = current_fs_time(inode->i_sb), - .ia_size = buffer_size, + .ia_size = new_size, .ia_valid = ATTR_SIZE | ATTR_CTIME, }; @@ -973,21 +973,13 @@ int reiserfs_permission(struct inode *inode, int mask) return generic_permission(inode, mask, NULL); } -/* This will catch lookups from the fs root to .reiserfs_priv */ -static int -xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name) +static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd) { - struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root; - if (container_of(q1, struct dentry, d_name) == priv_root) - return -ENOENT; - if (q1->len == name->len && - !memcmp(q1->name, name->name, name->len)) - return 0; - return 1; + return -EPERM; } static const struct dentry_operations xattr_lookup_poison_ops = { - .d_compare = xattr_lookup_poison, + .d_revalidate = xattr_hide_revalidate, }; int reiserfs_lookup_privroot(struct super_block *s) @@ -1001,8 +993,7 @@ int reiserfs_lookup_privroot(struct super_block *s) strlen(PRIVROOT_NAME)); if (!IS_ERR(dentry)) { REISERFS_SB(s)->priv_root = dentry; - if (!reiserfs_expose_privroot(s)) - s->s_root->d_op = &xattr_lookup_poison_ops; + dentry->d_op = &xattr_lookup_poison_ops; if (dentry->d_inode) dentry->d_inode->i_flags |= S_PRIVATE; } else diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h index 81f3b14d5d7..68f883b30a5 100644 --- a/include/linux/firewire-cdev.h +++ b/include/linux/firewire-cdev.h @@ -17,7 +17,7 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. diff --git a/include/linux/firewire-constants.h b/include/linux/firewire-constants.h index 9c63f06e67f..9b4bb5fbba4 100644 --- a/include/linux/firewire-constants.h +++ b/include/linux/firewire-constants.h @@ -17,7 +17,7 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. diff --git a/include/linux/fs.h b/include/linux/fs.h index 39d57bc6cc7..44f35aea2f1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2315,8 +2315,9 @@ extern int vfs_fstatat(int , char __user *, struct kstat *, int); extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg); extern int __generic_block_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, u64 start, - u64 len, get_block_t *get_block); + struct fiemap_extent_info *fieinfo, + loff_t start, loff_t len, + get_block_t *get_block); extern int generic_block_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len, get_block_t *get_block); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index a3fd0f91d94..169d07758ee 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -54,7 +54,7 @@ extern struct kmem_cache *kvm_vcpu_cache; */ struct kvm_io_bus { int dev_count; -#define NR_IOBUS_DEVS 6 +#define NR_IOBUS_DEVS 200 struct kvm_io_device *devs[NR_IOBUS_DEVS]; }; @@ -119,6 +119,11 @@ struct kvm_memory_slot { int user_alloc; }; +static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot) +{ + return ALIGN(memslot->npages, BITS_PER_LONG) / 8; +} + struct kvm_kernel_irq_routing_entry { u32 gsi; u32 type; diff --git a/include/linux/poison.h b/include/linux/poison.h index 2110a81c5e2..34066ffd893 100644 --- a/include/linux/poison.h +++ b/include/linux/poison.h @@ -48,6 +48,15 @@ #define POISON_FREE 0x6b /* for use-after-free poisoning */ #define POISON_END 0xa5 /* end-byte of poisoning */ +/********** mm/hugetlb.c **********/ +/* + * Private mappings of hugetlb pages use this poisoned value for + * page->mapping. The core VM should not be doing anything with this mapping + * but futex requires the existence of some page->mapping value even though it + * is unused if PAGE_MAPPING_ANON is set. + */ +#define HUGETLB_POISON ((void *)(0x00300300 + POISON_POINTER_DELTA + PAGE_MAPPING_ANON)) + /********** arch/$ARCH/mm/init.c **********/ #define POISON_FREE_INITMEM 0xcc diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 28c9fd020d3..ebd74726529 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -183,9 +183,13 @@ static inline struct regulator *__must_check regulator_get(struct device *dev, { /* Nothing except the stubbed out regulator API should be * looking at the value except to check if it is an error - * value so the actual return value doesn't matter. + * value. Drivers are free to handle NULL specifically by + * skipping all regulator API calls, but they don't have to. + * Drivers which don't, should make sure they properly handle + * corner cases of the API, such as regulator_get_voltage() + * returning 0. */ - return (struct regulator *)id; + return NULL; } static inline void regulator_put(struct regulator *regulator) { diff --git a/init/initramfs.c b/init/initramfs.c index 37d3859b1b3..4b9c2020509 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -457,7 +457,8 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len) compress_name); message = msg_buf; } - } + } else + error("junk in compressed archive"); if (state != Reset) error("junk in compressed archive"); this_header = saved_offset + my_inptr; diff --git a/kernel/cred.c b/kernel/cred.c index e1dbe9eef80..62af1816c23 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -398,6 +398,8 @@ struct cred *prepare_usermodehelper_creds(void) error: put_cred(new); + return NULL; + free_tgcred: #ifdef CONFIG_KEYS kfree(tgcred); @@ -791,8 +793,6 @@ bool creds_are_invalid(const struct cred *cred) { if (cred->magic != CRED_MAGIC) return true; - if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers)) - return true; #ifdef CONFIG_SECURITY_SELINUX if (selinux_is_enabled()) { if ((unsigned long) cred->security < PAGE_SIZE) diff --git a/kernel/sys.c b/kernel/sys.c index 6d1a7e0f9d5..7cb426a5896 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1118,7 +1118,7 @@ DECLARE_RWSEM(uts_sem); #ifdef COMPAT_UTS_MACHINE #define override_architecture(name) \ - (current->personality == PER_LINUX32 && \ + (personality(current->personality) == PER_LINUX32 && \ copy_to_user(name->machine, COMPAT_UTS_MACHINE, \ sizeof(COMPAT_UTS_MACHINE))) #else diff --git a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c index db521f45626..bcb3a4bd68f 100644 --- a/lib/decompress_unlzo.c +++ b/lib/decompress_unlzo.c @@ -97,7 +97,7 @@ STATIC inline int INIT unlzo(u8 *input, int in_len, u32 src_len, dst_len; size_t tmp; u8 *in_buf, *in_buf_save, *out_buf; - int obytes_processed = 0; + int ret = -1; set_error_fn(error_fn); @@ -174,15 +174,22 @@ STATIC inline int INIT unlzo(u8 *input, int in_len, /* decompress */ tmp = dst_len; - r = lzo1x_decompress_safe((u8 *) in_buf, src_len, + + /* When the input data is not compressed at all, + * lzo1x_decompress_safe will fail, so call memcpy() + * instead */ + if (unlikely(dst_len == src_len)) + memcpy(out_buf, in_buf, src_len); + else { + r = lzo1x_decompress_safe((u8 *) in_buf, src_len, out_buf, &tmp); - if (r != LZO_E_OK || dst_len != tmp) { - error("Compressed data violation"); - goto exit_2; + if (r != LZO_E_OK || dst_len != tmp) { + error("Compressed data violation"); + goto exit_2; + } } - obytes_processed += dst_len; if (flush) flush(out_buf, dst_len); if (output) @@ -196,6 +203,7 @@ STATIC inline int INIT unlzo(u8 *input, int in_len, in_buf += src_len; } + ret = 0; exit_2: if (!input) free(in_buf); @@ -203,7 +211,7 @@ exit_1: if (!output) free(out_buf); exit: - return obytes_processed; + return ret; } #define decompress unlzo diff --git a/lib/flex_array.c b/lib/flex_array.c index 66eef2e4483..41b1804fa72 100644 --- a/lib/flex_array.c +++ b/lib/flex_array.c @@ -99,7 +99,7 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total, ret->element_size = element_size; ret->total_nr_elements = total; if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO)) - memset(ret->parts[0], FLEX_ARRAY_FREE, + memset(&ret->parts[0], FLEX_ARRAY_FREE, FLEX_ARRAY_BASE_BYTES_LEFT); return ret; } diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 7376b7c55ff..46d34b0b74a 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -118,6 +118,7 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base) return simple_strtoull(cp, endp, base); } +EXPORT_SYMBOL(simple_strtoll); /** * strict_strtoul - convert a string to an unsigned long strictly diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 6034dc9e979..ffbdfc86aed 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -546,6 +546,7 @@ static void free_huge_page(struct page *page) mapping = (struct address_space *) page_private(page); set_page_private(page, 0); + page->mapping = NULL; BUG_ON(page_count(page)); INIT_LIST_HEAD(&page->lru); @@ -2447,8 +2448,10 @@ retry: spin_lock(&inode->i_lock); inode->i_blocks += blocks_per_huge_page(h); spin_unlock(&inode->i_lock); - } else + } else { lock_page(page); + page->mapping = HUGETLB_POISON; + } } /* @@ -365,7 +365,7 @@ static int break_ksm(struct vm_area_struct *vma, unsigned long addr) do { cond_resched(); page = follow_page(vma, addr, FOLL_GET); - if (!page) + if (IS_ERR_OR_NULL(page)) break; if (PageKsm(page)) ret = handle_mm_fault(vma->vm_mm, vma, addr, @@ -447,7 +447,7 @@ static struct page *get_mergeable_page(struct rmap_item *rmap_item) goto out; page = follow_page(vma, addr, FOLL_GET); - if (!page) + if (IS_ERR_OR_NULL(page)) goto out; if (PageAnon(page)) { flush_anon_page(vma, page, addr); @@ -1086,7 +1086,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, cond_resched(); tree_rmap_item = rb_entry(*new, struct rmap_item, node); tree_page = get_mergeable_page(tree_rmap_item); - if (!tree_page) + if (IS_ERR_OR_NULL(tree_page)) return NULL; /* @@ -1294,7 +1294,7 @@ next_mm: if (ksm_test_exit(mm)) break; *page = follow_page(vma, ksm_scan.address, FOLL_GET); - if (*page && PageAnon(*page)) { + if (!IS_ERR_OR_NULL(*page) && PageAnon(*page)) { flush_anon_page(vma, *page, ksm_scan.address); flush_dcache_page(*page); rmap_item = get_next_rmap_item(slot, @@ -1308,7 +1308,7 @@ next_mm: up_read(&mm->mmap_sem); return rmap_item; } - if (*page) + if (!IS_ERR_OR_NULL(*page)) put_page(*page); ksm_scan.address += PAGE_SIZE; cond_resched(); @@ -1367,7 +1367,7 @@ next_mm: static void ksm_do_scan(unsigned int scan_npages) { struct rmap_item *rmap_item; - struct page *page; + struct page *uninitialized_var(page); while (scan_npages--) { cond_resched(); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index f4ede99c8b9..6c755de385f 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2429,11 +2429,11 @@ int mem_cgroup_prepare_migration(struct page *page, struct mem_cgroup **ptr) } unlock_page_cgroup(pc); + *ptr = mem; if (mem) { - ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, &mem, false); + ret = __mem_cgroup_try_charge(NULL, GFP_KERNEL, ptr, false); css_put(&mem->css); } - *ptr = mem; return ret; } diff --git a/mm/rmap.c b/mm/rmap.c index 526704e8215..07fc9475879 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -133,8 +133,8 @@ int anon_vma_prepare(struct vm_area_struct *vma) goto out_enomem_free_avc; allocated = anon_vma; } - spin_lock(&anon_vma->lock); + spin_lock(&anon_vma->lock); /* page_table_lock to protect against threads */ spin_lock(&mm->page_table_lock); if (likely(!vma->anon_vma)) { @@ -144,14 +144,15 @@ int anon_vma_prepare(struct vm_area_struct *vma) list_add(&avc->same_vma, &vma->anon_vma_chain); list_add(&avc->same_anon_vma, &anon_vma->head); allocated = NULL; + avc = NULL; } spin_unlock(&mm->page_table_lock); - spin_unlock(&anon_vma->lock); - if (unlikely(allocated)) { + + if (unlikely(allocated)) anon_vma_free(allocated); + if (unlikely(avc)) anon_vma_chain_free(avc); - } } return 0; diff --git a/security/inode.c b/security/inode.c index c3a793881d0..1c812e87450 100644 --- a/security/inode.c +++ b/security/inode.c @@ -161,13 +161,13 @@ static int create_by_name(const char *name, mode_t mode, mutex_lock(&parent->d_inode->i_mutex); *dentry = lookup_one_len(name, parent, strlen(name)); - if (!IS_ERR(dentry)) { + if (!IS_ERR(*dentry)) { if ((mode & S_IFMT) == S_IFDIR) error = mkdir(parent->d_inode, *dentry, mode); else error = create(parent->d_inode, *dentry, mode); } else - error = PTR_ERR(dentry); + error = PTR_ERR(*dentry); mutex_unlock(&parent->d_inode->i_mutex); return error; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 03fe63ed55b..ea97c3120d6 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -68,7 +68,8 @@ static int call_sbin_request_key(struct key_construction *cons, { const struct cred *cred = current_cred(); key_serial_t prkey, sskey; - struct key *key = cons->key, *authkey = cons->authkey, *keyring; + struct key *key = cons->key, *authkey = cons->authkey, *keyring, + *session; char *argv[9], *envp[3], uid_str[12], gid_str[12]; char key_str[12], keyring_str[3][12]; char desc[20]; @@ -112,10 +113,12 @@ static int call_sbin_request_key(struct key_construction *cons, if (cred->tgcred->process_keyring) prkey = cred->tgcred->process_keyring->serial; - if (cred->tgcred->session_keyring) - sskey = rcu_dereference(cred->tgcred->session_keyring)->serial; - else - sskey = cred->user->session_keyring->serial; + rcu_read_lock(); + session = rcu_dereference(cred->tgcred->session_keyring); + if (!session) + session = cred->user->session_keyring; + sskey = session->serial; + rcu_read_unlock(); sprintf(keyring_str[2], "%d", sskey); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f669442b7c8..cec68152dcb 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2273,6 +2273,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), {} }; diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index af34606c30c..e9fdfc4b1c5 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -519,14 +519,6 @@ static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) ad198x_power_eapd(codec); return 0; } - -static int ad198x_resume(struct hda_codec *codec) -{ - ad198x_init(codec); - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - return 0; -} #endif static struct hda_codec_ops ad198x_patch_ops = { @@ -539,7 +531,6 @@ static struct hda_codec_ops ad198x_patch_ops = { #endif #ifdef SND_HDA_NEEDS_RESUME .suspend = ad198x_suspend, - .resume = ad198x_resume, #endif .reboot_notify = ad198x_shutup, }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index aad1627f56f..7404dba16f8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4143,7 +4143,7 @@ static struct snd_pci_quirk alc880_cfg_tbl[] = { SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FUJITSU), - SND_PCI_QUIRK(0x1734, 0x10ac, "FSC", ALC880_UNIWILL), + SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_F1734), SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU), SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW), SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c4be3fab94e..7fb7d017a34 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1607,6 +1607,10 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "Dell Studio 1555", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, "Dell Studio 1557", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, + "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, + "Dell Studio 1558", STAC_DELL_M6_BOTH), {} /* terminator */ }; diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index b64e78139d6..b56e3367678 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -849,6 +849,7 @@ struct snd_m3 { struct snd_kcontrol *master_switch; struct snd_kcontrol *master_volume; struct tasklet_struct hwvol_tq; + unsigned int in_suspend; #ifdef CONFIG_PM u16 *suspend_mem; @@ -884,6 +885,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { MODULE_DEVICE_TABLE(pci, snd_m3_ids); static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { + SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c), SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), SND_PCI_QUIRK(0x1033, 0x80f1, "NEC LM800J/7", 0x03), @@ -1613,6 +1615,11 @@ static void snd_m3_update_hw_volume(unsigned long private_data) outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); + /* Ignore spurious HV interrupts during suspend / resume, this avoids + mistaking them for a mute button press. */ + if (chip->in_suspend) + return; + if (!chip->master_switch || !chip->master_volume) return; @@ -2424,6 +2431,7 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state) if (chip->suspend_mem == NULL) return 0; + chip->in_suspend = 1; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); @@ -2497,6 +2505,7 @@ static int m3_resume(struct pci_dev *pci) snd_m3_hv_init(chip); snd_power_change_state(card, SNDRV_CTL_POWER_D0); + chip->in_suspend = 0; return 0; } #endif /* CONFIG_PM */ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 5a0cd194dce..c82ae249263 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -341,7 +341,11 @@ static void kvm_mmu_notifier_release(struct mmu_notifier *mn, struct mm_struct *mm) { struct kvm *kvm = mmu_notifier_to_kvm(mn); + int idx; + + idx = srcu_read_lock(&kvm->srcu); kvm_arch_flush_shadow(kvm); + srcu_read_unlock(&kvm->srcu, idx); } static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { @@ -648,7 +652,7 @@ skip_lpage: /* Allocate page dirty bitmap if needed */ if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) { - unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8; + unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(&new); new.dirty_bitmap = vmalloc(dirty_bytes); if (!new.dirty_bitmap) @@ -768,7 +772,7 @@ int kvm_get_dirty_log(struct kvm *kvm, { struct kvm_memory_slot *memslot; int r, i; - int n; + unsigned long n; unsigned long any = 0; r = -EINVAL; @@ -780,7 +784,7 @@ int kvm_get_dirty_log(struct kvm *kvm, if (!memslot->dirty_bitmap) goto out; - n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; + n = kvm_dirty_bitmap_bytes(memslot); for (i = 0; !any && i < n/sizeof(long); ++i) any = memslot->dirty_bitmap[i]; @@ -1186,10 +1190,13 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) memslot = gfn_to_memslot_unaliased(kvm, gfn); if (memslot && memslot->dirty_bitmap) { unsigned long rel_gfn = gfn - memslot->base_gfn; + unsigned long *p = memslot->dirty_bitmap + + rel_gfn / BITS_PER_LONG; + int offset = rel_gfn % BITS_PER_LONG; /* avoid RMW */ - if (!generic_test_le_bit(rel_gfn, memslot->dirty_bitmap)) - generic___set_le_bit(rel_gfn, memslot->dirty_bitmap); + if (!generic_test_le_bit(offset, p)) + generic___set_le_bit(offset, p); } } |