1 change: 1 addition & 0 deletions arch/sparc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ config SPARC

config SPARC32
def_bool !64BIT
select GENERIC_ATOMIC64

config SPARC64
def_bool 64BIT
Expand Down
2 changes: 2 additions & 0 deletions arch/sparc/include/asm/atomic_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

#ifdef __KERNEL__

#include <asm-generic/atomic64.h>

#include <asm/system.h>

#define ATOMIC_INIT(i) { (i) }
Expand Down
1 change: 1 addition & 0 deletions arch/sparc/include/asm/pgtable_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
}

#include <asm/tlbflush.h>
#include <asm-generic/pgtable.h>

/* We provide our own get_unmapped_area to cope with VA holes and
Expand Down
1 change: 1 addition & 0 deletions arch/sparc/include/asm/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ struct __old_sigaction {
unsigned long sa_flags;
void (*sa_restorer)(void); /* not used by Linux/SPARC yet */
};
#define __ARCH_HAS_SA_RESTORER

typedef struct sigaltstack {
void __user *ss_sp;
Expand Down
3 changes: 1 addition & 2 deletions arch/sparc/include/asm/system_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,7 @@ do { \
* and 2 stores in this critical code path. -DaveM
*/
#define switch_to(prev, next, last) \
do { flush_tlb_pending(); \
save_and_clear_fpu(); \
do { save_and_clear_fpu(); \
/* If you are tempted to conditionalize the following */ \
/* so that ASI is only written if it changes, think again. */ \
__asm__ __volatile__("wr %%g0, %0, %%asi" \
Expand Down
37 changes: 31 additions & 6 deletions arch/sparc/include/asm/tlbflush_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,40 @@
struct tlb_batch {
struct mm_struct *mm;
unsigned long tlb_nr;
unsigned long active;
unsigned long vaddrs[TLB_BATCH_NR];
};

extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
extern void flush_tsb_user(struct tlb_batch *tb);
extern void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr);

/* TLB flush operations. */

extern void flush_tlb_pending(void);
static inline void flush_tlb_mm(struct mm_struct *mm)
{
}

static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long vmaddr)
{
}

static inline void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
}

#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE

#define flush_tlb_range(vma,start,end) \
do { (void)(start); flush_tlb_pending(); } while (0)
#define flush_tlb_page(vma,addr) flush_tlb_pending()
#define flush_tlb_mm(mm) flush_tlb_pending()
extern void flush_tlb_pending(void);
extern void arch_enter_lazy_mmu_mode(void);
extern void arch_leave_lazy_mmu_mode(void);
#define arch_flush_lazy_mmu_mode() do {} while (0)

/* Local cpu only. */
extern void __flush_tlb_all(void);

extern void __flush_tlb_page(unsigned long context, unsigned long vaddr);
extern void __flush_tlb_kernel_range(unsigned long start, unsigned long end);

#ifndef CONFIG_SMP
Expand All @@ -38,15 +54,24 @@ do { flush_tsb_kernel_range(start,end); \
__flush_tlb_kernel_range(start,end); \
} while (0)

static inline void global_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
{
__flush_tlb_page(CTX_HWBITS(mm->context), vaddr);
}

#else /* CONFIG_SMP */

extern void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end);
extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr);

#define flush_tlb_kernel_range(start, end) \
do { flush_tsb_kernel_range(start,end); \
smp_flush_tlb_kernel_range(start, end); \
} while (0)

#define global_flush_tlb_page(mm, vaddr) \
smp_flush_tlb_page(mm, vaddr)

#endif /* ! CONFIG_SMP */

#endif /* _SPARC64_TLBFLUSH_H */
41 changes: 37 additions & 4 deletions arch/sparc/kernel/smp_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ void smp_tsb_sync(struct mm_struct *mm)
}

extern unsigned long xcall_flush_tlb_mm;
extern unsigned long xcall_flush_tlb_pending;
extern unsigned long xcall_flush_tlb_page;
extern unsigned long xcall_flush_tlb_kernel_range;
extern unsigned long xcall_fetch_glob_regs;
extern unsigned long xcall_receive_signal;
Expand Down Expand Up @@ -1070,23 +1070,56 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
put_cpu();
}

struct tlb_pending_info {
unsigned long ctx;
unsigned long nr;
unsigned long *vaddrs;
};

static void tlb_pending_func(void *info)
{
struct tlb_pending_info *t = info;

__flush_tlb_pending(t->ctx, t->nr, t->vaddrs);
}

void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long *vaddrs)
{
u32 ctx = CTX_HWBITS(mm->context);
struct tlb_pending_info info;
int cpu = get_cpu();

info.ctx = ctx;
info.nr = nr;
info.vaddrs = vaddrs;

if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
else
smp_cross_call_masked(&xcall_flush_tlb_pending,
ctx, nr, (unsigned long) vaddrs,
mm_cpumask(mm));
smp_call_function_many(mm_cpumask(mm), tlb_pending_func,
&info, 1);

__flush_tlb_pending(ctx, nr, vaddrs);

put_cpu();
}

void smp_flush_tlb_page(struct mm_struct *mm, unsigned long vaddr)
{
unsigned long context = CTX_HWBITS(mm->context);
int cpu = get_cpu();

if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
cpumask_copy(mm_cpumask(mm), cpumask_of(cpu));
else
smp_cross_call_masked(&xcall_flush_tlb_page,
context, vaddr, 0,
mm_cpumask(mm));
__flush_tlb_page(context, vaddr);

put_cpu();
}

void smp_flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
start &= PAGE_MASK;
Expand Down
39 changes: 35 additions & 4 deletions arch/sparc/mm/tlb.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
void flush_tlb_pending(void)
{
struct tlb_batch *tb = &get_cpu_var(tlb_batch);
struct mm_struct *mm = tb->mm;

if (tb->tlb_nr) {
flush_tsb_user(tb);
if (!tb->tlb_nr)
goto out;

if (CTX_VALID(tb->mm->context)) {
flush_tsb_user(tb);

if (CTX_VALID(mm->context)) {
if (tb->tlb_nr == 1) {
global_flush_tlb_page(mm, tb->vaddrs[0]);
} else {
#ifdef CONFIG_SMP
smp_flush_tlb_pending(tb->mm, tb->tlb_nr,
&tb->vaddrs[0]);
Expand All @@ -37,12 +43,30 @@ void flush_tlb_pending(void)
tb->tlb_nr, &tb->vaddrs[0]);
#endif
}
tb->tlb_nr = 0;
}

tb->tlb_nr = 0;

out:
put_cpu_var(tlb_batch);
}

void arch_enter_lazy_mmu_mode(void)
{
struct tlb_batch *tb = &__get_cpu_var(tlb_batch);

tb->active = 1;
}

void arch_leave_lazy_mmu_mode(void)
{
struct tlb_batch *tb = &__get_cpu_var(tlb_batch);

if (tb->tlb_nr)
flush_tlb_pending();
tb->active = 0;
}

void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
pte_t *ptep, pte_t orig, int fullmm)
{
Expand Down Expand Up @@ -90,6 +114,12 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
nr = 0;
}

if (!tb->active) {
global_flush_tlb_page(mm, vaddr);
flush_tsb_user_page(mm, vaddr);
goto out;
}

if (nr == 0)
tb->mm = mm;

Expand All @@ -98,5 +128,6 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
if (nr >= TLB_BATCH_NR)
flush_tlb_pending();

out:
put_cpu_var(tlb_batch);
}
57 changes: 42 additions & 15 deletions arch/sparc/mm/tsb.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@
#include <linux/slab.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/tlbflush.h>
#include <asm/tlb.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
#include <asm/tsb.h>
#include <asm/tlb.h>
#include <asm/oplib.h>

extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
Expand Down Expand Up @@ -47,23 +46,27 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
}
}

static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
unsigned long tsb, unsigned long nentries)
static void __flush_tsb_one_entry(unsigned long tsb, unsigned long v,
unsigned long hash_shift,
unsigned long nentries)
{
unsigned long i;
unsigned long tag, ent, hash;

for (i = 0; i < tb->tlb_nr; i++) {
unsigned long v = tb->vaddrs[i];
unsigned long tag, ent, hash;
v &= ~0x1UL;
hash = tsb_hash(v, hash_shift, nentries);
ent = tsb + (hash * sizeof(struct tsb));
tag = (v >> 22UL);

v &= ~0x1UL;
tsb_flush(ent, tag);
}

hash = tsb_hash(v, hash_shift, nentries);
ent = tsb + (hash * sizeof(struct tsb));
tag = (v >> 22UL);
static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
unsigned long tsb, unsigned long nentries)
{
unsigned long i;

tsb_flush(ent, tag);
}
for (i = 0; i < tb->tlb_nr; i++)
__flush_tsb_one_entry(tsb, tb->vaddrs[i], hash_shift, nentries);
}

void flush_tsb_user(struct tlb_batch *tb)
Expand Down Expand Up @@ -91,6 +94,30 @@ void flush_tsb_user(struct tlb_batch *tb)
spin_unlock_irqrestore(&mm->context.lock, flags);
}

void flush_tsb_user_page(struct mm_struct *mm, unsigned long vaddr)
{
unsigned long nentries, base, flags;

spin_lock_irqsave(&mm->context.lock, flags);

base = (unsigned long) mm->context.tsb_block[MM_TSB_BASE].tsb;
nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
if (tlb_type == cheetah_plus || tlb_type == hypervisor)
base = __pa(base);
__flush_tsb_one_entry(base, vaddr, PAGE_SHIFT, nentries);

#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
base = (unsigned long) mm->context.tsb_block[MM_TSB_HUGE].tsb;
nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
if (tlb_type == cheetah_plus || tlb_type == hypervisor)
base = __pa(base);
__flush_tsb_one_entry(base, vaddr, HPAGE_SHIFT, nentries);
}
#endif
spin_unlock_irqrestore(&mm->context.lock, flags);
}

#if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
#define HV_PGSZ_IDX_BASE HV_PGSZ_IDX_8K
#define HV_PGSZ_MASK_BASE HV_PGSZ_MASK_8K
Expand Down
119 changes: 95 additions & 24 deletions arch/sparc/mm/ultra.S
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,33 @@ __flush_tlb_mm: /* 18 insns */
nop
nop

.align 32
.globl __flush_tlb_page
__flush_tlb_page: /* 22 insns */
/* %o0 = context, %o1 = vaddr */
rdpr %pstate, %g7
andn %g7, PSTATE_IE, %g2
wrpr %g2, %pstate
mov SECONDARY_CONTEXT, %o4
ldxa [%o4] ASI_DMMU, %g2
stxa %o0, [%o4] ASI_DMMU
andcc %o1, 1, %g0
andn %o1, 1, %o3
be,pn %icc, 1f
or %o3, 0x10, %o3
stxa %g0, [%o3] ASI_IMMU_DEMAP
1: stxa %g0, [%o3] ASI_DMMU_DEMAP
membar #Sync
stxa %g2, [%o4] ASI_DMMU
sethi %hi(KERNBASE), %o4
flush %o4
retl
wrpr %g7, 0x0, %pstate
nop
nop
nop
nop

.align 32
.globl __flush_tlb_pending
__flush_tlb_pending: /* 26 insns */
Expand Down Expand Up @@ -203,6 +230,31 @@ __cheetah_flush_tlb_mm: /* 19 insns */
retl
wrpr %g7, 0x0, %pstate

__cheetah_flush_tlb_page: /* 22 insns */
/* %o0 = context, %o1 = vaddr */
rdpr %pstate, %g7
andn %g7, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o4
ldxa [%o4] ASI_DMMU, %g2
srlx %g2, CTX_PGSZ1_NUC_SHIFT, %o3
sllx %o3, CTX_PGSZ1_NUC_SHIFT, %o3
or %o0, %o3, %o0 /* Preserve nucleus page size fields */
stxa %o0, [%o4] ASI_DMMU
andcc %o1, 1, %g0
be,pn %icc, 1f
andn %o1, 1, %o3
stxa %g0, [%o3] ASI_IMMU_DEMAP
1: stxa %g0, [%o3] ASI_DMMU_DEMAP
membar #Sync
stxa %g2, [%o4] ASI_DMMU
sethi %hi(KERNBASE), %o4
flush %o4
wrpr %g0, 0, %tl
retl
wrpr %g7, 0x0, %pstate

__cheetah_flush_tlb_pending: /* 27 insns */
/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
rdpr %pstate, %g7
Expand Down Expand Up @@ -269,6 +321,20 @@ __hypervisor_flush_tlb_mm: /* 10 insns */
retl
nop

__hypervisor_flush_tlb_page: /* 11 insns */
/* %o0 = context, %o1 = vaddr */
mov %o0, %g2
mov %o1, %o0 /* ARG0: vaddr + IMMU-bit */
mov %g2, %o1 /* ARG1: mmu context */
mov HV_MMU_ALL, %o2 /* ARG2: flags */
srlx %o0, PAGE_SHIFT, %o0
sllx %o0, PAGE_SHIFT, %o0
ta HV_MMU_UNMAP_ADDR_TRAP
brnz,pn %o0, __hypervisor_tlb_tl0_error
mov HV_MMU_UNMAP_ADDR_TRAP, %o1
retl
nop

__hypervisor_flush_tlb_pending: /* 16 insns */
/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
sllx %o1, 3, %g1
Expand Down Expand Up @@ -339,6 +405,13 @@ cheetah_patch_cachetlbops:
call tlb_patch_one
mov 19, %o2

sethi %hi(__flush_tlb_page), %o0
or %o0, %lo(__flush_tlb_page), %o0
sethi %hi(__cheetah_flush_tlb_page), %o1
or %o1, %lo(__cheetah_flush_tlb_page), %o1
call tlb_patch_one
mov 22, %o2

sethi %hi(__flush_tlb_pending), %o0
or %o0, %lo(__flush_tlb_pending), %o0
sethi %hi(__cheetah_flush_tlb_pending), %o1
Expand Down Expand Up @@ -397,31 +470,26 @@ xcall_flush_tlb_mm: /* 21 insns */
nop
nop

.globl xcall_flush_tlb_pending
xcall_flush_tlb_pending: /* 21 insns */
/* %g5=context, %g1=nr, %g7=vaddrs[] */
sllx %g1, 3, %g1
.globl xcall_flush_tlb_page
xcall_flush_tlb_page: /* 17 insns */
/* %g5=context, %g1=vaddr */
mov PRIMARY_CONTEXT, %g4
ldxa [%g4] ASI_DMMU, %g2
srlx %g2, CTX_PGSZ1_NUC_SHIFT, %g4
sllx %g4, CTX_PGSZ1_NUC_SHIFT, %g4
or %g5, %g4, %g5
mov PRIMARY_CONTEXT, %g4
stxa %g5, [%g4] ASI_DMMU
1: sub %g1, (1 << 3), %g1
ldx [%g7 + %g1], %g5
andcc %g5, 0x1, %g0
andcc %g1, 0x1, %g0
be,pn %icc, 2f

andn %g5, 0x1, %g5
andn %g1, 0x1, %g5
stxa %g0, [%g5] ASI_IMMU_DEMAP
2: stxa %g0, [%g5] ASI_DMMU_DEMAP
membar #Sync
brnz,pt %g1, 1b
nop
stxa %g2, [%g4] ASI_DMMU
retry
nop
nop

.globl xcall_flush_tlb_kernel_range
xcall_flush_tlb_kernel_range: /* 25 insns */
Expand Down Expand Up @@ -596,15 +664,13 @@ __hypervisor_xcall_flush_tlb_mm: /* 21 insns */
membar #Sync
retry

.globl __hypervisor_xcall_flush_tlb_pending
__hypervisor_xcall_flush_tlb_pending: /* 21 insns */
/* %g5=ctx, %g1=nr, %g7=vaddrs[], %g2,%g3,%g4,g6=scratch */
sllx %g1, 3, %g1
.globl __hypervisor_xcall_flush_tlb_page
__hypervisor_xcall_flush_tlb_page: /* 17 insns */
/* %g5=ctx, %g1=vaddr */
mov %o0, %g2
mov %o1, %g3
mov %o2, %g4
1: sub %g1, (1 << 3), %g1
ldx [%g7 + %g1], %o0 /* ARG0: virtual address */
mov %g1, %o0 /* ARG0: virtual address */
mov %g5, %o1 /* ARG1: mmu context */
mov HV_MMU_ALL, %o2 /* ARG2: flags */
srlx %o0, PAGE_SHIFT, %o0
Expand All @@ -613,8 +679,6 @@ __hypervisor_xcall_flush_tlb_pending: /* 21 insns */
mov HV_MMU_UNMAP_ADDR_TRAP, %g6
brnz,a,pn %o0, __hypervisor_tlb_xcall_error
mov %o0, %g5
brnz,pt %g1, 1b
nop
mov %g2, %o0
mov %g3, %o1
mov %g4, %o2
Expand Down Expand Up @@ -697,6 +761,13 @@ hypervisor_patch_cachetlbops:
call tlb_patch_one
mov 10, %o2

sethi %hi(__flush_tlb_page), %o0
or %o0, %lo(__flush_tlb_page), %o0
sethi %hi(__hypervisor_flush_tlb_page), %o1
or %o1, %lo(__hypervisor_flush_tlb_page), %o1
call tlb_patch_one
mov 11, %o2

sethi %hi(__flush_tlb_pending), %o0
or %o0, %lo(__flush_tlb_pending), %o0
sethi %hi(__hypervisor_flush_tlb_pending), %o1
Expand Down Expand Up @@ -728,12 +799,12 @@ hypervisor_patch_cachetlbops:
call tlb_patch_one
mov 21, %o2

sethi %hi(xcall_flush_tlb_pending), %o0
or %o0, %lo(xcall_flush_tlb_pending), %o0
sethi %hi(__hypervisor_xcall_flush_tlb_pending), %o1
or %o1, %lo(__hypervisor_xcall_flush_tlb_pending), %o1
sethi %hi(xcall_flush_tlb_page), %o0
or %o0, %lo(xcall_flush_tlb_page), %o0
sethi %hi(__hypervisor_xcall_flush_tlb_page), %o1
or %o1, %lo(__hypervisor_xcall_flush_tlb_page), %o1
call tlb_patch_one
mov 21, %o2
mov 17, %o2

sethi %hi(xcall_flush_tlb_kernel_range), %o0
or %o0, %lo(xcall_flush_tlb_kernel_range), %o0
Expand Down
4 changes: 0 additions & 4 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1219,10 +1219,6 @@ config HAVE_ARCH_BOOTMEM
def_bool y
depends on X86_32 && NUMA

config HAVE_ARCH_ALLOC_REMAP
def_bool y
depends on X86_32 && NUMA

config ARCH_HAVE_MEMORY_PRESENT
def_bool y
depends on X86_32 && DISCONTIGMEM
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/ia32/ia32entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ sysexit_from_sys_call:
testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
jnz ia32_ret_from_sys_call
TRACE_IRQS_ON
sti
ENABLE_INTERRUPTS(CLBR_NONE)
movl %eax,%esi /* second arg, syscall return value */
cmpl $0,%eax /* is it < 0? */
setl %al /* 1 if so, 0 if not */
Expand All @@ -218,7 +218,7 @@ sysexit_from_sys_call:
GET_THREAD_INFO(%r10)
movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall return value */
movl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),%edi
cli
DISABLE_INTERRUPTS(CLBR_NONE)
TRACE_IRQS_OFF
testl %edi,TI_flags(%r10)
jz \exit
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ struct kvm_vcpu_arch {
gpa_t time;
struct pvclock_vcpu_time_info hv_clock;
unsigned int hw_tsc_khz;
unsigned int time_offset;
struct page *time_page;
struct gfn_to_hva_cache pv_time;
bool pv_time_enabled;
u64 last_guest_tsc;
u64 last_kernel_ns;
u64 last_tsc_nsec;
Expand Down
6 changes: 0 additions & 6 deletions arch/x86/include/asm/mmzone_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ extern struct pglist_data *node_data[];

#include <asm/numaq.h>

extern void resume_map_numa_kva(pgd_t *pgd);

#else /* !CONFIG_NUMA */

static inline void resume_map_numa_kva(pgd_t *pgd) {}

#endif /* CONFIG_NUMA */

#ifdef CONFIG_DISCONTIGMEM
Expand Down
5 changes: 4 additions & 1 deletion arch/x86/include/asm/paravirt.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,10 @@ static inline void arch_leave_lazy_mmu_mode(void)
PVOP_VCALL0(pv_mmu_ops.lazy_mode.leave);
}

void arch_flush_lazy_mmu_mode(void);
static inline void arch_flush_lazy_mmu_mode(void)
{
PVOP_VCALL0(pv_mmu_ops.lazy_mode.flush);
}

static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
phys_addr_t phys, pgprot_t flags)
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/paravirt_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ struct pv_lazy_ops {
/* Set deferred update mode, used for batching operations. */
void (*enter)(void);
void (*leave)(void);
void (*flush)(void);
};

struct pv_time_ops {
Expand Down Expand Up @@ -673,6 +674,7 @@ void paravirt_end_context_switch(struct task_struct *next);

void paravirt_enter_lazy_mmu(void);
void paravirt_leave_lazy_mmu(void);
void paravirt_flush_lazy_mmu(void);

void _paravirt_nop(void);
u32 _paravirt_ident_32(u32);
Expand Down
5 changes: 5 additions & 0 deletions arch/x86/include/asm/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
return (pmd_val(pmd) & PTE_PFN_MASK) >> PAGE_SHIFT;
}

static inline unsigned long pud_pfn(pud_t pud)
{
return (pud_val(pud) & PTE_PFN_MASK) >> PAGE_SHIFT;
}

#define pte_page(pte) pfn_to_page(pte_pfn(pte))

static inline int pmd_large(pmd_t pte)
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/include/asm/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ typedef unsigned long sigset_t;
extern void do_notify_resume(struct pt_regs *, void *, __u32);
# endif /* __KERNEL__ */

#define __ARCH_HAS_SA_RESTORER

#ifdef __i386__
# ifdef __KERNEL__
struct old_sigaction {
Expand Down
24 changes: 14 additions & 10 deletions arch/x86/kernel/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ static struct protection_domain *pt_domain;

static struct iommu_ops amd_iommu_ops;

static struct dma_map_ops amd_iommu_dma_ops;

/*
* general struct to manage commands send to an IOMMU
*/
Expand Down Expand Up @@ -1778,18 +1780,20 @@ static int device_change_notifier(struct notifier_block *nb,

domain = domain_for_device(dev);

/* allocate a protection domain if a device is added */
dma_domain = find_protection_domain(devid);
if (dma_domain)
goto out;
dma_domain = dma_ops_domain_alloc();
if (!dma_domain)
goto out;
dma_domain->target_dev = devid;
if (!dma_domain) {
/* allocate a protection domain if a device is added */
dma_domain = dma_ops_domain_alloc();
if (!dma_domain)
goto out;
dma_domain->target_dev = devid;

spin_lock_irqsave(&iommu_pd_list_lock, flags);
list_add_tail(&dma_domain->list, &iommu_pd_list);
spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
}

spin_lock_irqsave(&iommu_pd_list_lock, flags);
list_add_tail(&dma_domain->list, &iommu_pd_list);
spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
dev->archdata.dma_ops = &amd_iommu_dma_ops;

break;
case BUS_NOTIFY_DEL_DEVICE:
Expand Down
10 changes: 7 additions & 3 deletions arch/x86/kernel/amd_iommu_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,7 @@ static struct syscore_ops amd_iommu_syscore_ops = {
*/
static int __init amd_iommu_init(void)
{
struct amd_iommu *iommu;
int i, ret = 0;

/*
Expand Down Expand Up @@ -1411,9 +1412,6 @@ static int __init amd_iommu_init(void)
if (amd_iommu_pd_alloc_bitmap == NULL)
goto free;

/* init the device table */
init_device_table();

/*
* let all alias entries point to itself
*/
Expand Down Expand Up @@ -1463,6 +1461,12 @@ static int __init amd_iommu_init(void)
if (ret)
goto free_disable;

/* init the device table */
init_device_table();

for_each_iommu(iommu)
iommu_flush_all_caches(iommu);

amd_iommu_init_api();

amd_iommu_init_notifier();
Expand Down
17 changes: 12 additions & 5 deletions arch/x86/kernel/apic/x2apic_phys.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@ static int set_x2apic_phys_mode(char *arg)
}
early_param("x2apic_phys", set_x2apic_phys_mode);

static bool x2apic_fadt_phys(void)
{
if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
printk(KERN_DEBUG "System requires x2apic physical mode\n");
return true;
}
return false;
}

static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
if (x2apic_phys)
return x2apic_enabled();
else
return 0;
return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
}

static void
Expand Down Expand Up @@ -108,7 +115,7 @@ static void init_x2apic_ldr(void)

static int x2apic_phys_probe(void)
{
if (x2apic_mode && x2apic_phys)
if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys()))
return 1;

return apic == &apic_x2apic_phys;
Expand Down
10 changes: 10 additions & 0 deletions arch/x86/kernel/cpu/perf_event_intel_ds.c
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,16 @@ static void intel_ds_init(void)
}
}

void perf_restore_debug_store(void)
{
struct debug_store *ds = __this_cpu_read(cpu_hw_events.ds);

if (!x86_pmu.bts && !x86_pmu.pebs)
return;

wrmsrl(MSR_IA32_DS_AREA, (unsigned long)ds);
}

#else /* CONFIG_CPU_SUP_INTEL */

static void reserve_ds_buffers(void)
Expand Down
53 changes: 34 additions & 19 deletions arch/x86/kernel/head.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#include <asm/setup.h>
#include <asm/bios_ebda.h>

#define BIOS_LOWMEM_KILOBYTES 0x413

/*
* The BIOS places the EBDA/XBDA at the top of conventional
* memory, and usually decreases the reported amount of
Expand All @@ -16,17 +14,30 @@
* chipset: reserve a page before VGA to prevent PCI prefetch
* into it (errata #56). Usually the page is reserved anyways,
* unless you have no PS/2 mouse plugged in.
*
* This functions is deliberately very conservative. Losing
* memory in the bottom megabyte is rarely a problem, as long
* as we have enough memory to install the trampoline. Using
* memory that is in use by the BIOS or by some DMA device
* the BIOS didn't shut down *is* a big problem.
*/

#define BIOS_LOWMEM_KILOBYTES 0x413
#define LOWMEM_CAP 0x9f000U /* Absolute maximum */
#define INSANE_CUTOFF 0x20000U /* Less than this = insane */

void __init reserve_ebda_region(void)
{
unsigned int lowmem, ebda_addr;

/* To determine the position of the EBDA and the */
/* end of conventional memory, we need to look at */
/* the BIOS data area. In a paravirtual environment */
/* that area is absent. We'll just have to assume */
/* that the paravirt case can handle memory setup */
/* correctly, without our help. */
/*
* To determine the position of the EBDA and the
* end of conventional memory, we need to look at
* the BIOS data area. In a paravirtual environment
* that area is absent. We'll just have to assume
* that the paravirt case can handle memory setup
* correctly, without our help.
*/
if (paravirt_enabled())
return;

Expand All @@ -37,19 +48,23 @@ void __init reserve_ebda_region(void)
/* start of EBDA area */
ebda_addr = get_bios_ebda();

/* Fixup: bios puts an EBDA in the top 64K segment */
/* of conventional memory, but does not adjust lowmem. */
if ((lowmem - ebda_addr) <= 0x10000)
lowmem = ebda_addr;
/*
* Note: some old Dells seem to need 4k EBDA without
* reporting so, so just consider the memory above 0x9f000
* to be off limits (bugzilla 2990).
*/

/* If the EBDA address is below 128K, assume it is bogus */
if (ebda_addr < INSANE_CUTOFF)
ebda_addr = LOWMEM_CAP;

/* Fixup: bios does not report an EBDA at all. */
/* Some old Dells seem to need 4k anyhow (bugzilla 2990) */
if ((ebda_addr == 0) && (lowmem >= 0x9f000))
lowmem = 0x9f000;
/* If lowmem is less than 128K, assume it is bogus */
if (lowmem < INSANE_CUTOFF)
lowmem = LOWMEM_CAP;

/* Paranoia: should never happen, but... */
if ((lowmem == 0) || (lowmem >= 0x100000))
lowmem = 0x9f000;
/* Use the lower of the lowmem and EBDA markers as the cutoff */
lowmem = min(lowmem, ebda_addr);
lowmem = min(lowmem, LOWMEM_CAP); /* Absolute cap */

/* reserve all memory between lowmem and the 1MB mark */
memblock_x86_reserve_range(lowmem, 0x100000, "* BIOS reserved");
Expand Down
25 changes: 13 additions & 12 deletions arch/x86/kernel/paravirt.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,18 @@ void paravirt_leave_lazy_mmu(void)
leave_lazy(PARAVIRT_LAZY_MMU);
}

void paravirt_flush_lazy_mmu(void)
{
preempt_disable();

if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
arch_leave_lazy_mmu_mode();
arch_enter_lazy_mmu_mode();
}

preempt_enable();
}

void paravirt_start_context_switch(struct task_struct *prev)
{
BUG_ON(preemptible());
Expand Down Expand Up @@ -282,18 +294,6 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
return percpu_read(paravirt_lazy_mode);
}

void arch_flush_lazy_mmu_mode(void)
{
preempt_disable();

if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
arch_leave_lazy_mmu_mode();
arch_enter_lazy_mmu_mode();
}

preempt_enable();
}

struct pv_info pv_info = {
.name = "bare hardware",
.paravirt_enabled = 0,
Expand Down Expand Up @@ -462,6 +462,7 @@ struct pv_mmu_ops pv_mmu_ops = {
.lazy_mode = {
.enter = paravirt_nop,
.leave = paravirt_nop,
.flush = paravirt_nop,
},

.set_fixmap = native_set_fixmap,
Expand Down
10 changes: 7 additions & 3 deletions arch/x86/kvm/i8254.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,15 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
return HRTIMER_NORESTART;
}

static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period)
static void create_pit_timer(struct kvm *kvm, u32 val, int is_period)
{
struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
struct kvm_timer *pt = &ps->pit_timer;
s64 interval;

if (!irqchip_in_kernel(kvm))
return;

interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ);

pr_debug("create pit timer, interval is %llu nsec\n", interval);
Expand Down Expand Up @@ -394,13 +398,13 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val)
/* FIXME: enhance mode 4 precision */
case 4:
if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)) {
create_pit_timer(ps, val, 0);
create_pit_timer(kvm, val, 0);
}
break;
case 2:
case 3:
if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)){
create_pit_timer(ps, val, 1);
create_pit_timer(kvm, val, 1);
}
break;
default:
Expand Down
59 changes: 30 additions & 29 deletions arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,9 @@ static bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;

if (!cpu_has_xsave)
return 0;

best = kvm_find_cpuid_entry(vcpu, 1, 0);
return best && (best->ecx & bit(X86_FEATURE_XSAVE));
}
Expand Down Expand Up @@ -1070,7 +1073,6 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
{
unsigned long flags;
struct kvm_vcpu_arch *vcpu = &v->arch;
void *shared_kaddr;
unsigned long this_tsc_khz;
s64 kernel_ns, max_kernel_ns;
u64 tsc_timestamp;
Expand Down Expand Up @@ -1106,7 +1108,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)

local_irq_restore(flags);

if (!vcpu->time_page)
if (!vcpu->pv_time_enabled)
return 0;

/*
Expand Down Expand Up @@ -1164,14 +1166,9 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
*/
vcpu->hv_clock.version += 2;

shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0);

memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock,
sizeof(vcpu->hv_clock));

kunmap_atomic(shared_kaddr, KM_USER0);

mark_page_dirty(v->kvm, vcpu->time >> PAGE_SHIFT);
kvm_write_guest_cached(v->kvm, &vcpu->pv_time,
&vcpu->hv_clock,
sizeof(vcpu->hv_clock));
return 0;
}

Expand Down Expand Up @@ -1451,7 +1448,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
return 0;
}

if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa))
if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa,
sizeof(u32)))
return 1;

vcpu->arch.apf.send_user_only = !(data & KVM_ASYNC_PF_SEND_ALWAYS);
Expand All @@ -1461,10 +1459,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)

static void kvmclock_reset(struct kvm_vcpu *vcpu)
{
if (vcpu->arch.time_page) {
kvm_release_page_dirty(vcpu->arch.time_page);
vcpu->arch.time_page = NULL;
}
vcpu->arch.pv_time_enabled = false;
}

int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
Expand Down Expand Up @@ -1524,6 +1519,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
break;
case MSR_KVM_SYSTEM_TIME_NEW:
case MSR_KVM_SYSTEM_TIME: {
u64 gpa_offset;
kvmclock_reset(vcpu);

vcpu->arch.time = data;
Expand All @@ -1533,16 +1529,14 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
if (!(data & 1))
break;

/* ...but clean it before doing the actual write */
vcpu->arch.time_offset = data & ~(PAGE_MASK | 1);

vcpu->arch.time_page =
gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
gpa_offset = data & ~(PAGE_MASK | 1);

if (is_error_page(vcpu->arch.time_page)) {
kvm_release_page_clean(vcpu->arch.time_page);
vcpu->arch.time_page = NULL;
}
if (kvm_gfn_to_hva_cache_init(vcpu->kvm,
&vcpu->arch.pv_time, data & ~1ULL,
sizeof(struct pvclock_vcpu_time_info)))
vcpu->arch.pv_time_enabled = false;
else
vcpu->arch.pv_time_enabled = true;
break;
}
case MSR_KVM_ASYNC_PF_EN:
Expand Down Expand Up @@ -3410,6 +3404,9 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = -EEXIST;
if (kvm->arch.vpic)
goto create_irqchip_unlock;
r = -EINVAL;
if (atomic_read(&kvm->online_vcpus))
goto create_irqchip_unlock;
r = -ENOMEM;
vpic = kvm_create_pic(kvm);
if (vpic) {
Expand Down Expand Up @@ -5851,6 +5848,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
int pending_vec, max_bits, idx;
struct desc_ptr dt;

if (!guest_cpuid_has_xsave(vcpu) && (sregs->cr4 & X86_CR4_OSXSAVE))
return -EINVAL;

dt.size = sregs->idt.limit;
dt.address = sregs->idt.base;
kvm_x86_ops->set_idt(vcpu, &dt);
Expand Down Expand Up @@ -6116,12 +6116,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
if (r == 0)
r = kvm_mmu_setup(vcpu);
vcpu_put(vcpu);
if (r < 0)
goto free_vcpu;

return 0;
free_vcpu:
kvm_x86_ops->vcpu_free(vcpu);
return r;
}

Expand Down Expand Up @@ -6194,6 +6189,11 @@ void kvm_arch_check_processor_compat(void *rtn)
kvm_x86_ops->check_processor_compatibility(rtn);
}

bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
{
return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
}

int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
{
struct page *page;
Expand Down Expand Up @@ -6243,6 +6243,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
if (!zalloc_cpumask_var(&vcpu->arch.wbinvd_dirty_mask, GFP_KERNEL))
goto fail_free_mce_banks;

vcpu->arch.pv_time_enabled = false;
kvm_async_pf_hash_reset(vcpu);

return 0;
Expand Down
1 change: 1 addition & 0 deletions arch/x86/lguest/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,7 @@ __init void lguest_init(void)
pv_mmu_ops.read_cr3 = lguest_read_cr3;
pv_mmu_ops.lazy_mode.enter = paravirt_enter_lazy_mmu;
pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode;
pv_mmu_ops.lazy_mode.flush = paravirt_flush_lazy_mmu;
pv_mmu_ops.pte_update = lguest_pte_update;
pv_mmu_ops.pte_update_defer = lguest_pte_update;

Expand Down
4 changes: 2 additions & 2 deletions arch/x86/lib/usercopy_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,10 @@ copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest)
char c;
unsigned zero_len;

for (; len; --len) {
for (; len; --len, to++) {
if (__get_user_nocheck(c, from++, sizeof(char)))
break;
if (__put_user_nocheck(c, to++, sizeof(char)))
if (__put_user_nocheck(c, to, sizeof(char)))
break;
}

Expand Down
15 changes: 10 additions & 5 deletions arch/x86/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,12 @@ static noinline __kprobes int vmalloc_fault(unsigned long address)
if (pgd_none(*pgd_ref))
return -1;

if (pgd_none(*pgd))
if (pgd_none(*pgd)) {
set_pgd(pgd, *pgd_ref);
else
arch_flush_lazy_mmu_mode();
} else {
BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
}

/*
* Below here mismatches are bugs because these lower tables
Expand Down Expand Up @@ -720,12 +722,15 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
if (is_errata100(regs, address))
return;

if (unlikely(show_unhandled_signals))
/* Kernel addresses are always protection faults: */
if (address >= TASK_SIZE)
error_code |= PF_PROT;

if (likely(show_unhandled_signals))
show_signal_msg(regs, error_code, address, tsk);

/* Kernel addresses are always protection faults: */
tsk->thread.cr2 = address;
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 14;

force_sig_info_fault(SIGSEGV, si_code, address, tsk, 0);
Expand Down
3 changes: 3 additions & 0 deletions arch/x86/mm/init_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,9 @@ int kern_addr_valid(unsigned long addr)
if (pud_none(*pud))
return 0;

if (pud_large(*pud))
return pfn_valid(pud_pfn(*pud));

pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd))
return 0;
Expand Down
3 changes: 0 additions & 3 deletions arch/x86/mm/numa.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,6 @@ static void __init setup_node_data(int nid, u64 start, u64 end)
if (end && (end - start) < NODE_MIN_SIZE)
return;

/* initialize remap allocator before aligning to ZONE_ALIGN */
init_alloc_remap(nid, start, end);

start = roundup(start, ZONE_ALIGN);

printk(KERN_INFO "Initmem setup node %d %016Lx-%016Lx\n",
Expand Down
161 changes: 0 additions & 161 deletions arch/x86/mm/numa_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,167 +73,6 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,

extern unsigned long highend_pfn, highstart_pfn;

#define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)

static void *node_remap_start_vaddr[MAX_NUMNODES];
void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);

/*
* Remap memory allocator
*/
static unsigned long node_remap_start_pfn[MAX_NUMNODES];
static void *node_remap_end_vaddr[MAX_NUMNODES];
static void *node_remap_alloc_vaddr[MAX_NUMNODES];

/**
* alloc_remap - Allocate remapped memory
* @nid: NUMA node to allocate memory from
* @size: The size of allocation
*
* Allocate @size bytes from the remap area of NUMA node @nid. The
* size of the remap area is predetermined by init_alloc_remap() and
* only the callers considered there should call this function. For
* more info, please read the comment on top of init_alloc_remap().
*
* The caller must be ready to handle allocation failure from this
* function and fall back to regular memory allocator in such cases.
*
* CONTEXT:
* Single CPU early boot context.
*
* RETURNS:
* Pointer to the allocated memory on success, %NULL on failure.
*/
void *alloc_remap(int nid, unsigned long size)
{
void *allocation = node_remap_alloc_vaddr[nid];

size = ALIGN(size, L1_CACHE_BYTES);

if (!allocation || (allocation + size) > node_remap_end_vaddr[nid])
return NULL;

node_remap_alloc_vaddr[nid] += size;
memset(allocation, 0, size);

return allocation;
}

#ifdef CONFIG_HIBERNATION
/**
* resume_map_numa_kva - add KVA mapping to the temporary page tables created
* during resume from hibernation
* @pgd_base - temporary resume page directory
*/
void resume_map_numa_kva(pgd_t *pgd_base)
{
int node;

for_each_online_node(node) {
unsigned long start_va, start_pfn, nr_pages, pfn;

start_va = (unsigned long)node_remap_start_vaddr[node];
start_pfn = node_remap_start_pfn[node];
nr_pages = (node_remap_end_vaddr[node] -
node_remap_start_vaddr[node]) >> PAGE_SHIFT;

printk(KERN_DEBUG "%s: node %d\n", __func__, node);

for (pfn = 0; pfn < nr_pages; pfn += PTRS_PER_PTE) {
unsigned long vaddr = start_va + (pfn << PAGE_SHIFT);
pgd_t *pgd = pgd_base + pgd_index(vaddr);
pud_t *pud = pud_offset(pgd, vaddr);
pmd_t *pmd = pmd_offset(pud, vaddr);

set_pmd(pmd, pfn_pmd(start_pfn + pfn,
PAGE_KERNEL_LARGE_EXEC));

printk(KERN_DEBUG "%s: %08lx -> pfn %08lx\n",
__func__, vaddr, start_pfn + pfn);
}
}
}
#endif

/**
* init_alloc_remap - Initialize remap allocator for a NUMA node
* @nid: NUMA node to initizlie remap allocator for
*
* NUMA nodes may end up without any lowmem. As allocating pgdat and
* memmap on a different node with lowmem is inefficient, a special
* remap allocator is implemented which can be used by alloc_remap().
*
* For each node, the amount of memory which will be necessary for
* pgdat and memmap is calculated and two memory areas of the size are
* allocated - one in the node and the other in lowmem; then, the area
* in the node is remapped to the lowmem area.
*
* As pgdat and memmap must be allocated in lowmem anyway, this
* doesn't waste lowmem address space; however, the actual lowmem
* which gets remapped over is wasted. The amount shouldn't be
* problematic on machines this feature will be used.
*
* Initialization failure isn't fatal. alloc_remap() is used
* opportunistically and the callers will fall back to other memory
* allocation mechanisms on failure.
*/
void __init init_alloc_remap(int nid, u64 start, u64 end)
{
unsigned long start_pfn = start >> PAGE_SHIFT;
unsigned long end_pfn = end >> PAGE_SHIFT;
unsigned long size, pfn;
u64 node_pa, remap_pa;
void *remap_va;

/*
* The acpi/srat node info can show hot-add memroy zones where
* memory could be added but not currently present.
*/
printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
nid, start_pfn, end_pfn);

/* calculate the necessary space aligned to large page size */
size = node_memmap_size_bytes(nid, start_pfn, end_pfn);
size += ALIGN(sizeof(pg_data_t), PAGE_SIZE);
size = ALIGN(size, LARGE_PAGE_BYTES);

/* allocate node memory and the lowmem remap area */
node_pa = memblock_find_in_range(start, end, size, LARGE_PAGE_BYTES);
if (node_pa == MEMBLOCK_ERROR) {
pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n",
size, nid);
return;
}
memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM");

remap_pa = memblock_find_in_range(min_low_pfn << PAGE_SHIFT,
max_low_pfn << PAGE_SHIFT,
size, LARGE_PAGE_BYTES);
if (remap_pa == MEMBLOCK_ERROR) {
pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n",
size, nid);
memblock_x86_free_range(node_pa, node_pa + size);
return;
}
memblock_x86_reserve_range(remap_pa, remap_pa + size, "KVA PG");
remap_va = phys_to_virt(remap_pa);

/* perform actual remap */
for (pfn = 0; pfn < size >> PAGE_SHIFT; pfn += PTRS_PER_PTE)
set_pmd_pfn((unsigned long)remap_va + (pfn << PAGE_SHIFT),
(node_pa >> PAGE_SHIFT) + pfn,
PAGE_KERNEL_LARGE);

/* initialize remap allocator parameters */
node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT;
node_remap_start_vaddr[nid] = remap_va;
node_remap_end_vaddr[nid] = remap_va + size;
node_remap_alloc_vaddr[nid] = remap_va;

printk(KERN_DEBUG "remap_alloc: node %d [%08llx-%08llx) -> [%p-%p)\n",
nid, node_pa, node_pa + size, remap_va, remap_va + size);
}

void __init initmem_init(void)
{
x86_numa_init();
Expand Down
6 changes: 0 additions & 6 deletions arch/x86/mm/numa_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ void __init numa_reset_distance(void);

void __init x86_numa_init(void);

#ifdef CONFIG_X86_64
static inline void init_alloc_remap(int nid, u64 start, u64 end) { }
#else
void __init init_alloc_remap(int nid, u64 start, u64 end);
#endif

#ifdef CONFIG_NUMA_EMU
void __init numa_emulation(struct numa_meminfo *numa_meminfo,
int numa_dist_cnt);
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/power/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <linux/suspend.h>
#include <linux/smp.h>
#include <linux/perf_event.h>

#include <asm/pgtable.h>
#include <asm/proto.h>
Expand Down Expand Up @@ -224,6 +225,7 @@ static void __restore_processor_state(struct saved_context *ctxt)

do_fpu_end();
mtrr_bp_restore();
perf_restore_debug_store();
}

/* Needed by apm.c */
Expand Down
2 changes: 0 additions & 2 deletions arch/x86/power/hibernate_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ static int resume_physical_mapping_init(pgd_t *pgd_base)
}
}

resume_map_numa_kva(pgd_base);

return 0;
}

Expand Down
1 change: 1 addition & 0 deletions arch/x86/xen/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
.lazy_mode = {
.enter = paravirt_enter_lazy_mmu,
.leave = xen_leave_lazy_mmu,
.flush = paravirt_flush_lazy_mmu,
},

.set_fixmap = xen_set_fixmap,
Expand Down
1 change: 0 additions & 1 deletion arch/x86/xen/spinlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,6 @@ static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
if (per_cpu(lock_spinners, cpu) == xl) {
ADD_STATS(released_slow_kicked, 1);
xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
break;
}
}
}
Expand Down
14 changes: 7 additions & 7 deletions arch/x86/xen/xen-asm_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ ENTRY(xen_iret)
*/
#ifdef CONFIG_SMP
GET_THREAD_INFO(%eax)
movl TI_cpu(%eax), %eax
movl __per_cpu_offset(,%eax,4), %eax
mov xen_vcpu(%eax), %eax
movl %ss:TI_cpu(%eax), %eax
movl %ss:__per_cpu_offset(,%eax,4), %eax
mov %ss:xen_vcpu(%eax), %eax
#else
movl xen_vcpu, %eax
movl %ss:xen_vcpu, %eax
#endif

/* check IF state we're restoring */
Expand All @@ -105,19 +105,19 @@ ENTRY(xen_iret)
* resuming the code, so we don't have to be worried about
* being preempted to another CPU.
*/
setz XEN_vcpu_info_mask(%eax)
setz %ss:XEN_vcpu_info_mask(%eax)
xen_iret_start_crit:

/* check for unmasked and pending */
cmpw $0x0001, XEN_vcpu_info_pending(%eax)
cmpw $0x0001, %ss:XEN_vcpu_info_pending(%eax)

/*
* If there's something pending, mask events again so we can
* jump back into xen_hypervisor_callback. Otherwise do not
* touch XEN_vcpu_info_mask.
*/
jne 1f
movb $1, XEN_vcpu_info_mask(%eax)
movb $1, %ss:XEN_vcpu_info_mask(%eax)

1: popl %eax

Expand Down
1 change: 1 addition & 0 deletions arch/xtensa/include/asm/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ struct sigaction {
void (*sa_restorer)(void);
sigset_t sa_mask; /* mask last for extensibility */
};
#define __ARCH_HAS_SA_RESTORER

struct k_sigaction {
struct sigaction sa;
Expand Down
2 changes: 2 additions & 0 deletions block/blk-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ queue_store_##name(struct request_queue *q, const char *page, size_t count) \
unsigned long val; \
ssize_t ret; \
ret = queue_var_store(&val, page, count); \
if (ret < 0) \
return ret; \
if (neg) \
val = !val; \
\
Expand Down
2 changes: 2 additions & 0 deletions crypto/algif_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ static int hash_recvmsg(struct kiocb *unused, struct socket *sock,
else if (len < ds)
msg->msg_flags |= MSG_TRUNC;

msg->msg_namelen = 0;

lock_sock(sk);
if (ctx->more) {
ctx->more = 0;
Expand Down
1 change: 1 addition & 0 deletions crypto/algif_skcipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ static int skcipher_recvmsg(struct kiocb *unused, struct socket *sock,
long copied = 0;

lock_sock(sk);
msg->msg_namelen = 0;
for (iov = msg->msg_iov, iovlen = msg->msg_iovlen; iovlen > 0;
iovlen--, iov++) {
unsigned long seglen = iov->iov_len;
Expand Down
17 changes: 14 additions & 3 deletions crypto/gcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct crypto_rfc4543_ctx {

struct crypto_rfc4543_req_ctx {
u8 auth_tag[16];
u8 assocbuf[32];
struct scatterlist cipher[1];
struct scatterlist payload[2];
struct scatterlist assoc[2];
Expand Down Expand Up @@ -1142,9 +1143,19 @@ static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req,
scatterwalk_crypto_chain(payload, dst, vdst == req->iv + 8, 2);
assoclen += 8 + req->cryptlen - (enc ? 0 : authsize);

sg_init_table(assoc, 2);
sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
req->assoc->offset);
if (req->assoc->length == req->assoclen) {
sg_init_table(assoc, 2);
sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
req->assoc->offset);
} else {
BUG_ON(req->assoclen > sizeof(rctx->assocbuf));

scatterwalk_map_and_copy(rctx->assocbuf, req->assoc, 0,
req->assoclen, 0);

sg_init_table(assoc, 2);
sg_set_buf(assoc, rctx->assocbuf, req->assoclen);
}
scatterwalk_crypto_chain(assoc, payload, 0, 2);

aead_request_set_tfm(subreq, ctx->child);
Expand Down
4 changes: 4 additions & 0 deletions drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2412,6 +2412,9 @@ int ata_dev_configure(struct ata_device *dev)
dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
dev->max_sectors);

if (dev->horkage & ATA_HORKAGE_MAX_SEC_LBA48)
dev->max_sectors = ATA_MAX_SECTORS_LBA48;

if (ap->ops->dev_config)
ap->ops->dev_config(dev);

Expand Down Expand Up @@ -4077,6 +4080,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
{ "QUANTUM DAT DAT72-000", NULL, ATA_HORKAGE_ATAPI_MOD16_DMA },
{ "Slimtype DVD A DS8A8SH", NULL, ATA_HORKAGE_MAX_SEC_LBA48 },

/* Devices we expect to fail diagnostics */

Expand Down
146 changes: 73 additions & 73 deletions drivers/atm/iphase.h
Original file line number Diff line number Diff line change
Expand Up @@ -636,82 +636,82 @@ struct rx_buf_desc {
#define SEG_BASE IPHASE5575_FRAG_CONTROL_REG_BASE
#define REASS_BASE IPHASE5575_REASS_CONTROL_REG_BASE

typedef volatile u_int freg_t;
typedef volatile u_int ffreg_t;
typedef u_int rreg_t;

typedef struct _ffredn_t {
freg_t idlehead_high; /* Idle cell header (high) */
freg_t idlehead_low; /* Idle cell header (low) */
freg_t maxrate; /* Maximum rate */
freg_t stparms; /* Traffic Management Parameters */
freg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */
freg_t rm_type; /* */
u_int filler5[0x17 - 0x06];
freg_t cmd_reg; /* Command register */
u_int filler18[0x20 - 0x18];
freg_t cbr_base; /* CBR Pointer Base */
freg_t vbr_base; /* VBR Pointer Base */
freg_t abr_base; /* ABR Pointer Base */
freg_t ubr_base; /* UBR Pointer Base */
u_int filler24;
freg_t vbrwq_base; /* VBR Wait Queue Base */
freg_t abrwq_base; /* ABR Wait Queue Base */
freg_t ubrwq_base; /* UBR Wait Queue Base */
freg_t vct_base; /* Main VC Table Base */
freg_t vcte_base; /* Extended Main VC Table Base */
u_int filler2a[0x2C - 0x2A];
freg_t cbr_tab_beg; /* CBR Table Begin */
freg_t cbr_tab_end; /* CBR Table End */
freg_t cbr_pointer; /* CBR Pointer */
u_int filler2f[0x30 - 0x2F];
freg_t prq_st_adr; /* Packet Ready Queue Start Address */
freg_t prq_ed_adr; /* Packet Ready Queue End Address */
freg_t prq_rd_ptr; /* Packet Ready Queue read pointer */
freg_t prq_wr_ptr; /* Packet Ready Queue write pointer */
freg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/
freg_t tcq_ed_adr; /* Transmit Complete Queue End Address */
freg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */
freg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/
u_int filler38[0x40 - 0x38];
freg_t queue_base; /* Base address for PRQ and TCQ */
freg_t desc_base; /* Base address of descriptor table */
u_int filler42[0x45 - 0x42];
freg_t mode_reg_0; /* Mode register 0 */
freg_t mode_reg_1; /* Mode register 1 */
freg_t intr_status_reg;/* Interrupt Status register */
freg_t mask_reg; /* Mask Register */
freg_t cell_ctr_high1; /* Total cell transfer count (high) */
freg_t cell_ctr_lo1; /* Total cell transfer count (low) */
freg_t state_reg; /* Status register */
u_int filler4c[0x58 - 0x4c];
freg_t curr_desc_num; /* Contains the current descriptor num */
freg_t next_desc; /* Next descriptor */
freg_t next_vc; /* Next VC */
u_int filler5b[0x5d - 0x5b];
freg_t present_slot_cnt;/* Present slot count */
u_int filler5e[0x6a - 0x5e];
freg_t new_desc_num; /* New descriptor number */
freg_t new_vc; /* New VC */
freg_t sched_tbl_ptr; /* Schedule table pointer */
freg_t vbrwq_wptr; /* VBR wait queue write pointer */
freg_t vbrwq_rptr; /* VBR wait queue read pointer */
freg_t abrwq_wptr; /* ABR wait queue write pointer */
freg_t abrwq_rptr; /* ABR wait queue read pointer */
freg_t ubrwq_wptr; /* UBR wait queue write pointer */
freg_t ubrwq_rptr; /* UBR wait queue read pointer */
freg_t cbr_vc; /* CBR VC */
freg_t vbr_sb_vc; /* VBR SB VC */
freg_t abr_sb_vc; /* ABR SB VC */
freg_t ubr_sb_vc; /* UBR SB VC */
freg_t vbr_next_link; /* VBR next link */
freg_t abr_next_link; /* ABR next link */
freg_t ubr_next_link; /* UBR next link */
u_int filler7a[0x7c-0x7a];
freg_t out_rate_head; /* Out of rate head */
u_int filler7d[0xca-0x7d]; /* pad out to full address space */
freg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */
freg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */
u_int fillercc[0x100-0xcc]; /* pad out to full address space */
ffreg_t idlehead_high; /* Idle cell header (high) */
ffreg_t idlehead_low; /* Idle cell header (low) */
ffreg_t maxrate; /* Maximum rate */
ffreg_t stparms; /* Traffic Management Parameters */
ffreg_t abrubr_abr; /* ABRUBR Priority Byte 1, TCR Byte 0 */
ffreg_t rm_type; /* */
u_int filler5[0x17 - 0x06];
ffreg_t cmd_reg; /* Command register */
u_int filler18[0x20 - 0x18];
ffreg_t cbr_base; /* CBR Pointer Base */
ffreg_t vbr_base; /* VBR Pointer Base */
ffreg_t abr_base; /* ABR Pointer Base */
ffreg_t ubr_base; /* UBR Pointer Base */
u_int filler24;
ffreg_t vbrwq_base; /* VBR Wait Queue Base */
ffreg_t abrwq_base; /* ABR Wait Queue Base */
ffreg_t ubrwq_base; /* UBR Wait Queue Base */
ffreg_t vct_base; /* Main VC Table Base */
ffreg_t vcte_base; /* Extended Main VC Table Base */
u_int filler2a[0x2C - 0x2A];
ffreg_t cbr_tab_beg; /* CBR Table Begin */
ffreg_t cbr_tab_end; /* CBR Table End */
ffreg_t cbr_pointer; /* CBR Pointer */
u_int filler2f[0x30 - 0x2F];
ffreg_t prq_st_adr; /* Packet Ready Queue Start Address */
ffreg_t prq_ed_adr; /* Packet Ready Queue End Address */
ffreg_t prq_rd_ptr; /* Packet Ready Queue read pointer */
ffreg_t prq_wr_ptr; /* Packet Ready Queue write pointer */
ffreg_t tcq_st_adr; /* Transmit Complete Queue Start Address*/
ffreg_t tcq_ed_adr; /* Transmit Complete Queue End Address */
ffreg_t tcq_rd_ptr; /* Transmit Complete Queue read pointer */
ffreg_t tcq_wr_ptr; /* Transmit Complete Queue write pointer*/
u_int filler38[0x40 - 0x38];
ffreg_t queue_base; /* Base address for PRQ and TCQ */
ffreg_t desc_base; /* Base address of descriptor table */
u_int filler42[0x45 - 0x42];
ffreg_t mode_reg_0; /* Mode register 0 */
ffreg_t mode_reg_1; /* Mode register 1 */
ffreg_t intr_status_reg;/* Interrupt Status register */
ffreg_t mask_reg; /* Mask Register */
ffreg_t cell_ctr_high1; /* Total cell transfer count (high) */
ffreg_t cell_ctr_lo1; /* Total cell transfer count (low) */
ffreg_t state_reg; /* Status register */
u_int filler4c[0x58 - 0x4c];
ffreg_t curr_desc_num; /* Contains the current descriptor num */
ffreg_t next_desc; /* Next descriptor */
ffreg_t next_vc; /* Next VC */
u_int filler5b[0x5d - 0x5b];
ffreg_t present_slot_cnt;/* Present slot count */
u_int filler5e[0x6a - 0x5e];
ffreg_t new_desc_num; /* New descriptor number */
ffreg_t new_vc; /* New VC */
ffreg_t sched_tbl_ptr; /* Schedule table pointer */
ffreg_t vbrwq_wptr; /* VBR wait queue write pointer */
ffreg_t vbrwq_rptr; /* VBR wait queue read pointer */
ffreg_t abrwq_wptr; /* ABR wait queue write pointer */
ffreg_t abrwq_rptr; /* ABR wait queue read pointer */
ffreg_t ubrwq_wptr; /* UBR wait queue write pointer */
ffreg_t ubrwq_rptr; /* UBR wait queue read pointer */
ffreg_t cbr_vc; /* CBR VC */
ffreg_t vbr_sb_vc; /* VBR SB VC */
ffreg_t abr_sb_vc; /* ABR SB VC */
ffreg_t ubr_sb_vc; /* UBR SB VC */
ffreg_t vbr_next_link; /* VBR next link */
ffreg_t abr_next_link; /* ABR next link */
ffreg_t ubr_next_link; /* UBR next link */
u_int filler7a[0x7c-0x7a];
ffreg_t out_rate_head; /* Out of rate head */
u_int filler7d[0xca-0x7d]; /* pad out to full address space */
ffreg_t cell_ctr_high1_nc;/* Total cell transfer count (high) */
ffreg_t cell_ctr_lo1_nc;/* Total cell transfer count (low) */
u_int fillercc[0x100-0xcc]; /* pad out to full address space */
} ffredn_t;

typedef struct _rfredn_t {
Expand Down
4 changes: 2 additions & 2 deletions drivers/base/bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start,
struct device *dev;
int error = 0;

if (!bus)
if (!bus || !bus->p)
return -EINVAL;

klist_iter_init_node(&bus->p->klist_devices, &i,
Expand Down Expand Up @@ -323,7 +323,7 @@ struct device *bus_find_device(struct bus_type *bus,
struct klist_iter i;
struct device *dev;

if (!bus)
if (!bus || !bus->p)
return NULL;

klist_iter_init_node(&bus->p->klist_devices, &i,
Expand Down
3 changes: 2 additions & 1 deletion drivers/block/aoe/aoecmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ new_skb(ulong len)
{
struct sk_buff *skb;

skb = alloc_skb(len, GFP_ATOMIC);
skb = alloc_skb(len + MAX_HEADER, GFP_ATOMIC);
if (skb) {
skb_reserve(skb, MAX_HEADER);
skb_reset_mac_header(skb);
skb_reset_network_header(skb);
skb->protocol = __constant_htons(ETH_P_AOE);
Expand Down
11 changes: 8 additions & 3 deletions drivers/block/loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,11 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
wake_up_process(lo->lo_thread);
if (max_part > 0)
ioctl_by_bdev(bdev, BLKRRPART, 0);

/* Grab the block_device to prevent its destruction after we
* put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev).
*/
bdgrab(bdev);
return 0;

out_clr:
Expand Down Expand Up @@ -1024,8 +1029,10 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
if (bdev)
if (bdev) {
bdput(bdev);
invalidate_bdev(bdev);
}
set_capacity(lo->lo_disk, 0);
loop_sysfs_exit(lo);
if (bdev) {
Expand Down Expand Up @@ -1274,11 +1281,9 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
/* the width of sector_t may be narrow for bit-shift */
sz = sec;
sz <<= 9;
mutex_lock(&bdev->bd_mutex);
bd_set_size(bdev, sz);
/* let user-space know about the new size */
kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
mutex_unlock(&bdev->bd_mutex);

out:
return err;
Expand Down
2 changes: 1 addition & 1 deletion drivers/block/sunvdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
int op_len, err;
void *req_buf;

if (!(((u64)1 << ((u64)op - 1)) & port->operations))
if (!(((u64)1 << (u64)op) & port->operations))
return -EOPNOTSUPP;

switch (op) {
Expand Down
7 changes: 1 addition & 6 deletions drivers/block/xen-blkback/blkback.c
Original file line number Diff line number Diff line change
Expand Up @@ -650,13 +650,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
bio->bi_end_io = end_block_io_op;
}

/*
* We set it one so that the last submit_bio does not have to call
* atomic_inc.
*/
atomic_set(&pending_req->pendcnt, nbio);

/* Get a reference count for the disk queue and start sending I/O */
blk_start_plug(&plug);

for (i = 0; i < nbio; i++)
Expand Down Expand Up @@ -684,6 +678,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
fail_put_bio:
for (i = 0; i < nbio; i++)
bio_put(biolist[i]);
atomic_set(&pending_req->pendcnt, 1);
__end_block_io_op(pending_req, -EINVAL);
msleep(1); /* back off a bit */
return -EIO;
Expand Down
49 changes: 24 additions & 25 deletions drivers/block/xen-blkback/xenbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ static int xen_blkbk_remove(struct xenbus_device *dev)
be->blkif = NULL;
}

kfree(be->mode);
kfree(be);
dev_set_drvdata(&dev->dev, NULL);
return 0;
Expand Down Expand Up @@ -482,6 +483,7 @@ static void backend_changed(struct xenbus_watch *watch,
= container_of(watch, struct backend_info, backend_watch);
struct xenbus_device *dev = be->dev;
int cdrom = 0;
unsigned long handle;
char *device_type;

DPRINTK("");
Expand All @@ -501,10 +503,10 @@ static void backend_changed(struct xenbus_watch *watch,
return;
}

if ((be->major || be->minor) &&
((be->major != major) || (be->minor != minor))) {
pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n",
be->major, be->minor, major, minor);
if (be->major | be->minor) {
if (be->major != major || be->minor != minor)
pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n",
be->major, be->minor, major, minor);
return;
}

Expand All @@ -522,36 +524,33 @@ static void backend_changed(struct xenbus_watch *watch,
kfree(device_type);
}

if (be->major == 0 && be->minor == 0) {
/* Front end dir is a number, which is used as the handle. */

char *p = strrchr(dev->otherend, '/') + 1;
long handle;
err = strict_strtoul(p, 0, &handle);
if (err)
return;
/* Front end dir is a number, which is used as the handle. */
err = strict_strtoul(strrchr(dev->otherend, '/') + 1, 0, &handle);
if (err)
return;

be->major = major;
be->minor = minor;
be->major = major;
be->minor = minor;

err = xen_vbd_create(be->blkif, handle, major, minor,
(NULL == strchr(be->mode, 'w')), cdrom);
if (err) {
be->major = 0;
be->minor = 0;
xenbus_dev_fatal(dev, err, "creating vbd structure");
return;
}
err = xen_vbd_create(be->blkif, handle, major, minor,
!strchr(be->mode, 'w'), cdrom);

if (err)
xenbus_dev_fatal(dev, err, "creating vbd structure");
else {
err = xenvbd_sysfs_addif(dev);
if (err) {
xen_vbd_free(&be->blkif->vbd);
be->major = 0;
be->minor = 0;
xenbus_dev_fatal(dev, err, "creating sysfs entries");
return;
}
}

if (err) {
kfree(be->mode);
be->mode = NULL;
be->major = 0;
be->minor = 0;
} else {
/* We're potentially connected now */
xen_update_blkif_status(be->blkif);
}
Expand Down
4 changes: 4 additions & 0 deletions drivers/bluetooth/ath3k.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x03F0, 0x311D) },

/* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x0036) },
{ USB_DEVICE(0x0CF3, 0x3004) },
{ USB_DEVICE(0x0CF3, 0x311D) },
{ USB_DEVICE(0x0CF3, 0x817a) },
{ USB_DEVICE(0x13d3, 0x3375) },
{ USB_DEVICE(0x04CA, 0x3005) },

Expand All @@ -93,8 +95,10 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
static struct usb_device_id ath3k_blist_tbl[] = {

/* Atheros AR3012 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },

Expand Down
2 changes: 2 additions & 0 deletions drivers/bluetooth/btusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,10 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },

/* Atheros 3012 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },

Expand Down
14 changes: 1 addition & 13 deletions drivers/char/hpet.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,26 +374,14 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
struct hpet_dev *devp;
unsigned long addr;

if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
return -EINVAL;

devp = file->private_data;
addr = devp->hd_hpets->hp_hpet_phys;

if (addr & (PAGE_SIZE - 1))
return -ENOSYS;

vma->vm_flags |= VM_IO;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);

if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
__func__);
return -EAGAIN;
}

return 0;
return vm_iomap_memory(vma, addr, PAGE_SIZE);
#else
return -ENOSYS;
#endif
Expand Down
19 changes: 16 additions & 3 deletions drivers/char/hw_random/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <asm/uaccess.h>


Expand All @@ -52,8 +53,12 @@ static struct hwrng *current_rng;
static LIST_HEAD(rng_list);
static DEFINE_MUTEX(rng_mutex);
static int data_avail;
static u8 rng_buffer[SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES]
__cacheline_aligned;
static u8 *rng_buffer;

static size_t rng_buffer_size(void)
{
return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES;
}

static inline int hwrng_init(struct hwrng *rng)
{
Expand Down Expand Up @@ -116,7 +121,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,

if (!data_avail) {
bytes_read = rng_get_data(current_rng, rng_buffer,
sizeof(rng_buffer),
rng_buffer_size(),
!(filp->f_flags & O_NONBLOCK));
if (bytes_read < 0) {
err = bytes_read;
Expand Down Expand Up @@ -307,6 +312,14 @@ int hwrng_register(struct hwrng *rng)

mutex_lock(&rng_mutex);

/* kmalloc makes this safe for virt_to_page() in virtio_rng.c */
err = -ENOMEM;
if (!rng_buffer) {
rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL);
if (!rng_buffer)
goto out_unlock;
}

/* Must not register two RNGs with the same name. */
err = -EEXIST;
list_for_each_entry(tmp, &rng_list, list) {
Expand Down
13 changes: 11 additions & 2 deletions drivers/char/hw_random/virtio-rng.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,22 @@ static int virtrng_probe(struct virtio_device *vdev)
{
int err;

if (vq) {
/* We only support one device for now */
return -EBUSY;
}
/* We expect a single virtqueue. */
vq = virtio_find_single_vq(vdev, random_recv_done, "input");
if (IS_ERR(vq))
return PTR_ERR(vq);
if (IS_ERR(vq)) {
err = PTR_ERR(vq);
vq = NULL;
return err;
}

err = hwrng_register(&virtio_hwrng);
if (err) {
vdev->config->del_vqs(vdev);
vq = NULL;
return err;
}

Expand All @@ -107,6 +115,7 @@ static void __devexit virtrng_remove(struct virtio_device *vdev)
vdev->config->reset(vdev);
hwrng_unregister(&virtio_hwrng);
vdev->config->del_vqs(vdev);
vq = NULL;
}

static struct virtio_device_id id_table[] = {
Expand Down
3 changes: 2 additions & 1 deletion drivers/char/virtio_console.c
Original file line number Diff line number Diff line change
Expand Up @@ -1750,7 +1750,8 @@ static void virtcons_remove(struct virtio_device *vdev)
/* Disable interrupts for vqs */
vdev->config->reset(vdev);
/* Finish up work that's lined up */
cancel_work_sync(&portdev->control_work);
if (use_multiport(portdev))
cancel_work_sync(&portdev->control_work);

list_for_each_entry_safe(port, port2, &portdev->ports, list)
unplug_port(port);
Expand Down
1 change: 1 addition & 0 deletions drivers/cpufreq/cpufreq_stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
cpufreq_update_policy(cpu);
break;
case CPU_DOWN_PREPARE:
case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD:
Expand Down
5 changes: 5 additions & 0 deletions drivers/dca/dca-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,11 @@ void unregister_dca_provider(struct dca_provider *dca, struct device *dev)

spin_lock_irqsave(&dca_lock, flags);

if (list_empty(&dca_domains)) {
spin_unlock_irqrestore(&dca_lock, flags);
return;
}

list_del(&dca->node);

pci_rc = dca_pci_rc_from_dev(dev);
Expand Down
4 changes: 4 additions & 0 deletions drivers/firewire/core-device.c
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,10 @@ static void fw_device_init(struct work_struct *work)
ret = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
idr_get_new(&fw_device_idr, device, &minor) :
-ENOMEM;
if (minor >= 1 << MINORBITS) {
idr_remove(&fw_device_idr, minor);
minor = -ENOSPC;
}
up_write(&fw_device_rwsem);

if (ret < 0)
Expand Down
5 changes: 2 additions & 3 deletions drivers/firmware/dmi_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,6 @@ static int __init dmi_present(const char __iomem *p)
static int __init smbios_present(const char __iomem *p)
{
u8 buf[32];
int offset = 0;

memcpy_fromio(buf, p, 32);
if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) {
Expand All @@ -461,9 +460,9 @@ static int __init smbios_present(const char __iomem *p)
dmi_ver = 0x0206;
break;
}
offset = 16;
return memcmp(p + 16, "_DMI_", 5) || dmi_present(p + 16);
}
return dmi_present(buf + offset);
return 1;
}

void __init dmi_scan_machine(void)
Expand Down
92 changes: 89 additions & 3 deletions drivers/firmware/efivars.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ struct efivar_attribute {
ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count);
};

static struct efivars __efivars;
static struct efivar_operations ops;

#define EFIVAR_ATTR(_name, _mode, _show, _store) \
struct efivar_attribute efivar_attr_##_name = { \
Expand Down Expand Up @@ -730,6 +732,53 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
return count;
}

static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
{
struct efivar_entry *entry, *n;
struct efivars *efivars = &__efivars;
unsigned long strsize1, strsize2;
bool found = false;

strsize1 = utf16_strsize(variable_name, 1024);
list_for_each_entry_safe(entry, n, &efivars->list, list) {
strsize2 = utf16_strsize(entry->var.VariableName, 1024);
if (strsize1 == strsize2 &&
!memcmp(variable_name, &(entry->var.VariableName),
strsize2) &&
!efi_guidcmp(entry->var.VendorGuid,
*vendor)) {
found = true;
break;
}
}
return found;
}

/*
* Returns the size of variable_name, in bytes, including the
* terminating NULL character, or variable_name_size if no NULL
* character is found among the first variable_name_size bytes.
*/
static unsigned long var_name_strnsize(efi_char16_t *variable_name,
unsigned long variable_name_size)
{
unsigned long len;
efi_char16_t c;

/*
* The variable name is, by definition, a NULL-terminated
* string, so make absolutely sure that variable_name_size is
* the value we expect it to be. If not, return the real size.
*/
for (len = 2; len <= variable_name_size; len += sizeof(c)) {
c = variable_name[(len / sizeof(c)) - 1];
if (!c)
break;
}

return min(len, variable_name_size);
}

/*
* Let's not leave out systab information that snuck into
* the efivars driver
Expand Down Expand Up @@ -917,6 +966,28 @@ void unregister_efivars(struct efivars *efivars)
}
EXPORT_SYMBOL_GPL(unregister_efivars);

/*
* Print a warning when duplicate EFI variables are encountered and
* disable the sysfs workqueue since the firmware is buggy.
*/
static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
unsigned long len16)
{
size_t i, len8 = len16 / sizeof(efi_char16_t);
char *s8;

s8 = kzalloc(len8, GFP_KERNEL);
if (!s8)
return;

for (i = 0; i < len8; i++)
s8[i] = s16[i];

printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
s8, vendor_guid);
kfree(s8);
}

int register_efivars(struct efivars *efivars,
const struct efivar_operations *ops,
struct kobject *parent_kobj)
Expand Down Expand Up @@ -957,6 +1028,24 @@ int register_efivars(struct efivars *efivars,
&vendor_guid);
switch (status) {
case EFI_SUCCESS:
variable_name_size = var_name_strnsize(variable_name,
variable_name_size);

/*
* Some firmware implementations return the
* same variable name on multiple calls to
* get_next_variable(). Terminate the loop
* immediately as there is no guarantee that
* we'll ever see a different variable name,
* and may end up looping here forever.
*/
if (variable_is_present(variable_name, &vendor_guid)) {
dup_variable_bug(variable_name, &vendor_guid,
variable_name_size);
status = EFI_NOT_FOUND;
break;
}

efivar_create_sysfs_entry(efivars,
variable_name_size,
variable_name,
Expand All @@ -983,9 +1072,6 @@ int register_efivars(struct efivars *efivars,
}
EXPORT_SYMBOL_GPL(register_efivars);

static struct efivars __efivars;
static struct efivar_operations ops;

/*
* For now we register the efi subsystem with the firmware subsystem
* and the vars subsystem with the efi subsystem. In the future, it
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_edid.c
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo;
unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo;
unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo;
unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;
unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 2 | pt->vsync_offset_pulse_width_lo >> 4;
unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf);

/* ignore tiny modes */
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ int drm_get_usb_dev(struct usb_interface *interface,

usbdev = interface_to_usbdev(interface);
dev->usbdev = usbdev;
dev->dev = &usbdev->dev;
dev->dev = &interface->dev;

mutex_lock(&drm_global_mutex);

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/i915_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static const char *cache_level_str(int type)
static void
describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
{
seq_printf(m, "%p: %s%s %8zd %04x %04x %d %d%s%s%s",
seq_printf(m, "%pK: %s%s %8zd %04x %04x %d %d%s%s%s",
&obj->base,
get_pin_flag(obj),
get_tiling_flag(obj),
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,11 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
case 0:
case -ERESTARTSYS:
case -EINTR:
case -EBUSY:
/*
* EBUSY is ok: this just means that another thread
* already did the job.
*/
return VM_FAULT_NOPAGE;
case -ENOMEM:
return VM_FAULT_OOM;
Expand Down
11 changes: 8 additions & 3 deletions drivers/gpu/drm/i915/i915_gem_execbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,15 +888,20 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
int count)
{
int i;
int relocs_total = 0;
int relocs_max = INT_MAX / sizeof(struct drm_i915_gem_relocation_entry);

for (i = 0; i < count; i++) {
char __user *ptr = (char __user *)(uintptr_t)exec[i].relocs_ptr;
int length; /* limited by fault_in_pages_readable() */

/* First check for malicious input causing overflow */
if (exec[i].relocation_count >
INT_MAX / sizeof(struct drm_i915_gem_relocation_entry))
/* First check for malicious input causing overflow in
* the worst case where we need to allocate the entire
* relocation tree as a single array.
*/
if (exec[i].relocation_count > relocs_max - relocs_total)
return -EINVAL;
relocs_total += exec[i].relocation_count;

length = exec[i].relocation_count *
sizeof(struct drm_i915_gem_relocation_entry);
Expand Down
31 changes: 19 additions & 12 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -2898,6 +2898,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
u32 pctl;

if (!intel_crtc->active)
return;
Expand All @@ -2914,6 +2915,13 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)

intel_disable_plane(dev_priv, plane, pipe);
intel_disable_pipe(dev_priv, pipe);

/* Disable pannel fitter if it is on this pipe. */
pctl = I915_READ(PFIT_CONTROL);
if ((pctl & PFIT_ENABLE) &&
((pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT) == pipe)
I915_WRITE(PFIT_CONTROL, 0);

intel_disable_pll(dev_priv, pipe);

intel_crtc->active = false;
Expand Down Expand Up @@ -6499,8 +6507,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_framebuffer *intel_fb;
struct drm_i915_gem_object *obj;
struct drm_framebuffer *old_fb = crtc->fb;
struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work;
unsigned long flags;
Expand All @@ -6512,25 +6520,26 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,

work->event = event;
work->dev = crtc->dev;
intel_fb = to_intel_framebuffer(crtc->fb);
work->old_fb_obj = intel_fb->obj;
work->old_fb_obj = to_intel_framebuffer(old_fb)->obj;
INIT_WORK(&work->work, intel_unpin_work_fn);

ret = drm_vblank_get(dev, intel_crtc->pipe);
if (ret)
goto free_work;

/* We borrow the event spin lock for protecting unpin_work */
spin_lock_irqsave(&dev->event_lock, flags);
if (intel_crtc->unpin_work) {
spin_unlock_irqrestore(&dev->event_lock, flags);
kfree(work);
drm_vblank_put(dev, intel_crtc->pipe);

DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
return -EBUSY;
}
intel_crtc->unpin_work = work;
spin_unlock_irqrestore(&dev->event_lock, flags);

intel_fb = to_intel_framebuffer(fb);
obj = intel_fb->obj;

mutex_lock(&dev->struct_mutex);

/* Reference the objects for the scheduled work. */
Expand All @@ -6539,10 +6548,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,

crtc->fb = fb;

ret = drm_vblank_get(dev, intel_crtc->pipe);
if (ret)
goto cleanup_objs;

work->pending_flip_obj = obj;

work->enable_stall_check = true;
Expand All @@ -6564,7 +6569,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,

cleanup_pending:
atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
cleanup_objs:
crtc->fb = old_fb;
drm_gem_object_unreference(&work->old_fb_obj->base);
drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
Expand All @@ -6573,6 +6578,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
intel_crtc->unpin_work = NULL;
spin_unlock_irqrestore(&dev->event_lock, flags);

drm_vblank_put(dev, intel_crtc->pipe);
free_work:
kfree(work);

return ret;
Expand Down
23 changes: 22 additions & 1 deletion drivers/gpu/drm/i915/intel_opregion.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,25 @@ static void intel_didl_outputs(struct drm_device *dev)
goto end;
}

static void intel_setup_cadls(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
int i = 0;
u32 disp_id;

/* Initialize the CADL field by duplicating the DIDL values.
* Technically, this is not always correct as display outputs may exist,
* but not active. This initialization is necessary for some Clevo
* laptops that check this field before processing the brightness and
* display switching hotkeys. Just like DIDL, CADL is NULL-terminated if
* there are less than eight devices. */
do {
disp_id = ioread32(&opregion->acpi->didl[i]);
iowrite32(disp_id, &opregion->acpi->cadl[i]);
} while (++i < 8 && disp_id != 0);
}

void intel_opregion_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
Expand All @@ -422,8 +441,10 @@ void intel_opregion_init(struct drm_device *dev)
return;

if (opregion->acpi) {
if (drm_core_check_feature(dev, DRIVER_MODESET))
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_didl_outputs(dev);
intel_setup_cadls(dev);
}

/* Notify BIOS we are ready to handle ACPI video ext notifs.
* Right now, all the events are handled by the ACPI video module.
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/radeon/evergreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
WREG32(EVERGREEN_D5VGA_CONTROL, 0);
WREG32(EVERGREEN_D6VGA_CONTROL, 0);
}
/* wait for the MC to settle */
udelay(100);
}

void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save)
Expand Down
17 changes: 17 additions & 0 deletions drivers/gpu/drm/radeon/radeon_combios.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,15 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
found = 1;
}

/* quirks */
/* Radeon 9100 (R200) */
if ((dev->pdev->device == 0x514D) &&
(dev->pdev->subsystem_vendor == 0x174B) &&
(dev->pdev->subsystem_device == 0x7149)) {
/* vbios value is bad, use the default */
found = 0;
}

if (!found) /* fallback to defaults */
radeon_legacy_get_primary_dac_info_from_table(rdev, p_dac);

Expand Down Expand Up @@ -2338,6 +2347,14 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
1),
ATOM_DEVICE_CRT1_SUPPORT);
}
/* RV100 board with external TDMS bit mis-set.
* Actually uses internal TMDS, clear the bit.
*/
if (dev->pdev->device == 0x5159 &&
dev->pdev->subsystem_vendor == 0x1014 &&
dev->pdev->subsystem_device == 0x029A) {
tmp &= ~(1 << 4);
}
if ((tmp >> 4) & 0x1) {
devices |= ATOM_DEVICE_DFP2_SUPPORT;
radeon_add_legacy_encoder(dev,
Expand Down
4 changes: 3 additions & 1 deletion drivers/gpu/drm/radeon/radeon_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,8 +1158,10 @@ radeon_user_framebuffer_create(struct drm_device *dev,
}

radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
if (radeon_fb == NULL)
if (radeon_fb == NULL) {
drm_gem_object_unreference_unlocked(obj);
return ERR_PTR(-ENOMEM);
}

radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);

Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/vga/vga_switcheroo.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/fb.h>

#include <linux/pci.h>
#include <linux/console.h>
#include <linux/vga_switcheroo.h>

struct vga_switcheroo_client {
Expand Down Expand Up @@ -256,8 +257,10 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)

if (new_client->fb_info) {
struct fb_event event;
console_lock();
event.info = new_client->fb_info;
fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
console_unlock();
}

ret = vgasr_priv.handler->switchto(new_client->id);
Expand Down
2 changes: 2 additions & 0 deletions drivers/hwmon/lineage-pem.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ static struct attribute *pem_input_attributes[] = {
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
NULL
};

static const struct attribute_group pem_input_group = {
Expand All @@ -431,6 +432,7 @@ static struct attribute *pem_fan_attributes[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
NULL
};

static const struct attribute_group pem_fan_group = {
Expand Down
8 changes: 7 additions & 1 deletion drivers/hwmon/sht15.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,13 @@ static int __devinit sht15_probe(struct platform_device *pdev)
if (voltage)
data->supply_uV = voltage;

regulator_enable(data->reg);
ret = regulator_enable(data->reg);
if (ret != 0) {
dev_err(&pdev->dev,
"failed to enable regulator: %d\n", ret);
goto err_free_data;
}

/*
* Setup a notifier block to update this if another device
* causes the voltage to change
Expand Down
8 changes: 6 additions & 2 deletions drivers/infiniband/ulp/ipoib/ipoib_cm.c
Original file line number Diff line number Diff line change
Expand Up @@ -753,9 +753,13 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
if (++priv->tx_outstanding == ipoib_sendq_size) {
ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
tx->qp->qp_num);
if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP))
ipoib_warn(priv, "request notify on send CQ failed\n");
netif_stop_queue(dev);
rc = ib_req_notify_cq(priv->send_cq,
IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
if (rc < 0)
ipoib_warn(priv, "request notify on send CQ failed\n");
else if (rc)
ipoib_send_comp_handler(priv->send_cq, dev);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/isdn/gigaset/capi.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag,
CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l,
CAPIMSG_CONTROL(data));
l -= 12;
if (l <= 0)
return;
dbgline = kmalloc(3*l, GFP_ATOMIC);
if (!dbgline)
return;
Expand Down
4 changes: 4 additions & 0 deletions drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ static int md_make_request(struct request_queue *q, struct bio *bio)
bio_io_error(bio);
return 0;
}
if (mddev->ro == 1 && unlikely(rw == WRITE)) {
bio_endio(bio, bio_sectors(bio) == 0 ? 0 : -EROFS);
return 0;
}
smp_rmb(); /* Ensure implications of 'active' are visible */
rcu_read_lock();
if (mddev->suspended) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/raid0.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf)
kfree(conf->strip_zone);
kfree(conf->devlist);
kfree(conf);
*private_conf = NULL;
*private_conf = ERR_PTR(err);
return err;
}

Expand Down
4 changes: 3 additions & 1 deletion drivers/media/rc/rc-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -775,8 +775,10 @@ static ssize_t show_protocols(struct device *device,
} else if (dev->raw) {
enabled = dev->raw->enabled_protocols;
allowed = ir_raw_get_allowed_protocols();
} else
} else {
mutex_unlock(&dev->lock);
return -ENODEV;
}

IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
(long long)allowed,
Expand Down
56 changes: 34 additions & 22 deletions drivers/mtd/mtdchar.c
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,33 @@ static unsigned long mtd_get_unmapped_area(struct file *file,
}
#endif

static inline unsigned long get_vm_size(struct vm_area_struct *vma)
{
return vma->vm_end - vma->vm_start;
}

static inline resource_size_t get_vm_offset(struct vm_area_struct *vma)
{
return (resource_size_t) vma->vm_pgoff << PAGE_SHIFT;
}

/*
* Set a new vm offset.
*
* Verify that the incoming offset really works as a page offset,
* and that the offset and size fit in a resource_size_t.
*/
static inline int set_vm_offset(struct vm_area_struct *vma, resource_size_t off)
{
pgoff_t pgoff = off >> PAGE_SHIFT;
if (off != (resource_size_t) pgoff << PAGE_SHIFT)
return -EINVAL;
if (off + get_vm_size(vma) - 1 < off)
return -EINVAL;
vma->vm_pgoff = pgoff;
return 0;
}

/*
* set up a mapping for shared memory segments
*/
Expand All @@ -1073,32 +1100,17 @@ static int mtd_mmap(struct file *file, struct vm_area_struct *vma)
struct mtd_file_info *mfi = file->private_data;
struct mtd_info *mtd = mfi->mtd;
struct map_info *map = mtd->priv;
unsigned long start;
unsigned long off;
u32 len;

if (mtd->type == MTD_RAM || mtd->type == MTD_ROM) {
off = vma->vm_pgoff << PAGE_SHIFT;
start = map->phys;
len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;

off += start;
vma->vm_pgoff = off >> PAGE_SHIFT;
vma->vm_flags |= VM_IO | VM_RESERVED;

/* This is broken because it assumes the MTD device is map-based
and that mtd->priv is a valid struct map_info. It should be
replaced with something that uses the mtd_get_unmapped_area()
operation properly. */
if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) {
#ifdef pgprot_noncached
if (file->f_flags & O_DSYNC || off >= __pa(high_memory))
if (file->f_flags & O_DSYNC || map->phys >= __pa(high_memory))
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
#endif
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;

return 0;
return vm_iomap_memory(vma, map->phys, map->size);
}
return -ENOSYS;
#else
Expand Down
3 changes: 1 addition & 2 deletions drivers/net/atl1e/atl1e.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ struct atl1e_tpd_desc {
/* how about 0x2000 */
#define MAX_TX_BUF_LEN 0x2000
#define MAX_TX_BUF_SHIFT 13
/*#define MAX_TX_BUF_LEN 0x3000 */
#define MAX_TSO_SEG_SIZE 0x3c00

/* rrs word 1 bit 0:31 */
#define RRS_RX_CSUM_MASK 0xFFFF
Expand Down Expand Up @@ -439,7 +439,6 @@ struct atl1e_adapter {
struct atl1e_hw hw;
struct atl1e_hw_stats hw_stats;

bool have_msi;
u32 wol;
u16 link_speed;
u16 link_duplex;
Expand Down
23 changes: 3 additions & 20 deletions drivers/net/atl1e/atl1e_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1848,37 +1848,19 @@ static void atl1e_free_irq(struct atl1e_adapter *adapter)
struct net_device *netdev = adapter->netdev;

free_irq(adapter->pdev->irq, netdev);

if (adapter->have_msi)
pci_disable_msi(adapter->pdev);
}

static int atl1e_request_irq(struct atl1e_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
int flags = 0;
int err = 0;

adapter->have_msi = true;
err = pci_enable_msi(adapter->pdev);
if (err) {
netdev_dbg(adapter->netdev,
"Unable to allocate MSI interrupt Error: %d\n", err);
adapter->have_msi = false;
} else
netdev->irq = pdev->irq;


if (!adapter->have_msi)
flags |= IRQF_SHARED;
err = request_irq(adapter->pdev->irq, atl1e_intr, flags,
netdev->name, netdev);
err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED,
netdev->name, netdev);
if (err) {
netdev_dbg(adapter->netdev,
"Unable to allocate interrupt Error: %d\n", err);
if (adapter->have_msi)
pci_disable_msi(adapter->pdev);
return err;
}
netdev_dbg(adapter->netdev, "atl1e_request_irq OK\n");
Expand Down Expand Up @@ -2351,6 +2333,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,

INIT_WORK(&adapter->reset_task, atl1e_reset_task);
INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task);
netif_set_gso_max_size(netdev, MAX_TSO_SEG_SIZE);
err = register_netdev(netdev);
if (err) {
netdev_err(netdev, "register netdevice failed\n");
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1949,6 +1949,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
write_unlock_bh(&bond->lock);

err_close:
slave_dev->priv_flags &= ~IFF_BONDING;
dev_close(slave_dev);

err_unset_master:
Expand Down Expand Up @@ -2017,12 +2018,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
return -EINVAL;
}

write_unlock_bh(&bond->lock);
/* unregister rx_handler early so bond_handle_frame wouldn't be called
* for this slave anymore.
*/
netdev_rx_handler_unregister(slave_dev);
write_unlock_bh(&bond->lock);
synchronize_net();
write_lock_bh(&bond->lock);

if (!bond->params.fail_over_mac) {
Expand Down
31 changes: 15 additions & 16 deletions drivers/net/can/sja1000/sja1000_of_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ static int __devinit sja1000_ofp_probe(struct platform_device *ofdev)
struct net_device *dev;
struct sja1000_priv *priv;
struct resource res;
const u32 *prop;
int err, irq, res_size, prop_size;
u32 prop;
int err, irq, res_size;
void __iomem *base;

err = of_address_to_resource(np, 0, &res);
Expand Down Expand Up @@ -135,27 +135,27 @@ static int __devinit sja1000_ofp_probe(struct platform_device *ofdev)
priv->read_reg = sja1000_ofp_read_reg;
priv->write_reg = sja1000_ofp_write_reg;

prop = of_get_property(np, "nxp,external-clock-frequency", &prop_size);
if (prop && (prop_size == sizeof(u32)))
priv->can.clock.freq = *prop / 2;
err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop);
if (!err)
priv->can.clock.freq = prop / 2;
else
priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */

prop = of_get_property(np, "nxp,tx-output-mode", &prop_size);
if (prop && (prop_size == sizeof(u32)))
priv->ocr |= *prop & OCR_MODE_MASK;
err = of_property_read_u32(np, "nxp,tx-output-mode", &prop);
if (!err)
priv->ocr |= prop & OCR_MODE_MASK;
else
priv->ocr |= OCR_MODE_NORMAL; /* default */

prop = of_get_property(np, "nxp,tx-output-config", &prop_size);
if (prop && (prop_size == sizeof(u32)))
priv->ocr |= (*prop << OCR_TX_SHIFT) & OCR_TX_MASK;
err = of_property_read_u32(np, "nxp,tx-output-config", &prop);
if (!err)
priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
else
priv->ocr |= OCR_TX0_PULLDOWN; /* default */

prop = of_get_property(np, "nxp,clock-out-frequency", &prop_size);
if (prop && (prop_size == sizeof(u32)) && *prop) {
u32 divider = priv->can.clock.freq * 2 / *prop;
err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop);
if (!err && prop) {
u32 divider = priv->can.clock.freq * 2 / prop;

if (divider > 1)
priv->cdr |= divider / 2 - 1;
Expand All @@ -165,8 +165,7 @@ static int __devinit sja1000_ofp_probe(struct platform_device *ofdev)
priv->cdr |= CDR_CLK_OFF; /* default */
}

prop = of_get_property(np, "nxp,no-comparator-bypass", NULL);
if (!prop)
if (!of_property_read_bool(np, "nxp,no-comparator-bypass"))
priv->cdr |= CDR_CBP; /* default */

priv->irq_flags = IRQF_SHARED;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/davinci_emac.c
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 +1049,7 @@ static void emac_tx_handler(void *token, int len, int status)
struct net_device *ndev = skb->dev;

if (unlikely(netif_queue_stopped(ndev)))
netif_start_queue(ndev);
netif_wake_queue(ndev);
ndev->stats.tx_packets++;
ndev->stats.tx_bytes += len;
dev_kfree_skb_any(skb);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/e1000e/netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -5330,7 +5330,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,
*/
e1000e_release_hw_control(adapter);

pci_disable_device(pdev);
pci_clear_master(pdev);

return 0;
}
Expand Down
8 changes: 5 additions & 3 deletions drivers/net/igb/igb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4521,11 +4521,13 @@ void igb_update_stats(struct igb_adapter *adapter,
bytes = 0;
packets = 0;
for (i = 0; i < adapter->num_rx_queues; i++) {
u32 rqdpc_tmp = rd32(E1000_RQDPC(i)) & 0x0FFF;
u32 rqdpc = rd32(E1000_RQDPC(i));
struct igb_ring *ring = adapter->rx_ring[i];

ring->rx_stats.drops += rqdpc_tmp;
net_stats->rx_fifo_errors += rqdpc_tmp;
if (rqdpc) {
ring->rx_stats.drops += rqdpc;
net_stats->rx_fifo_errors += rqdpc;
}

do {
start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ks8851.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)
for (; rxfc != 0; rxfc--) {
rxh = ks8851_rdreg32(ks, KS_RXFHSR);
rxstat = rxh & 0xffff;
rxlen = rxh >> 16;
rxlen = (rxh >> 16) & 0xfff;

netif_dbg(ks, rx_status, ks->netdev,
"rx: stat 0x%04x, len 0x%04x\n", rxstat, rxlen);
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/loopback.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,

skb_orphan(skb);

/* Before queueing this packet to netif_rx(),
* make sure dst is refcounted.
*/
skb_dst_force(skb);

skb->protocol = eth_type_trans(skb, dev);

/* it's OK to use per_cpu_ptr() because BHs are off */
Expand Down
4 changes: 4 additions & 0 deletions drivers/net/macvtap.c
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q,
if (unlikely(len < ETH_HLEN))
goto err;

err = -EMSGSIZE;
if (unlikely(count > UIO_MAXIOV))
goto err;

skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, len, vnet_hdr.hdr_len,
noblock, &err);
if (!skb)
Expand Down
20 changes: 9 additions & 11 deletions drivers/net/netconsole.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
goto done;

spin_lock_irqsave(&target_list_lock, flags);
restart:
list_for_each_entry(nt, &target_list, list) {
netconsole_target_get(nt);
if (nt->np.dev == dev) {
Expand All @@ -642,20 +643,17 @@ static int netconsole_netdev_event(struct notifier_block *this,
case NETDEV_UNREGISTER:
/*
* rtnl_lock already held
* we might sleep in __netpoll_cleanup()
*/
if (nt->np.dev) {
spin_unlock_irqrestore(
&target_list_lock,
flags);
__netpoll_cleanup(&nt->np);
spin_lock_irqsave(&target_list_lock,
flags);
dev_put(nt->np.dev);
nt->np.dev = NULL;
}
spin_unlock_irqrestore(&target_list_lock, flags);
__netpoll_cleanup(&nt->np);
spin_lock_irqsave(&target_list_lock, flags);
dev_put(nt->np.dev);
nt->np.dev = NULL;
nt->enabled = 0;
stopped = true;
break;
netconsole_target_put(nt);
goto restart;
}
}
netconsole_target_put(nt);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/pch_gbe/pch_gbe_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1509,9 +1509,9 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
skb_put(skb, length);
skb->protocol = eth_type_trans(skb, netdev);
if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK)
skb->ip_summed = CHECKSUM_NONE;
else
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;

napi_gro_receive(&adapter->napi, skb);
(*work_done)++;
Expand Down
37 changes: 26 additions & 11 deletions drivers/net/r8169.c
Original file line number Diff line number Diff line change
Expand Up @@ -3105,11 +3105,34 @@ static void r810x_phy_power_up(struct rtl8169_private *tp)
rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
}

static void rtl_speed_down(struct rtl8169_private *tp)
{
u32 adv;
int lpa;

rtl_writephy(tp, 0x1f, 0x0000);
lpa = rtl_readphy(tp, MII_LPA);

if (lpa & (LPA_10HALF | LPA_10FULL))
adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full;
else if (lpa & (LPA_100HALF | LPA_100FULL))
adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
else
adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
(tp->mii.supports_gmii ?
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full : 0);

rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
adv);
}

static void r810x_pll_power_down(struct rtl8169_private *tp)
{
if (__rtl8169_get_wol(tp) & WAKE_ANY) {
rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, MII_BMCR, 0x0000);
rtl_speed_down(tp);
return;
}

Expand Down Expand Up @@ -3201,8 +3224,7 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
rtl_ephy_write(ioaddr, 0x19, 0xff64);

if (__rtl8169_get_wol(tp) & WAKE_ANY) {
rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, MII_BMCR, 0x0000);
rtl_speed_down(tp);

if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
tp->mac_version == RTL_GIGA_MAC_VER_33)
Expand Down Expand Up @@ -5203,13 +5225,6 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
}

/* Work around for AMD plateform. */
if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
(tp->mac_version == RTL_GIGA_MAC_VER_05)) {
desc->opts2 = 0;
cur_rx++;
}
}

count = cur_rx - tp->cur_rx;
Expand Down
Loading