Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
net/ipv6/ip6_gre.c is a case of parallel adds. include/trace/events/tcp.h is a little bit more tricky. The removal of in-trace-macro ifdefs in 'net' paralleled with moving show_tcp_state_name and friends over to include/trace/events/sock.h in 'net-next'. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
6bb8824732
|
@ -73,7 +73,7 @@ Example:
|
|||
compatible = "dlg,da7218";
|
||||
reg = <0x1a>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
|
||||
wakeup-source;
|
||||
|
||||
VDD-supply = <®_audio>;
|
||||
|
|
|
@ -77,7 +77,7 @@ Example:
|
|||
reg = <0x1a>;
|
||||
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
VDD-supply = <®_audio>;
|
||||
VDDMIC-supply = <®_audio>;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
<previous description obsolete, deleted>
|
||||
|
||||
Virtual memory map with 4 level page tables:
|
||||
|
||||
0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm
|
||||
|
@ -14,13 +12,15 @@ ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
|
|||
... unused hole ...
|
||||
ffffec0000000000 - fffffbffffffffff (=44 bits) kasan shadow memory (16TB)
|
||||
... unused hole ...
|
||||
fffffe8000000000 - fffffeffffffffff (=39 bits) cpu_entry_area mapping
|
||||
ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
|
||||
... unused hole ...
|
||||
ffffffef00000000 - fffffffeffffffff (=64 GB) EFI region mapping space
|
||||
... unused hole ...
|
||||
ffffffff80000000 - ffffffff9fffffff (=512 MB) kernel text mapping, from phys 0
|
||||
ffffffffa0000000 - ffffffffff5fffff (=1526 MB) module mapping space (variable)
|
||||
ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls
|
||||
ffffffffa0000000 - [fixmap start] (~1526 MB) module mapping space (variable)
|
||||
[fixmap start] - ffffffffff5fffff kernel-internal fixmap range
|
||||
ffffffffff600000 - ffffffffff600fff (=4 kB) legacy vsyscall ABI
|
||||
ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole
|
||||
|
||||
Virtual memory map with 5 level page tables:
|
||||
|
@ -36,19 +36,22 @@ ffd4000000000000 - ffd5ffffffffffff (=49 bits) virtual memory map (512TB)
|
|||
... unused hole ...
|
||||
ffdf000000000000 - fffffc0000000000 (=53 bits) kasan shadow memory (8PB)
|
||||
... unused hole ...
|
||||
fffffe8000000000 - fffffeffffffffff (=39 bits) cpu_entry_area mapping
|
||||
ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
|
||||
... unused hole ...
|
||||
ffffffef00000000 - fffffffeffffffff (=64 GB) EFI region mapping space
|
||||
... unused hole ...
|
||||
ffffffff80000000 - ffffffff9fffffff (=512 MB) kernel text mapping, from phys 0
|
||||
ffffffffa0000000 - ffffffffff5fffff (=1526 MB) module mapping space
|
||||
ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls
|
||||
ffffffffa0000000 - [fixmap start] (~1526 MB) module mapping space
|
||||
[fixmap start] - ffffffffff5fffff kernel-internal fixmap range
|
||||
ffffffffff600000 - ffffffffff600fff (=4 kB) legacy vsyscall ABI
|
||||
ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole
|
||||
|
||||
Architecture defines a 64-bit virtual address. Implementations can support
|
||||
less. Currently supported are 48- and 57-bit virtual addresses. Bits 63
|
||||
through to the most-significant implemented bit are set to either all ones
|
||||
or all zero. This causes hole between user space and kernel addresses.
|
||||
through to the most-significant implemented bit are sign extended.
|
||||
This causes hole between user space and kernel addresses if you interpret them
|
||||
as unsigned.
|
||||
|
||||
The direct mapping covers all memory in the system up to the highest
|
||||
memory address (this means in some cases it can also include PCI memory
|
||||
|
@ -58,9 +61,6 @@ vmalloc space is lazily synchronized into the different PML4/PML5 pages of
|
|||
the processes using the page fault handler, with init_top_pgt as
|
||||
reference.
|
||||
|
||||
Current X86-64 implementations support up to 46 bits of address space (64 TB),
|
||||
which is our current limit. This expands into MBZ space in the page tables.
|
||||
|
||||
We map EFI runtime services in the 'efi_pgd' PGD in a 64Gb large virtual
|
||||
memory window (this size is arbitrary, it can be raised later if needed).
|
||||
The mappings are not part of any other kernel PGD and are only available
|
||||
|
@ -72,5 +72,3 @@ following fixmap section.
|
|||
Note that if CONFIG_RANDOMIZE_MEMORY is enabled, the direct mapping of all
|
||||
physical memory, vmalloc/ioremap space and virtual memory map are randomized.
|
||||
Their order is preserved but their base will be offset early at boot time.
|
||||
|
||||
-Andi Kleen, Jul 2004
|
||||
|
|
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
|||
VERSION = 4
|
||||
PATCHLEVEL = 15
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc4
|
||||
EXTRAVERSION = -rc5
|
||||
NAME = Fearless Coyote
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
@ -160,9 +160,10 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void arch_dup_mmap(struct mm_struct *oldmm,
|
||||
struct mm_struct *mm)
|
||||
static inline int arch_dup_mmap(struct mm_struct *oldmm,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_PPC_BOOK3S_64
|
||||
|
|
|
@ -1403,7 +1403,7 @@ void show_regs(struct pt_regs * regs)
|
|||
|
||||
printk("NIP: "REG" LR: "REG" CTR: "REG"\n",
|
||||
regs->nip, regs->link, regs->ctr);
|
||||
printk("REGS: %p TRAP: %04lx %s (%s)\n",
|
||||
printk("REGS: %px TRAP: %04lx %s (%s)\n",
|
||||
regs, regs->trap, print_tainted(), init_utsname()->release);
|
||||
printk("MSR: "REG" ", regs->msr);
|
||||
print_msr_bits(regs->msr);
|
||||
|
|
|
@ -725,7 +725,8 @@ u64 kvmppc_xive_get_icp(struct kvm_vcpu *vcpu)
|
|||
|
||||
/* Return the per-cpu state for state saving/migration */
|
||||
return (u64)xc->cppr << KVM_REG_PPC_ICP_CPPR_SHIFT |
|
||||
(u64)xc->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT;
|
||||
(u64)xc->mfrr << KVM_REG_PPC_ICP_MFRR_SHIFT |
|
||||
(u64)0xff << KVM_REG_PPC_ICP_PPRI_SHIFT;
|
||||
}
|
||||
|
||||
int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval)
|
||||
|
@ -1558,7 +1559,7 @@ static int xive_set_source(struct kvmppc_xive *xive, long irq, u64 addr)
|
|||
|
||||
/*
|
||||
* Restore P and Q. If the interrupt was pending, we
|
||||
* force both P and Q, which will trigger a resend.
|
||||
* force Q and !P, which will trigger a resend.
|
||||
*
|
||||
* That means that a guest that had both an interrupt
|
||||
* pending (queued) and Q set will restore with only
|
||||
|
@ -1566,7 +1567,7 @@ static int xive_set_source(struct kvmppc_xive *xive, long irq, u64 addr)
|
|||
* is perfectly fine as coalescing interrupts that haven't
|
||||
* been presented yet is always allowed.
|
||||
*/
|
||||
if (val & KVM_XICS_PRESENTED || val & KVM_XICS_PENDING)
|
||||
if (val & KVM_XICS_PRESENTED && !(val & KVM_XICS_PENDING))
|
||||
state->old_p = true;
|
||||
if (val & KVM_XICS_QUEUED || val & KVM_XICS_PENDING)
|
||||
state->old_q = true;
|
||||
|
|
|
@ -410,8 +410,12 @@ static __u64 power_pmu_bhrb_to(u64 addr)
|
|||
int ret;
|
||||
__u64 target;
|
||||
|
||||
if (is_kernel_addr(addr))
|
||||
return branch_target((unsigned int *)addr);
|
||||
if (is_kernel_addr(addr)) {
|
||||
if (probe_kernel_read(&instr, (void *)addr, sizeof(instr)))
|
||||
return 0;
|
||||
|
||||
return branch_target(&instr);
|
||||
}
|
||||
|
||||
/* Userspace: need copy instruction here then translate it */
|
||||
pagefault_disable();
|
||||
|
|
|
@ -309,6 +309,19 @@ static int ppc_nest_imc_cpu_offline(unsigned int cpu)
|
|||
if (!cpumask_test_and_clear_cpu(cpu, &nest_imc_cpumask))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Check whether nest_imc is registered. We could end up here if the
|
||||
* cpuhotplug callback registration fails. i.e, callback invokes the
|
||||
* offline path for all successfully registered nodes. At this stage,
|
||||
* nest_imc pmu will not be registered and we should return here.
|
||||
*
|
||||
* We return with a zero since this is not an offline failure. And
|
||||
* cpuhp_setup_state() returns the actual failure reason to the caller,
|
||||
* which in turn will call the cleanup routine.
|
||||
*/
|
||||
if (!nest_pmus)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Now that this cpu is one of the designated,
|
||||
* find a next cpu a) which is online and b) in same chip.
|
||||
|
@ -1171,6 +1184,7 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
|
|||
if (nest_pmus == 1) {
|
||||
cpuhp_remove_state(CPUHP_AP_PERF_POWERPC_NEST_IMC_ONLINE);
|
||||
kfree(nest_imc_refc);
|
||||
kfree(per_nest_pmu_arr);
|
||||
}
|
||||
|
||||
if (nest_pmus > 0)
|
||||
|
@ -1195,7 +1209,6 @@ static void imc_common_cpuhp_mem_free(struct imc_pmu *pmu_ptr)
|
|||
kfree(pmu_ptr->attr_groups[IMC_EVENT_ATTR]->attrs);
|
||||
kfree(pmu_ptr->attr_groups[IMC_EVENT_ATTR]);
|
||||
kfree(pmu_ptr);
|
||||
kfree(per_nest_pmu_arr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1309,6 +1322,8 @@ int init_imc_pmu(struct device_node *parent, struct imc_pmu *pmu_ptr, int pmu_id
|
|||
ret = nest_pmu_cpumask_init();
|
||||
if (ret) {
|
||||
mutex_unlock(&nest_init_lock);
|
||||
kfree(nest_imc_refc);
|
||||
kfree(per_nest_pmu_arr);
|
||||
goto err_free;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@ extern void uml_setup_stubs(struct mm_struct *mm);
|
|||
/*
|
||||
* Needed since we do not use the asm-generic/mm_hooks.h:
|
||||
*/
|
||||
static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
|
||||
static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
|
||||
{
|
||||
uml_setup_stubs(mm);
|
||||
return 0;
|
||||
}
|
||||
extern void arch_exit_mmap(struct mm_struct *mm);
|
||||
static inline void arch_unmap(struct mm_struct *mm,
|
||||
|
|
|
@ -81,9 +81,10 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static inline void arch_dup_mmap(struct mm_struct *oldmm,
|
||||
struct mm_struct *mm)
|
||||
static inline int arch_dup_mmap(struct mm_struct *oldmm,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void arch_unmap(struct mm_struct *mm,
|
||||
|
|
|
@ -927,7 +927,8 @@ config MAXSMP
|
|||
config NR_CPUS
|
||||
int "Maximum number of CPUs" if SMP && !MAXSMP
|
||||
range 2 8 if SMP && X86_32 && !X86_BIGSMP
|
||||
range 2 512 if SMP && !MAXSMP && !CPUMASK_OFFSTACK
|
||||
range 2 64 if SMP && X86_32 && X86_BIGSMP
|
||||
range 2 512 if SMP && !MAXSMP && !CPUMASK_OFFSTACK && X86_64
|
||||
range 2 8192 if SMP && !MAXSMP && CPUMASK_OFFSTACK && X86_64
|
||||
default "1" if !SMP
|
||||
default "8192" if MAXSMP
|
||||
|
|
|
@ -942,9 +942,9 @@ ENTRY(debug)
|
|||
|
||||
/* Are we currently on the SYSENTER stack? */
|
||||
movl PER_CPU_VAR(cpu_entry_area), %ecx
|
||||
addl $CPU_ENTRY_AREA_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx
|
||||
subl %eax, %ecx /* ecx = (end of SYSENTER_stack) - esp */
|
||||
cmpl $SIZEOF_SYSENTER_stack, %ecx
|
||||
addl $CPU_ENTRY_AREA_entry_stack + SIZEOF_entry_stack, %ecx
|
||||
subl %eax, %ecx /* ecx = (end of entry_stack) - esp */
|
||||
cmpl $SIZEOF_entry_stack, %ecx
|
||||
jb .Ldebug_from_sysenter_stack
|
||||
|
||||
TRACE_IRQS_OFF
|
||||
|
@ -986,9 +986,9 @@ ENTRY(nmi)
|
|||
|
||||
/* Are we currently on the SYSENTER stack? */
|
||||
movl PER_CPU_VAR(cpu_entry_area), %ecx
|
||||
addl $CPU_ENTRY_AREA_SYSENTER_stack + SIZEOF_SYSENTER_stack, %ecx
|
||||
subl %eax, %ecx /* ecx = (end of SYSENTER_stack) - esp */
|
||||
cmpl $SIZEOF_SYSENTER_stack, %ecx
|
||||
addl $CPU_ENTRY_AREA_entry_stack + SIZEOF_entry_stack, %ecx
|
||||
subl %eax, %ecx /* ecx = (end of entry_stack) - esp */
|
||||
cmpl $SIZEOF_entry_stack, %ecx
|
||||
jb .Lnmi_from_sysenter_stack
|
||||
|
||||
/* Not on SYSENTER stack. */
|
||||
|
|
|
@ -158,8 +158,8 @@ END(native_usergs_sysret64)
|
|||
_entry_trampoline - CPU_ENTRY_AREA_entry_trampoline(%rip)
|
||||
|
||||
/* The top word of the SYSENTER stack is hot and is usable as scratch space. */
|
||||
#define RSP_SCRATCH CPU_ENTRY_AREA_SYSENTER_stack + \
|
||||
SIZEOF_SYSENTER_stack - 8 + CPU_ENTRY_AREA
|
||||
#define RSP_SCRATCH CPU_ENTRY_AREA_entry_stack + \
|
||||
SIZEOF_entry_stack - 8 + CPU_ENTRY_AREA
|
||||
|
||||
ENTRY(entry_SYSCALL_64_trampoline)
|
||||
UNWIND_HINT_EMPTY
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <asm/unistd.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/paravirt.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "vsyscall_trace.h"
|
||||
|
@ -138,6 +139,10 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
|
|||
|
||||
WARN_ON_ONCE(address != regs->ip);
|
||||
|
||||
/* This should be unreachable in NATIVE mode. */
|
||||
if (WARN_ON(vsyscall_mode == NATIVE))
|
||||
return false;
|
||||
|
||||
if (vsyscall_mode == NONE) {
|
||||
warn_bad_vsyscall(KERN_INFO, regs,
|
||||
"vsyscall attempted with vsyscall=none");
|
||||
|
@ -329,16 +334,47 @@ int in_gate_area_no_mm(unsigned long addr)
|
|||
return vsyscall_mode != NONE && (addr & PAGE_MASK) == VSYSCALL_ADDR;
|
||||
}
|
||||
|
||||
/*
|
||||
* The VSYSCALL page is the only user-accessible page in the kernel address
|
||||
* range. Normally, the kernel page tables can have _PAGE_USER clear, but
|
||||
* the tables covering VSYSCALL_ADDR need _PAGE_USER set if vsyscalls
|
||||
* are enabled.
|
||||
*
|
||||
* Some day we may create a "minimal" vsyscall mode in which we emulate
|
||||
* vsyscalls but leave the page not present. If so, we skip calling
|
||||
* this.
|
||||
*/
|
||||
static void __init set_vsyscall_pgtable_user_bits(void)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
p4d_t *p4d;
|
||||
pud_t *pud;
|
||||
pmd_t *pmd;
|
||||
|
||||
pgd = pgd_offset_k(VSYSCALL_ADDR);
|
||||
set_pgd(pgd, __pgd(pgd_val(*pgd) | _PAGE_USER));
|
||||
p4d = p4d_offset(pgd, VSYSCALL_ADDR);
|
||||
#if CONFIG_PGTABLE_LEVELS >= 5
|
||||
p4d->p4d |= _PAGE_USER;
|
||||
#endif
|
||||
pud = pud_offset(p4d, VSYSCALL_ADDR);
|
||||
set_pud(pud, __pud(pud_val(*pud) | _PAGE_USER));
|
||||
pmd = pmd_offset(pud, VSYSCALL_ADDR);
|
||||
set_pmd(pmd, __pmd(pmd_val(*pmd) | _PAGE_USER));
|
||||
}
|
||||
|
||||
void __init map_vsyscall(void)
|
||||
{
|
||||
extern char __vsyscall_page;
|
||||
unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
|
||||
|
||||
if (vsyscall_mode != NONE)
|
||||
if (vsyscall_mode != NONE) {
|
||||
__set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
|
||||
vsyscall_mode == NATIVE
|
||||
? PAGE_KERNEL_VSYSCALL
|
||||
: PAGE_KERNEL_VVAR);
|
||||
set_vsyscall_pgtable_user_bits();
|
||||
}
|
||||
|
||||
BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
|
||||
(unsigned long)VSYSCALL_ADDR);
|
||||
|
|
68
arch/x86/include/asm/cpu_entry_area.h
Normal file
68
arch/x86/include/asm/cpu_entry_area.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#ifndef _ASM_X86_CPU_ENTRY_AREA_H
|
||||
#define _ASM_X86_CPU_ENTRY_AREA_H
|
||||
|
||||
#include <linux/percpu-defs.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/*
|
||||
* cpu_entry_area is a percpu region that contains things needed by the CPU
|
||||
* and early entry/exit code. Real types aren't used for all fields here
|
||||
* to avoid circular header dependencies.
|
||||
*
|
||||
* Every field is a virtual alias of some other allocated backing store.
|
||||
* There is no direct allocation of a struct cpu_entry_area.
|
||||
*/
|
||||
struct cpu_entry_area {
|
||||
char gdt[PAGE_SIZE];
|
||||
|
||||
/*
|
||||
* The GDT is just below entry_stack and thus serves (on x86_64) as
|
||||
* a a read-only guard page.
|
||||
*/
|
||||
struct entry_stack_page entry_stack_page;
|
||||
|
||||
/*
|
||||
* On x86_64, the TSS is mapped RO. On x86_32, it's mapped RW because
|
||||
* we need task switches to work, and task switches write to the TSS.
|
||||
*/
|
||||
struct tss_struct tss;
|
||||
|
||||
char entry_trampoline[PAGE_SIZE];
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Exception stacks used for IST entries.
|
||||
*
|
||||
* In the future, this should have a separate slot for each stack
|
||||
* with guard pages between them.
|
||||
*/
|
||||
char exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ];
|
||||
#endif
|
||||
};
|
||||
|
||||
#define CPU_ENTRY_AREA_SIZE (sizeof(struct cpu_entry_area))
|
||||
#define CPU_ENTRY_AREA_TOT_SIZE (CPU_ENTRY_AREA_SIZE * NR_CPUS)
|
||||
|
||||
DECLARE_PER_CPU(struct cpu_entry_area *, cpu_entry_area);
|
||||
|
||||
extern void setup_cpu_entry_areas(void);
|
||||
extern void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags);
|
||||
|
||||
#define CPU_ENTRY_AREA_RO_IDT CPU_ENTRY_AREA_BASE
|
||||
#define CPU_ENTRY_AREA_PER_CPU (CPU_ENTRY_AREA_RO_IDT + PAGE_SIZE)
|
||||
|
||||
#define CPU_ENTRY_AREA_RO_IDT_VADDR ((void *)CPU_ENTRY_AREA_RO_IDT)
|
||||
|
||||
#define CPU_ENTRY_AREA_MAP_SIZE \
|
||||
(CPU_ENTRY_AREA_PER_CPU + CPU_ENTRY_AREA_TOT_SIZE - CPU_ENTRY_AREA_BASE)
|
||||
|
||||
extern struct cpu_entry_area *get_cpu_entry_area(int cpu);
|
||||
|
||||
static inline struct entry_stack *cpu_entry_stack(int cpu)
|
||||
{
|
||||
return &get_cpu_entry_area(cpu)->entry_stack_page.stack;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
#include <asm/mmu.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/irq_vectors.h>
|
||||
#include <asm/cpu_entry_area.h>
|
||||
|
||||
#include <linux/smp.h>
|
||||
#include <linux/percpu.h>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#ifndef _ASM_X86_ESPFIX_H
|
||||
#define _ASM_X86_ESPFIX_H
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#ifdef CONFIG_X86_ESPFIX64
|
||||
|
||||
#include <asm/percpu.h>
|
||||
|
||||
|
@ -11,7 +11,8 @@ DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
|
|||
|
||||
extern void init_espfix_bsp(void);
|
||||
extern void init_espfix_ap(int cpu);
|
||||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
#else
|
||||
static inline void init_espfix_ap(int cpu) { }
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_ESPFIX_H */
|
||||
|
|
|
@ -44,46 +44,6 @@ extern unsigned long __FIXADDR_TOP;
|
|||
PAGE_SIZE)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cpu_entry_area is a percpu region in the fixmap that contains things
|
||||
* needed by the CPU and early entry/exit code. Real types aren't used
|
||||
* for all fields here to avoid circular header dependencies.
|
||||
*
|
||||
* Every field is a virtual alias of some other allocated backing store.
|
||||
* There is no direct allocation of a struct cpu_entry_area.
|
||||
*/
|
||||
struct cpu_entry_area {
|
||||
char gdt[PAGE_SIZE];
|
||||
|
||||
/*
|
||||
* The GDT is just below SYSENTER_stack and thus serves (on x86_64) as
|
||||
* a a read-only guard page.
|
||||
*/
|
||||
struct SYSENTER_stack_page SYSENTER_stack_page;
|
||||
|
||||
/*
|
||||
* On x86_64, the TSS is mapped RO. On x86_32, it's mapped RW because
|
||||
* we need task switches to work, and task switches write to the TSS.
|
||||
*/
|
||||
struct tss_struct tss;
|
||||
|
||||
char entry_trampoline[PAGE_SIZE];
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/*
|
||||
* Exception stacks used for IST entries.
|
||||
*
|
||||
* In the future, this should have a separate slot for each stack
|
||||
* with guard pages between them.
|
||||
*/
|
||||
char exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ];
|
||||
#endif
|
||||
};
|
||||
|
||||
#define CPU_ENTRY_AREA_PAGES (sizeof(struct cpu_entry_area) / PAGE_SIZE)
|
||||
|
||||
extern void setup_cpu_entry_areas(void);
|
||||
|
||||
/*
|
||||
* Here we define all the compile-time 'special' virtual
|
||||
* addresses. The point is to have a constant address at
|
||||
|
@ -123,7 +83,6 @@ enum fixed_addresses {
|
|||
FIX_IO_APIC_BASE_0,
|
||||
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS - 1,
|
||||
#endif
|
||||
FIX_RO_IDT, /* Virtual mapping for read-only IDT */
|
||||
#ifdef CONFIG_X86_32
|
||||
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
|
||||
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
|
||||
|
@ -139,9 +98,6 @@ enum fixed_addresses {
|
|||
#ifdef CONFIG_X86_INTEL_MID
|
||||
FIX_LNW_VRTC,
|
||||
#endif
|
||||
/* Fixmap entries to remap the GDTs, one per processor. */
|
||||
FIX_CPU_ENTRY_AREA_TOP,
|
||||
FIX_CPU_ENTRY_AREA_BOTTOM = FIX_CPU_ENTRY_AREA_TOP + (CPU_ENTRY_AREA_PAGES * NR_CPUS) - 1,
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI_GHES
|
||||
/* Used for GHES mapping from assorted contexts */
|
||||
|
@ -182,7 +138,7 @@ enum fixed_addresses {
|
|||
extern void reserve_top_address(unsigned long reserve);
|
||||
|
||||
#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
|
||||
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
|
||||
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
|
||||
|
||||
extern int fixmaps_set;
|
||||
|
||||
|
@ -230,30 +186,5 @@ void __init *early_memremap_decrypted_wp(resource_size_t phys_addr,
|
|||
void __early_set_fixmap(enum fixed_addresses idx,
|
||||
phys_addr_t phys, pgprot_t flags);
|
||||
|
||||
static inline unsigned int __get_cpu_entry_area_page_index(int cpu, int page)
|
||||
{
|
||||
BUILD_BUG_ON(sizeof(struct cpu_entry_area) % PAGE_SIZE != 0);
|
||||
|
||||
return FIX_CPU_ENTRY_AREA_BOTTOM - cpu*CPU_ENTRY_AREA_PAGES - page;
|
||||
}
|
||||
|
||||
#define __get_cpu_entry_area_offset_index(cpu, offset) ({ \
|
||||
BUILD_BUG_ON(offset % PAGE_SIZE != 0); \
|
||||
__get_cpu_entry_area_page_index(cpu, offset / PAGE_SIZE); \
|
||||
})
|
||||
|
||||
#define get_cpu_entry_area_index(cpu, field) \
|
||||
__get_cpu_entry_area_offset_index((cpu), offsetof(struct cpu_entry_area, field))
|
||||
|
||||
static inline struct cpu_entry_area *get_cpu_entry_area(int cpu)
|
||||
{
|
||||
return (struct cpu_entry_area *)__fix_to_virt(__get_cpu_entry_area_page_index(cpu, 0));
|
||||
}
|
||||
|
||||
static inline struct SYSENTER_stack *cpu_SYSENTER_stack(int cpu)
|
||||
{
|
||||
return &get_cpu_entry_area(cpu)->SYSENTER_stack_page.stack;
|
||||
}
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
#endif /* _ASM_X86_FIXMAP_H */
|
||||
|
|
53
arch/x86/include/asm/invpcid.h
Normal file
53
arch/x86/include/asm/invpcid.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_INVPCID
|
||||
#define _ASM_X86_INVPCID
|
||||
|
||||
static inline void __invpcid(unsigned long pcid, unsigned long addr,
|
||||
unsigned long type)
|
||||
{
|
||||
struct { u64 d[2]; } desc = { { pcid, addr } };
|
||||
|
||||
/*
|
||||
* The memory clobber is because the whole point is to invalidate
|
||||
* stale TLB entries and, especially if we're flushing global
|
||||
* mappings, we don't want the compiler to reorder any subsequent
|
||||
* memory accesses before the TLB flush.
|
||||
*
|
||||
* The hex opcode is invpcid (%ecx), %eax in 32-bit mode and
|
||||
* invpcid (%rcx), %rax in long mode.
|
||||
*/
|
||||
asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01"
|
||||
: : "m" (desc), "a" (type), "c" (&desc) : "memory");
|
||||
}
|
||||
|
||||
#define INVPCID_TYPE_INDIV_ADDR 0
|
||||
#define INVPCID_TYPE_SINGLE_CTXT 1
|
||||
#define INVPCID_TYPE_ALL_INCL_GLOBAL 2
|
||||
#define INVPCID_TYPE_ALL_NON_GLOBAL 3
|
||||
|
||||
/* Flush all mappings for a given pcid and addr, not including globals. */
|
||||
static inline void invpcid_flush_one(unsigned long pcid,
|
||||
unsigned long addr)
|
||||
{
|
||||
__invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR);
|
||||
}
|
||||
|
||||
/* Flush all mappings for a given PCID, not including globals. */
|
||||
static inline void invpcid_flush_single_context(unsigned long pcid)
|
||||
{
|
||||
__invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT);
|
||||
}
|
||||
|
||||
/* Flush all mappings, including globals, for all PCIDs. */
|
||||
static inline void invpcid_flush_all(void)
|
||||
{
|
||||
__invpcid(0, 0, INVPCID_TYPE_ALL_INCL_GLOBAL);
|
||||
}
|
||||
|
||||
/* Flush all mappings for all PCIDs except globals. */
|
||||
static inline void invpcid_flush_all_nonglobals(void)
|
||||
{
|
||||
__invpcid(0, 0, INVPCID_TYPE_ALL_NON_GLOBAL);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_INVPCID */
|
|
@ -3,6 +3,7 @@
|
|||
#define _ASM_X86_MMU_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
|
@ -27,7 +28,8 @@ typedef struct {
|
|||
atomic64_t tlb_gen;
|
||||
|
||||
#ifdef CONFIG_MODIFY_LDT_SYSCALL
|
||||
struct ldt_struct *ldt;
|
||||
struct rw_semaphore ldt_usr_sem;
|
||||
struct ldt_struct *ldt;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
|
|
@ -57,11 +57,17 @@ struct ldt_struct {
|
|||
/*
|
||||
* Used for LDT copy/destruction.
|
||||
*/
|
||||
int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm);
|
||||
static inline void init_new_context_ldt(struct mm_struct *mm)
|
||||
{
|
||||
mm->context.ldt = NULL;
|
||||
init_rwsem(&mm->context.ldt_usr_sem);
|
||||
}
|
||||
int ldt_dup_context(struct mm_struct *oldmm, struct mm_struct *mm);
|
||||
void destroy_context_ldt(struct mm_struct *mm);
|
||||
#else /* CONFIG_MODIFY_LDT_SYSCALL */
|
||||
static inline int init_new_context_ldt(struct task_struct *tsk,
|
||||
struct mm_struct *mm)
|
||||
static inline void init_new_context_ldt(struct mm_struct *mm) { }
|
||||
static inline int ldt_dup_context(struct mm_struct *oldmm,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -132,18 +138,21 @@ void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk);
|
|||
static inline int init_new_context(struct task_struct *tsk,
|
||||
struct mm_struct *mm)
|
||||
{
|
||||
mutex_init(&mm->context.lock);
|
||||
|
||||
mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id);
|
||||
atomic64_set(&mm->context.tlb_gen, 0);
|
||||
|
||||
#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
|
||||
#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
|
||||
if (cpu_feature_enabled(X86_FEATURE_OSPKE)) {
|
||||
/* pkey 0 is the default and always allocated */
|
||||
mm->context.pkey_allocation_map = 0x1;
|
||||
/* -1 means unallocated or invalid */
|
||||
mm->context.execute_only_pkey = -1;
|
||||
}
|
||||
#endif
|
||||
return init_new_context_ldt(tsk, mm);
|
||||
#endif
|
||||
init_new_context_ldt(mm);
|
||||
return 0;
|
||||
}
|
||||
static inline void destroy_context(struct mm_struct *mm)
|
||||
{
|
||||
|
@ -176,10 +185,10 @@ do { \
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
static inline void arch_dup_mmap(struct mm_struct *oldmm,
|
||||
struct mm_struct *mm)
|
||||
static inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
|
||||
{
|
||||
paravirt_arch_dup_mmap(oldmm, mm);
|
||||
return ldt_dup_context(oldmm, mm);
|
||||
}
|
||||
|
||||
static inline void arch_exit_mmap(struct mm_struct *mm)
|
||||
|
@ -281,33 +290,6 @@ static inline bool arch_vma_access_permitted(struct vm_area_struct *vma,
|
|||
return __pkru_allows_pkey(vma_pkey(vma), write);
|
||||
}
|
||||
|
||||
/*
|
||||
* If PCID is on, ASID-aware code paths put the ASID+1 into the PCID
|
||||
* bits. This serves two purposes. It prevents a nasty situation in
|
||||
* which PCID-unaware code saves CR3, loads some other value (with PCID
|
||||
* == 0), and then restores CR3, thus corrupting the TLB for ASID 0 if
|
||||
* the saved ASID was nonzero. It also means that any bugs involving
|
||||
* loading a PCID-enabled CR3 with CR4.PCIDE off will trigger
|
||||
* deterministically.
|
||||
*/
|
||||
|
||||
static inline unsigned long build_cr3(struct mm_struct *mm, u16 asid)
|
||||
{
|
||||
if (static_cpu_has(X86_FEATURE_PCID)) {
|
||||
VM_WARN_ON_ONCE(asid > 4094);
|
||||
return __sme_pa(mm->pgd) | (asid + 1);
|
||||
} else {
|
||||
VM_WARN_ON_ONCE(asid != 0);
|
||||
return __sme_pa(mm->pgd);
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long build_cr3_noflush(struct mm_struct *mm, u16 asid)
|
||||
{
|
||||
VM_WARN_ON_ONCE(asid > 4094);
|
||||
return __sme_pa(mm->pgd) | (asid + 1) | CR3_NOFLUSH;
|
||||
}
|
||||
|
||||
/*
|
||||
* This can be used from process context to figure out what the value of
|
||||
* CR3 is without needing to do a (slow) __read_cr3().
|
||||
|
@ -317,7 +299,7 @@ static inline unsigned long build_cr3_noflush(struct mm_struct *mm, u16 asid)
|
|||
*/
|
||||
static inline unsigned long __get_current_cr3_fast(void)
|
||||
{
|
||||
unsigned long cr3 = build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm),
|
||||
unsigned long cr3 = build_cr3(this_cpu_read(cpu_tlbstate.loaded_mm)->pgd,
|
||||
this_cpu_read(cpu_tlbstate.loaded_mm_asid));
|
||||
|
||||
/* For now, be very restrictive about when this can be called. */
|
||||
|
|
|
@ -38,13 +38,22 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */
|
|||
#define LAST_PKMAP 1024
|
||||
#endif
|
||||
|
||||
#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \
|
||||
& PMD_MASK)
|
||||
/*
|
||||
* Define this here and validate with BUILD_BUG_ON() in pgtable_32.c
|
||||
* to avoid include recursion hell
|
||||
*/
|
||||
#define CPU_ENTRY_AREA_PAGES (NR_CPUS * 40)
|
||||
|
||||
#define CPU_ENTRY_AREA_BASE \
|
||||
((FIXADDR_START - PAGE_SIZE * (CPU_ENTRY_AREA_PAGES + 1)) & PMD_MASK)
|
||||
|
||||
#define PKMAP_BASE \
|
||||
((CPU_ENTRY_AREA_BASE - PAGE_SIZE) & PMD_MASK)
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
# define VMALLOC_END (PKMAP_BASE - 2 * PAGE_SIZE)
|
||||
#else
|
||||
# define VMALLOC_END (FIXADDR_START - 2 * PAGE_SIZE)
|
||||
# define VMALLOC_END (CPU_ENTRY_AREA_BASE - 2 * PAGE_SIZE)
|
||||
#endif
|
||||
|
||||
#define MODULES_VADDR VMALLOC_START
|
||||
|
|
|
@ -76,32 +76,41 @@ typedef struct { pteval_t pte; } pte_t;
|
|||
#define PGDIR_MASK (~(PGDIR_SIZE - 1))
|
||||
|
||||
/* See Documentation/x86/x86_64/mm.txt for a description of the memory map. */
|
||||
#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL)
|
||||
#define MAXMEM _AC(__AC(1, UL) << MAX_PHYSMEM_BITS, UL)
|
||||
|
||||
#ifdef CONFIG_X86_5LEVEL
|
||||
#define VMALLOC_SIZE_TB _AC(16384, UL)
|
||||
#define __VMALLOC_BASE _AC(0xff92000000000000, UL)
|
||||
#define __VMEMMAP_BASE _AC(0xffd4000000000000, UL)
|
||||
# define VMALLOC_SIZE_TB _AC(16384, UL)
|
||||
# define __VMALLOC_BASE _AC(0xff92000000000000, UL)
|
||||
# define __VMEMMAP_BASE _AC(0xffd4000000000000, UL)
|
||||
#else
|
||||
#define VMALLOC_SIZE_TB _AC(32, UL)
|
||||
#define __VMALLOC_BASE _AC(0xffffc90000000000, UL)
|
||||
#define __VMEMMAP_BASE _AC(0xffffea0000000000, UL)
|
||||
# define VMALLOC_SIZE_TB _AC(32, UL)
|
||||
# define __VMALLOC_BASE _AC(0xffffc90000000000, UL)
|
||||
# define __VMEMMAP_BASE _AC(0xffffea0000000000, UL)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RANDOMIZE_MEMORY
|
||||
#define VMALLOC_START vmalloc_base
|
||||
#define VMEMMAP_START vmemmap_base
|
||||
# define VMALLOC_START vmalloc_base
|
||||
# define VMEMMAP_START vmemmap_base
|
||||
#else
|
||||
#define VMALLOC_START __VMALLOC_BASE
|
||||
#define VMEMMAP_START __VMEMMAP_BASE
|
||||
# define VMALLOC_START __VMALLOC_BASE
|
||||
# define VMEMMAP_START __VMEMMAP_BASE
|
||||
#endif /* CONFIG_RANDOMIZE_MEMORY */
|
||||
#define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL))
|
||||
#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE)
|
||||
|
||||
#define VMALLOC_END (VMALLOC_START + _AC((VMALLOC_SIZE_TB << 40) - 1, UL))
|
||||
|
||||
#define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE)
|
||||
/* The module sections ends with the start of the fixmap */
|
||||
#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1)
|
||||
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
|
||||
#define ESPFIX_PGD_ENTRY _AC(-2, UL)
|
||||
#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << P4D_SHIFT)
|
||||
#define EFI_VA_START ( -4 * (_AC(1, UL) << 30))
|
||||
#define EFI_VA_END (-68 * (_AC(1, UL) << 30))
|
||||
#define MODULES_END __fix_to_virt(__end_of_fixed_addresses + 1)
|
||||
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
|
||||
|
||||
#define ESPFIX_PGD_ENTRY _AC(-2, UL)
|
||||
#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << P4D_SHIFT)
|
||||
|
||||
#define CPU_ENTRY_AREA_PGD _AC(-3, UL)
|
||||
#define CPU_ENTRY_AREA_BASE (CPU_ENTRY_AREA_PGD << P4D_SHIFT)
|
||||
|
||||
#define EFI_VA_START ( -4 * (_AC(1, UL) << 30))
|
||||
#define EFI_VA_END (-68 * (_AC(1, UL) << 30))
|
||||
|
||||
#define EARLY_DYNAMIC_PAGE_TABLES 64
|
||||
|
||||
|
|
|
@ -337,12 +337,12 @@ struct x86_hw_tss {
|
|||
#define IO_BITMAP_OFFSET (offsetof(struct tss_struct, io_bitmap) - offsetof(struct tss_struct, x86_tss))
|
||||
#define INVALID_IO_BITMAP_OFFSET 0x8000
|
||||
|
||||
struct SYSENTER_stack {
|
||||
struct entry_stack {
|
||||
unsigned long words[64];
|
||||
};
|
||||
|
||||
struct SYSENTER_stack_page {
|
||||
struct SYSENTER_stack stack;
|
||||
struct entry_stack_page {
|
||||
struct entry_stack stack;
|
||||
} __aligned(PAGE_SIZE);
|
||||
|
||||
struct tss_struct {
|
||||
|
|
|
@ -16,7 +16,7 @@ enum stack_type {
|
|||
STACK_TYPE_TASK,
|
||||
STACK_TYPE_IRQ,
|
||||
STACK_TYPE_SOFTIRQ,
|
||||
STACK_TYPE_SYSENTER,
|
||||
STACK_TYPE_ENTRY,
|
||||
STACK_TYPE_EXCEPTION,
|
||||
STACK_TYPE_EXCEPTION_LAST = STACK_TYPE_EXCEPTION + N_EXCEPTION_STACKS-1,
|
||||
};
|
||||
|
@ -29,7 +29,7 @@ struct stack_info {
|
|||
bool in_task_stack(unsigned long *stack, struct task_struct *task,
|
||||
struct stack_info *info);
|
||||
|
||||
bool in_sysenter_stack(unsigned long *stack, struct stack_info *info);
|
||||
bool in_entry_stack(unsigned long *stack, struct stack_info *info);
|
||||
|
||||
int get_stack_info(unsigned long *stack, struct task_struct *task,
|
||||
struct stack_info *info, unsigned long *visit_mask);
|
||||
|
|
|
@ -9,70 +9,66 @@
|
|||
#include <asm/cpufeature.h>
|
||||
#include <asm/special_insns.h>
|
||||
#include <asm/smp.h>
|
||||
|
||||
static inline void __invpcid(unsigned long pcid, unsigned long addr,
|
||||
unsigned long type)
|
||||
{
|
||||
struct { u64 d[2]; } desc = { { pcid, addr } };
|
||||
|
||||
/*
|
||||
* The memory clobber is because the whole point is to invalidate
|
||||
* stale TLB entries and, especially if we're flushing global
|
||||
* mappings, we don't want the compiler to reorder any subsequent
|
||||
* memory accesses before the TLB flush.
|
||||
*
|
||||
* The hex opcode is invpcid (%ecx), %eax in 32-bit mode and
|
||||
* invpcid (%rcx), %rax in long mode.
|
||||
*/
|
||||
asm volatile (".byte 0x66, 0x0f, 0x38, 0x82, 0x01"
|
||||
: : "m" (desc), "a" (type), "c" (&desc) : "memory");
|
||||
}
|
||||
|
||||
#define INVPCID_TYPE_INDIV_ADDR 0
|
||||
#define INVPCID_TYPE_SINGLE_CTXT 1
|
||||
#define INVPCID_TYPE_ALL_INCL_GLOBAL 2
|
||||
#define INVPCID_TYPE_ALL_NON_GLOBAL 3
|
||||
|
||||
/* Flush all mappings for a given pcid and addr, not including globals. */
|
||||
static inline void invpcid_flush_one(unsigned long pcid,
|
||||
unsigned long addr)
|
||||
{
|
||||
__invpcid(pcid, addr, INVPCID_TYPE_INDIV_ADDR);
|
||||
}
|
||||
|
||||
/* Flush all mappings for a given PCID, not including globals. */
|
||||
static inline void invpcid_flush_single_context(unsigned long pcid)
|
||||
{
|
||||
__invpcid(pcid, 0, INVPCID_TYPE_SINGLE_CTXT);
|
||||
}
|
||||
|
||||
/* Flush all mappings, including globals, for all PCIDs. */
|
||||
static inline void invpcid_flush_all(void)
|
||||
{
|
||||
__invpcid(0, 0, INVPCID_TYPE_ALL_INCL_GLOBAL);
|
||||
}
|
||||
|
||||
/* Flush all mappings for all PCIDs except globals. */
|
||||
static inline void invpcid_flush_all_nonglobals(void)
|
||||
{
|
||||
__invpcid(0, 0, INVPCID_TYPE_ALL_NON_GLOBAL);
|
||||
}
|
||||
#include <asm/invpcid.h>
|
||||
|
||||
static inline u64 inc_mm_tlb_gen(struct mm_struct *mm)
|
||||
{
|
||||
u64 new_tlb_gen;
|
||||
|
||||
/*
|
||||
* Bump the generation count. This also serves as a full barrier
|
||||
* that synchronizes with switch_mm(): callers are required to order
|
||||
* their read of mm_cpumask after their writes to the paging
|
||||
* structures.
|
||||
*/
|
||||
smp_mb__before_atomic();
|
||||
new_tlb_gen = atomic64_inc_return(&mm->context.tlb_gen);
|
||||
smp_mb__after_atomic();
|
||||
return atomic64_inc_return(&mm->context.tlb_gen);
|
||||
}
|
||||
|
||||
return new_tlb_gen;
|
||||
/* There are 12 bits of space for ASIDS in CR3 */
|
||||
#define CR3_HW_ASID_BITS 12
|
||||
/*
|
||||
* When enabled, PAGE_TABLE_ISOLATION consumes a single bit for
|
||||
* user/kernel switches
|
||||
*/
|
||||
#define PTI_CONSUMED_ASID_BITS 0
|
||||
|
||||
#define CR3_AVAIL_ASID_BITS (CR3_HW_ASID_BITS - PTI_CONSUMED_ASID_BITS)
|
||||
/*
|
||||
* ASIDs are zero-based: 0->MAX_AVAIL_ASID are valid. -1 below to account
|
||||
* for them being zero-based. Another -1 is because ASID 0 is reserved for
|
||||
* use by non-PCID-aware users.
|
||||
*/
|
||||
#define MAX_ASID_AVAILABLE ((1 << CR3_AVAIL_ASID_BITS) - 2)
|
||||
|
||||
static inline u16 kern_pcid(u16 asid)
|
||||
{
|
||||
VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE);
|
||||
/*
|
||||
* If PCID is on, ASID-aware code paths put the ASID+1 into the
|
||||
* PCID bits. This serves two purposes. It prevents a nasty
|
||||
* situation in which PCID-unaware code saves CR3, loads some other
|
||||
* value (with PCID == 0), and then restores CR3, thus corrupting
|
||||
* the TLB for ASID 0 if the saved ASID was nonzero. It also means
|
||||
* that any bugs involving loading a PCID-enabled CR3 with
|
||||
* CR4.PCIDE off will trigger deterministically.
|
||||
*/
|
||||
return asid + 1;
|
||||
}
|
||||
|
||||
struct pgd_t;
|
||||
static inline unsigned long build_cr3(pgd_t *pgd, u16 asid)
|
||||
{
|
||||
if (static_cpu_has(X86_FEATURE_PCID)) {
|
||||
return __sme_pa(pgd) | kern_pcid(asid);
|
||||
} else {
|
||||
VM_WARN_ON_ONCE(asid != 0);
|
||||
return __sme_pa(pgd);
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned long build_cr3_noflush(pgd_t *pgd, u16 asid)
|
||||
{
|
||||
VM_WARN_ON_ONCE(asid > MAX_ASID_AVAILABLE);
|
||||
VM_WARN_ON_ONCE(!this_cpu_has(X86_FEATURE_PCID));
|
||||
return __sme_pa(pgd) | kern_pcid(asid) | CR3_NOFLUSH;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
|
@ -237,6 +233,9 @@ static inline void cr4_set_bits_and_update_boot(unsigned long mask)
|
|||
|
||||
extern void initialize_tlbstate_and_flush(void);
|
||||
|
||||
/*
|
||||
* flush the entire current user mapping
|
||||
*/
|
||||
static inline void __native_flush_tlb(void)
|
||||
{
|
||||
/*
|
||||
|
@ -249,20 +248,12 @@ static inline void __native_flush_tlb(void)
|
|||
preempt_enable();
|
||||
}
|
||||
|
||||
static inline void __native_flush_tlb_global_irq_disabled(void)
|
||||
{
|
||||
unsigned long cr4;
|
||||
|
||||
cr4 = this_cpu_read(cpu_tlbstate.cr4);
|
||||
/* clear PGE */
|
||||
native_write_cr4(cr4 & ~X86_CR4_PGE);
|
||||
/* write old PGE again and flush TLBs */
|
||||
native_write_cr4(cr4);
|
||||
}
|
||||
|
||||
/*
|
||||
* flush everything
|
||||
*/
|
||||
static inline void __native_flush_tlb_global(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long cr4, flags;
|
||||
|
||||
if (static_cpu_has(X86_FEATURE_INVPCID)) {
|
||||
/*
|
||||
|
@ -280,22 +271,36 @@ static inline void __native_flush_tlb_global(void)
|
|||
*/
|
||||
raw_local_irq_save(flags);
|
||||
|
||||
__native_flush_tlb_global_irq_disabled();
|
||||
cr4 = this_cpu_read(cpu_tlbstate.cr4);
|
||||
/* toggle PGE */
|
||||
native_write_cr4(cr4 ^ X86_CR4_PGE);
|
||||
/* write old PGE again and flush TLBs */
|
||||
native_write_cr4(cr4);
|
||||
|
||||
raw_local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* flush one page in the user mapping
|
||||
*/
|
||||
static inline void __native_flush_tlb_single(unsigned long addr)
|
||||
{
|
||||
asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
|
||||
}
|
||||
|
||||
/*
|
||||
* flush everything
|
||||
*/
|
||||
static inline void __flush_tlb_all(void)
|
||||
{
|
||||
if (boot_cpu_has(X86_FEATURE_PGE))
|
||||
if (boot_cpu_has(X86_FEATURE_PGE)) {
|
||||
__flush_tlb_global();
|
||||
else
|
||||
} else {
|
||||
/*
|
||||
* !PGE -> !PCID (setup_pcid()), thus every flush is total.
|
||||
*/
|
||||
__flush_tlb();
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: if we somehow had PCID but not PGE, then this wouldn't work --
|
||||
|
@ -306,6 +311,9 @@ static inline void __flush_tlb_all(void)
|
|||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* flush one page in the kernel mapping
|
||||
*/
|
||||
static inline void __flush_tlb_one(unsigned long addr)
|
||||
{
|
||||
count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ONE);
|
||||
|
|
|
@ -97,6 +97,6 @@ void common(void) {
|
|||
/* Layout info for cpu_entry_area */
|
||||
OFFSET(CPU_ENTRY_AREA_tss, cpu_entry_area, tss);
|
||||
OFFSET(CPU_ENTRY_AREA_entry_trampoline, cpu_entry_area, entry_trampoline);
|
||||
OFFSET(CPU_ENTRY_AREA_SYSENTER_stack, cpu_entry_area, SYSENTER_stack_page);
|
||||
DEFINE(SIZEOF_SYSENTER_stack, sizeof(struct SYSENTER_stack));
|
||||
OFFSET(CPU_ENTRY_AREA_entry_stack, cpu_entry_area, entry_stack_page);
|
||||
DEFINE(SIZEOF_entry_stack, sizeof(struct entry_stack));
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ void foo(void)
|
|||
|
||||
/* Offset from the sysenter stack to tss.sp0 */
|
||||
DEFINE(TSS_sysenter_sp0, offsetof(struct cpu_entry_area, tss.x86_tss.sp0) -
|
||||
offsetofend(struct cpu_entry_area, SYSENTER_stack_page.stack));
|
||||
offsetofend(struct cpu_entry_area, entry_stack_page.stack));
|
||||
|
||||
#ifdef CONFIG_CC_STACKPROTECTOR
|
||||
BLANK();
|
||||
|
|
|
@ -506,102 +506,8 @@ static const unsigned int exception_stack_sizes[N_EXCEPTION_STACKS] = {
|
|||
[0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STKSZ,
|
||||
[DEBUG_STACK - 1] = DEBUG_STKSZ
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
|
||||
[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
|
||||
#endif
|
||||
|
||||
static DEFINE_PER_CPU_PAGE_ALIGNED(struct SYSENTER_stack_page,
|
||||
SYSENTER_stack_storage);
|
||||
|
||||
static void __init
|
||||
set_percpu_fixmap_pages(int idx, void *ptr, int pages, pgprot_t prot)
|
||||
{
|
||||
for ( ; pages; pages--, idx--, ptr += PAGE_SIZE)
|
||||
__set_fixmap(idx, per_cpu_ptr_to_phys(ptr), prot);
|
||||
}
|
||||
|
||||
/* Setup the fixmap mappings only once per-processor */
|
||||
static void __init setup_cpu_entry_area(int cpu)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
extern char _entry_trampoline[];
|
||||
|
||||
/* On 64-bit systems, we use a read-only fixmap GDT and TSS. */
|
||||
pgprot_t gdt_prot = PAGE_KERNEL_RO;
|
||||
pgprot_t tss_prot = PAGE_KERNEL_RO;
|
||||
#else
|
||||
/*
|
||||
* On native 32-bit systems, the GDT cannot be read-only because
|
||||
* our double fault handler uses a task gate, and entering through
|
||||
* a task gate needs to change an available TSS to busy. If the
|
||||
* GDT is read-only, that will triple fault. The TSS cannot be
|
||||
* read-only because the CPU writes to it on task switches.
|
||||
*
|
||||
* On Xen PV, the GDT must be read-only because the hypervisor
|
||||
* requires it.
|
||||
*/
|
||||
pgprot_t gdt_prot = boot_cpu_has(X86_FEATURE_XENPV) ?
|
||||
PAGE_KERNEL_RO : PAGE_KERNEL;
|
||||
pgprot_t tss_prot = PAGE_KERNEL;
|
||||
#endif
|
||||
|
||||
__set_fixmap(get_cpu_entry_area_index(cpu, gdt), get_cpu_gdt_paddr(cpu), gdt_prot);
|
||||
set_percpu_fixmap_pages(get_cpu_entry_area_index(cpu, SYSENTER_stack_page),
|
||||
per_cpu_ptr(&SYSENTER_stack_storage, cpu), 1,
|
||||
PAGE_KERNEL);
|
||||
|
||||
/*
|
||||
* The Intel SDM says (Volume 3, 7.2.1):
|
||||
*
|
||||
* Avoid placing a page boundary in the part of the TSS that the
|
||||
* processor reads during a task switch (the first 104 bytes). The
|
||||
* processor may not correctly perform address translations if a
|
||||
* boundary occurs in this area. During a task switch, the processor
|
||||
* reads and writes into the first 104 bytes of each TSS (using
|
||||
* contiguous physical addresses beginning with the physical address
|
||||
* of the first byte of the TSS). So, after TSS access begins, if
|
||||
* part of the 104 bytes is not physically contiguous, the processor
|
||||
* will access incorrect information without generating a page-fault
|
||||
* exception.
|
||||
*
|
||||
* There are also a lot of errata involving the TSS spanning a page
|
||||
* boundary. Assert that we're not doing that.
|
||||
*/
|
||||
BUILD_BUG_ON((offsetof(struct tss_struct, x86_tss) ^
|
||||
offsetofend(struct tss_struct, x86_tss)) & PAGE_MASK);
|
||||
BUILD_BUG_ON(sizeof(struct tss_struct) % PAGE_SIZE != 0);
|
||||
set_percpu_fixmap_pages(get_cpu_entry_area_index(cpu, tss),
|
||||
&per_cpu(cpu_tss_rw, cpu),
|
||||
sizeof(struct tss_struct) / PAGE_SIZE,
|
||||
tss_prot);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
per_cpu(cpu_entry_area, cpu) = get_cpu_entry_area(cpu);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
BUILD_BUG_ON(sizeof(exception_stacks) % PAGE_SIZE != 0);
|
||||
BUILD_BUG_ON(sizeof(exception_stacks) !=
|
||||
sizeof(((struct cpu_entry_area *)0)->exception_stacks));
|
||||
set_percpu_fixmap_pages(get_cpu_entry_area_index(cpu, exception_stacks),
|
||||
&per_cpu(exception_stacks, cpu),
|
||||
sizeof(exception_stacks) / PAGE_SIZE,
|
||||
PAGE_KERNEL);
|
||||
|
||||
__set_fixmap(get_cpu_entry_area_index(cpu, entry_trampoline),
|
||||
__pa_symbol(_entry_trampoline), PAGE_KERNEL_RX);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __init setup_cpu_entry_areas(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
setup_cpu_entry_area(cpu);
|
||||
}
|
||||
|
||||
/* Load the original GDT from the per-cpu structure */
|
||||
void load_direct_gdt(int cpu)
|
||||
{
|
||||
|
@ -1348,7 +1254,7 @@ void enable_sep_cpu(void)
|
|||
|
||||
tss->x86_tss.ss1 = __KERNEL_CS;
|
||||
wrmsr(MSR_IA32_SYSENTER_CS, tss->x86_tss.ss1, 0);
|
||||
wrmsr(MSR_IA32_SYSENTER_ESP, (unsigned long)(cpu_SYSENTER_stack(cpu) + 1), 0);
|
||||
wrmsr(MSR_IA32_SYSENTER_ESP, (unsigned long)(cpu_entry_stack(cpu) + 1), 0);
|
||||
wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long)entry_SYSENTER_32, 0);
|
||||
|
||||
put_cpu();
|
||||
|
@ -1465,7 +1371,7 @@ void syscall_init(void)
|
|||
* AMD doesn't allow SYSENTER in long mode (either 32- or 64-bit).
|
||||
*/
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_CS, (u64)__KERNEL_CS);
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_ESP, (unsigned long)(cpu_SYSENTER_stack(cpu) + 1));
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_ESP, (unsigned long)(cpu_entry_stack(cpu) + 1));
|
||||
wrmsrl_safe(MSR_IA32_SYSENTER_EIP, (u64)entry_SYSENTER_compat);
|
||||
#else
|
||||
wrmsrl(MSR_CSTAR, (unsigned long)ignore_sysret);
|
||||
|
@ -1680,7 +1586,7 @@ void cpu_init(void)
|
|||
*/
|
||||
set_tss_desc(cpu, &get_cpu_entry_area(cpu)->tss.x86_tss);
|
||||
load_TR_desc();
|
||||
load_sp0((unsigned long)(cpu_SYSENTER_stack(cpu) + 1));
|
||||
load_sp0((unsigned long)(cpu_entry_stack(cpu) + 1));
|
||||
|
||||
load_mm_ldt(&init_mm);
|
||||
|
||||
|
|
|
@ -565,15 +565,6 @@ static void print_ucode(struct ucode_cpu_info *uci)
|
|||
}
|
||||
#else
|
||||
|
||||
/*
|
||||
* Flush global tlb. We only do this in x86_64 where paging has been enabled
|
||||
* already and PGE should be enabled as well.
|
||||
*/
|
||||
static inline void flush_tlb_early(void)
|
||||
{
|
||||
__native_flush_tlb_global_irq_disabled();
|
||||
}
|
||||
|
||||
static inline void print_ucode(struct ucode_cpu_info *uci)
|
||||
{
|
||||
struct microcode_intel *mc;
|
||||
|
@ -602,10 +593,6 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
|
|||
if (rev != mc->hdr.rev)
|
||||
return -1;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
/* Flush global tlb. This is precaution. */
|
||||
flush_tlb_early();
|
||||
#endif
|
||||
uci->cpu_sig.rev = rev;
|
||||
|
||||
if (early)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/nmi.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <asm/cpu_entry_area.h>
|
||||
#include <asm/stacktrace.h>
|
||||
#include <asm/unwind.h>
|
||||
|
||||
|
@ -43,9 +44,9 @@ bool in_task_stack(unsigned long *stack, struct task_struct *task,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool in_sysenter_stack(unsigned long *stack, struct stack_info *info)
|
||||
bool in_entry_stack(unsigned long *stack, struct stack_info *info)
|
||||
{
|
||||
struct SYSENTER_stack *ss = cpu_SYSENTER_stack(smp_processor_id());
|
||||
struct entry_stack *ss = cpu_entry_stack(smp_processor_id());
|
||||
|
||||
void *begin = ss;
|
||||
void *end = ss + 1;
|
||||
|
@ -53,7 +54,7 @@ bool in_sysenter_stack(unsigned long *stack, struct stack_info *info)
|
|||
if ((void *)stack < begin || (void *)stack >= end)
|
||||
return false;
|
||||
|
||||
info->type = STACK_TYPE_SYSENTER;
|
||||
info->type = STACK_TYPE_ENTRY;
|
||||
info->begin = begin;
|
||||
info->end = end;
|
||||
info->next_sp = NULL;
|
||||
|
@ -111,13 +112,13 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
|
|||
* - task stack
|
||||
* - interrupt stack
|
||||
* - HW exception stacks (double fault, nmi, debug, mce)
|
||||
* - SYSENTER stack
|
||||
* - entry stack
|
||||
*
|
||||
* x86-32 can have up to four stacks:
|
||||
* - task stack
|
||||
* - softirq stack
|
||||
* - hardirq stack
|
||||
* - SYSENTER stack
|
||||
* - entry stack
|
||||
*/
|
||||
for (regs = NULL; stack; stack = PTR_ALIGN(stack_info.next_sp, sizeof(long))) {
|
||||
const char *stack_name;
|
||||
|
|
|
@ -26,8 +26,8 @@ const char *stack_type_name(enum stack_type type)
|
|||
if (type == STACK_TYPE_SOFTIRQ)
|
||||
return "SOFTIRQ";
|
||||
|
||||
if (type == STACK_TYPE_SYSENTER)
|
||||
return "SYSENTER";
|
||||
if (type == STACK_TYPE_ENTRY)
|
||||
return "ENTRY_TRAMPOLINE";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
|
|||
if (task != current)
|
||||
goto unknown;
|
||||
|
||||
if (in_sysenter_stack(stack, info))
|
||||
if (in_entry_stack(stack, info))
|
||||
goto recursion_check;
|
||||
|
||||
if (in_hardirq_stack(stack, info))
|
||||
|
|
|
@ -37,8 +37,14 @@ const char *stack_type_name(enum stack_type type)
|
|||
if (type == STACK_TYPE_IRQ)
|
||||
return "IRQ";
|
||||
|
||||
if (type == STACK_TYPE_SYSENTER)
|
||||
return "SYSENTER";
|
||||
if (type == STACK_TYPE_ENTRY) {
|
||||
/*
|
||||
* On 64-bit, we have a generic entry stack that we
|
||||
* use for all the kernel entry points, including
|
||||
* SYSENTER.
|
||||
*/
|
||||
return "ENTRY_TRAMPOLINE";
|
||||
}
|
||||
|
||||
if (type >= STACK_TYPE_EXCEPTION && type <= STACK_TYPE_EXCEPTION_LAST)
|
||||
return exception_stack_names[type - STACK_TYPE_EXCEPTION];
|
||||
|
@ -118,7 +124,7 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
|
|||
if (in_irq_stack(stack, info))
|
||||
goto recursion_check;
|
||||
|
||||
if (in_sysenter_stack(stack, info))
|
||||
if (in_entry_stack(stack, info))
|
||||
goto recursion_check;
|
||||
|
||||
goto unknown;
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
* Copyright (C) 2002 Andi Kleen
|
||||
*
|
||||
* This handles calls from both 32bit and 64bit mode.
|
||||
*
|
||||
* Lock order:
|
||||
* contex.ldt_usr_sem
|
||||
* mmap_sem
|
||||
* context.lock
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
@ -42,7 +47,7 @@ static void refresh_ldt_segments(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* context.lock is held for us, so we don't need any locking. */
|
||||
/* context.lock is held by the task which issued the smp function call */
|
||||
static void flush_ldt(void *__mm)
|
||||
{
|
||||
struct mm_struct *mm = __mm;
|
||||
|
@ -99,15 +104,17 @@ static void finalize_ldt_struct(struct ldt_struct *ldt)
|
|||
paravirt_alloc_ldt(ldt->entries, ldt->nr_entries);
|
||||
}
|
||||
|
||||
/* context.lock is held */
|
||||
static void install_ldt(struct mm_struct *current_mm,
|
||||
struct ldt_struct *ldt)
|
||||
static void install_ldt(struct mm_struct *mm, struct ldt_struct *ldt)
|
||||
{
|
||||
/* Synchronizes with READ_ONCE in load_mm_ldt. */
|
||||
smp_store_release(¤t_mm->context.ldt, ldt);
|
||||
mutex_lock(&mm->context.lock);
|
||||
|
||||
/* Activate the LDT for all CPUs using current_mm. */
|
||||
on_each_cpu_mask(mm_cpumask(current_mm), flush_ldt, current_mm, true);
|
||||
/* Synchronizes with READ_ONCE in load_mm_ldt. */
|
||||
smp_store_release(&mm->context.ldt, ldt);
|
||||
|
||||
/* Activate the LDT for all CPUs using currents mm. */
|
||||
on_each_cpu_mask(mm_cpumask(mm), flush_ldt, mm, true);
|
||||
|
||||
mutex_unlock(&mm->context.lock);
|
||||
}
|
||||
|
||||
static void free_ldt_struct(struct ldt_struct *ldt)
|
||||
|
@ -124,27 +131,20 @@ static void free_ldt_struct(struct ldt_struct *ldt)
|
|||
}
|
||||
|
||||
/*
|
||||
* we do not have to muck with descriptors here, that is
|
||||
* done in switch_mm() as needed.
|
||||
* Called on fork from arch_dup_mmap(). Just copy the current LDT state,
|
||||
* the new task is not running, so nothing can be installed.
|
||||
*/
|
||||
int init_new_context_ldt(struct task_struct *tsk, struct mm_struct *mm)
|
||||
int ldt_dup_context(struct mm_struct *old_mm, struct mm_struct *mm)
|
||||
{
|
||||
struct ldt_struct *new_ldt;
|
||||
struct mm_struct *old_mm;
|
||||
int retval = 0;
|
||||
|
||||
mutex_init(&mm->context.lock);
|
||||
old_mm = current->mm;
|
||||
if (!old_mm) {
|
||||
mm->context.ldt = NULL;
|
||||
if (!old_mm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&old_mm->context.lock);
|
||||
if (!old_mm->context.ldt) {
|
||||
mm->context.ldt = NULL;
|
||||
if (!old_mm->context.ldt)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
new_ldt = alloc_ldt_struct(old_mm->context.ldt->nr_entries);
|
||||
if (!new_ldt) {
|
||||
|
@ -180,7 +180,7 @@ static int read_ldt(void __user *ptr, unsigned long bytecount)
|
|||
unsigned long entries_size;
|
||||
int retval;
|
||||
|
||||
mutex_lock(&mm->context.lock);
|
||||
down_read(&mm->context.ldt_usr_sem);
|
||||
|
||||
if (!mm->context.ldt) {
|
||||
retval = 0;
|
||||
|
@ -209,7 +209,7 @@ static int read_ldt(void __user *ptr, unsigned long bytecount)
|
|||
retval = bytecount;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&mm->context.lock);
|
||||
up_read(&mm->context.ldt_usr_sem);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,8 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
|
|||
ldt.avl = 0;
|
||||
}
|
||||
|
||||
mutex_lock(&mm->context.lock);
|
||||
if (down_write_killable(&mm->context.ldt_usr_sem))
|
||||
return -EINTR;
|
||||
|
||||
old_ldt = mm->context.ldt;
|
||||
old_nr_entries = old_ldt ? old_ldt->nr_entries : 0;
|
||||
|
@ -291,7 +292,7 @@ static int write_ldt(void __user *ptr, unsigned long bytecount, int oldmode)
|
|||
error = 0;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&mm->context.lock);
|
||||
up_write(&mm->context.ldt_usr_sem);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -932,12 +932,8 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle,
|
|||
initial_code = (unsigned long)start_secondary;
|
||||
initial_stack = idle->thread.sp;
|
||||
|
||||
/*
|
||||
* Enable the espfix hack for this CPU
|
||||
*/
|
||||
#ifdef CONFIG_X86_ESPFIX64
|
||||
/* Enable the espfix hack for this CPU */
|
||||
init_espfix_ap(cpu);
|
||||
#endif
|
||||
|
||||
/* So we see what's up */
|
||||
announce_cpu(cpu, apicid);
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include <asm/traps.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/fpu/internal.h>
|
||||
#include <asm/cpu_entry_area.h>
|
||||
#include <asm/mce.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/mach_traps.h>
|
||||
|
@ -951,8 +952,9 @@ void __init trap_init(void)
|
|||
* "sidt" instruction will not leak the location of the kernel, and
|
||||
* to defend the IDT against arbitrary memory write vulnerabilities.
|
||||
* It will be reloaded in cpu_init() */
|
||||
__set_fixmap(FIX_RO_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
|
||||
idt_descr.address = fix_to_virt(FIX_RO_IDT);
|
||||
cea_set_pte(CPU_ENTRY_AREA_RO_IDT_VADDR, __pa_symbol(idt_table),
|
||||
PAGE_KERNEL_RO);
|
||||
idt_descr.address = CPU_ENTRY_AREA_RO_IDT;
|
||||
|
||||
/*
|
||||
* Should be a barrier for any external CPU state:
|
||||
|
|
|
@ -10,7 +10,7 @@ CFLAGS_REMOVE_mem_encrypt.o = -pg
|
|||
endif
|
||||
|
||||
obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
|
||||
pat.o pgtable.o physaddr.o setup_nx.o tlb.o
|
||||
pat.o pgtable.o physaddr.o setup_nx.o tlb.o cpu_entry_area.o
|
||||
|
||||
# Make sure __phys_addr has no stackprotector
|
||||
nostackp := $(call cc-option, -fno-stack-protector)
|
||||
|
|
139
arch/x86/mm/cpu_entry_area.c
Normal file
139
arch/x86/mm/cpu_entry_area.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/percpu.h>
|
||||
|
||||
#include <asm/cpu_entry_area.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/desc.h>
|
||||
|
||||
static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
|
||||
[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
|
||||
#endif
|
||||
|
||||
struct cpu_entry_area *get_cpu_entry_area(int cpu)
|
||||
{
|
||||
unsigned long va = CPU_ENTRY_AREA_PER_CPU + cpu * CPU_ENTRY_AREA_SIZE;
|
||||
BUILD_BUG_ON(sizeof(struct cpu_entry_area) % PAGE_SIZE != 0);
|
||||
|
||||
return (struct cpu_entry_area *) va;
|
||||
}
|
||||
EXPORT_SYMBOL(get_cpu_entry_area);
|
||||
|
||||
void cea_set_pte(void *cea_vaddr, phys_addr_t pa, pgprot_t flags)
|
||||
{
|
||||
unsigned long va = (unsigned long) cea_vaddr;
|
||||
|
||||
set_pte_vaddr(va, pfn_pte(pa >> PAGE_SHIFT, flags));
|
||||
}
|
||||
|
||||
static void __init
|
||||
cea_map_percpu_pages(void *cea_vaddr, void *ptr, int pages, pgprot_t prot)
|
||||
{
|
||||
for ( ; pages; pages--, cea_vaddr+= PAGE_SIZE, ptr += PAGE_SIZE)
|
||||
cea_set_pte(cea_vaddr, per_cpu_ptr_to_phys(ptr), prot);
|
||||
}
|
||||
|
||||
/* Setup the fixmap mappings only once per-processor */
|
||||
static void __init setup_cpu_entry_area(int cpu)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
extern char _entry_trampoline[];
|
||||
|
||||
/* On 64-bit systems, we use a read-only fixmap GDT and TSS. */
|
||||
pgprot_t gdt_prot = PAGE_KERNEL_RO;
|
||||
pgprot_t tss_prot = PAGE_KERNEL_RO;
|
||||
#else
|
||||
/*
|
||||
* On native 32-bit systems, the GDT cannot be read-only because
|
||||
* our double fault handler uses a task gate, and entering through
|
||||
* a task gate needs to change an available TSS to busy. If the
|
||||
* GDT is read-only, that will triple fault. The TSS cannot be
|
||||
* read-only because the CPU writes to it on task switches.
|
||||
*
|
||||
* On Xen PV, the GDT must be read-only because the hypervisor
|
||||
* requires it.
|
||||
*/
|
||||
pgprot_t gdt_prot = boot_cpu_has(X86_FEATURE_XENPV) ?
|
||||
PAGE_KERNEL_RO : PAGE_KERNEL;
|
||||
pgprot_t tss_prot = PAGE_KERNEL;
|
||||
#endif
|
||||
|
||||
cea_set_pte(&get_cpu_entry_area(cpu)->gdt, get_cpu_gdt_paddr(cpu),
|
||||
gdt_prot);
|
||||
|
||||
cea_map_percpu_pages(&get_cpu_entry_area(cpu)->entry_stack_page,
|
||||
per_cpu_ptr(&entry_stack_storage, cpu), 1,
|
||||
PAGE_KERNEL);
|
||||
|
||||
/*
|
||||
* The Intel SDM says (Volume 3, 7.2.1):
|
||||
*
|
||||
* Avoid placing a page boundary in the part of the TSS that the
|
||||
* processor reads during a task switch (the first 104 bytes). The
|
||||
* processor may not correctly perform address translations if a
|
||||
* boundary occurs in this area. During a task switch, the processor
|
||||
* reads and writes into the first 104 bytes of each TSS (using
|
||||
* contiguous physical addresses beginning with the physical address
|
||||
* of the first byte of the TSS). So, after TSS access begins, if
|
||||
* part of the 104 bytes is not physically contiguous, the processor
|
||||
* will access incorrect information without generating a page-fault
|
||||
* exception.
|
||||
*
|
||||
* There are also a lot of errata involving the TSS spanning a page
|
||||
* boundary. Assert that we're not doing that.
|
||||
*/
|
||||
BUILD_BUG_ON((offsetof(struct tss_struct, x86_tss) ^
|
||||
offsetofend(struct tss_struct, x86_tss)) & PAGE_MASK);
|
||||
BUILD_BUG_ON(sizeof(struct tss_struct) % PAGE_SIZE != 0);
|
||||
cea_map_percpu_pages(&get_cpu_entry_area(cpu)->tss,
|
||||
&per_cpu(cpu_tss_rw, cpu),
|
||||
sizeof(struct tss_struct) / PAGE_SIZE, tss_prot);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
per_cpu(cpu_entry_area, cpu) = get_cpu_entry_area(cpu);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
BUILD_BUG_ON(sizeof(exception_stacks) % PAGE_SIZE != 0);
|
||||
BUILD_BUG_ON(sizeof(exception_stacks) !=
|
||||
sizeof(((struct cpu_entry_area *)0)->exception_stacks));
|
||||
cea_map_percpu_pages(&get_cpu_entry_area(cpu)->exception_stacks,
|
||||
&per_cpu(exception_stacks, cpu),
|
||||
sizeof(exception_stacks) / PAGE_SIZE, PAGE_KERNEL);
|
||||
|
||||
cea_set_pte(&get_cpu_entry_area(cpu)->entry_trampoline,
|
||||
__pa_symbol(_entry_trampoline), PAGE_KERNEL_RX);
|
||||
#endif
|
||||
}
|
||||
|
||||
static __init void setup_cpu_entry_area_ptes(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_32
|
||||
unsigned long start, end;
|
||||
|
||||
BUILD_BUG_ON(CPU_ENTRY_AREA_PAGES * PAGE_SIZE < CPU_ENTRY_AREA_MAP_SIZE);
|
||||
BUG_ON(CPU_ENTRY_AREA_BASE & ~PMD_MASK);
|
||||
|
||||
start = CPU_ENTRY_AREA_BASE;
|
||||
end = start + CPU_ENTRY_AREA_MAP_SIZE;
|
||||
|
||||
/* Careful here: start + PMD_SIZE might wrap around */
|
||||
for (; start < end && start >= CPU_ENTRY_AREA_BASE; start += PMD_SIZE)
|
||||
populate_extra_pte(start);
|
||||
#endif
|
||||
}
|
||||
|
||||
void __init setup_cpu_entry_areas(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
setup_cpu_entry_area_ptes();
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
setup_cpu_entry_area(cpu);
|
||||
}
|
|
@ -44,10 +44,12 @@ struct addr_marker {
|
|||
unsigned long max_lines;
|
||||
};
|
||||
|
||||
/* indices for address_markers; keep sync'd w/ address_markers below */
|
||||
/* Address space markers hints */
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
enum address_markers_idx {
|
||||
USER_SPACE_NR = 0,
|
||||
#ifdef CONFIG_X86_64
|
||||
KERNEL_SPACE_NR,
|
||||
LOW_KERNEL_NR,
|
||||
VMALLOC_START_NR,
|
||||
|
@ -56,56 +58,74 @@ enum address_markers_idx {
|
|||
KASAN_SHADOW_START_NR,
|
||||
KASAN_SHADOW_END_NR,
|
||||
#endif
|
||||
# ifdef CONFIG_X86_ESPFIX64
|
||||
CPU_ENTRY_AREA_NR,
|
||||
#ifdef CONFIG_X86_ESPFIX64
|
||||
ESPFIX_START_NR,
|
||||
# endif
|
||||
#endif
|
||||
#ifdef CONFIG_EFI
|
||||
EFI_END_NR,
|
||||
#endif
|
||||
HIGH_KERNEL_NR,
|
||||
MODULES_VADDR_NR,
|
||||
MODULES_END_NR,
|
||||
#else
|
||||
FIXADDR_START_NR,
|
||||
END_OF_SPACE_NR,
|
||||
};
|
||||
|
||||
static struct addr_marker address_markers[] = {
|
||||
[USER_SPACE_NR] = { 0, "User Space" },
|
||||
[KERNEL_SPACE_NR] = { (1UL << 63), "Kernel Space" },
|
||||
[LOW_KERNEL_NR] = { 0UL, "Low Kernel Mapping" },
|
||||
[VMALLOC_START_NR] = { 0UL, "vmalloc() Area" },
|
||||
[VMEMMAP_START_NR] = { 0UL, "Vmemmap" },
|
||||
#ifdef CONFIG_KASAN
|
||||
[KASAN_SHADOW_START_NR] = { KASAN_SHADOW_START, "KASAN shadow" },
|
||||
[KASAN_SHADOW_END_NR] = { KASAN_SHADOW_END, "KASAN shadow end" },
|
||||
#endif
|
||||
[CPU_ENTRY_AREA_NR] = { CPU_ENTRY_AREA_BASE,"CPU entry Area" },
|
||||
#ifdef CONFIG_X86_ESPFIX64
|
||||
[ESPFIX_START_NR] = { ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
|
||||
#endif
|
||||
#ifdef CONFIG_EFI
|
||||
[EFI_END_NR] = { EFI_VA_END, "EFI Runtime Services" },
|
||||
#endif
|
||||
[HIGH_KERNEL_NR] = { __START_KERNEL_map, "High Kernel Mapping" },
|
||||
[MODULES_VADDR_NR] = { MODULES_VADDR, "Modules" },
|
||||
[MODULES_END_NR] = { MODULES_END, "End Modules" },
|
||||
[FIXADDR_START_NR] = { FIXADDR_START, "Fixmap Area" },
|
||||
[END_OF_SPACE_NR] = { -1, NULL }
|
||||
};
|
||||
|
||||
#else /* CONFIG_X86_64 */
|
||||
|
||||
enum address_markers_idx {
|
||||
USER_SPACE_NR = 0,
|
||||
KERNEL_SPACE_NR,
|
||||
VMALLOC_START_NR,
|
||||
VMALLOC_END_NR,
|
||||
# ifdef CONFIG_HIGHMEM
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
PKMAP_BASE_NR,
|
||||
# endif
|
||||
FIXADDR_START_NR,
|
||||
#endif
|
||||
CPU_ENTRY_AREA_NR,
|
||||
FIXADDR_START_NR,
|
||||
END_OF_SPACE_NR,
|
||||
};
|
||||
|
||||
/* Address space markers hints */
|
||||
static struct addr_marker address_markers[] = {
|
||||
{ 0, "User Space" },
|
||||
#ifdef CONFIG_X86_64
|
||||
{ 0x8000000000000000UL, "Kernel Space" },
|
||||
{ 0/* PAGE_OFFSET */, "Low Kernel Mapping" },
|
||||
{ 0/* VMALLOC_START */, "vmalloc() Area" },
|
||||
{ 0/* VMEMMAP_START */, "Vmemmap" },
|
||||
#ifdef CONFIG_KASAN
|
||||
{ KASAN_SHADOW_START, "KASAN shadow" },
|
||||
{ KASAN_SHADOW_END, "KASAN shadow end" },
|
||||
[USER_SPACE_NR] = { 0, "User Space" },
|
||||
[KERNEL_SPACE_NR] = { PAGE_OFFSET, "Kernel Mapping" },
|
||||
[VMALLOC_START_NR] = { 0UL, "vmalloc() Area" },
|
||||
[VMALLOC_END_NR] = { 0UL, "vmalloc() End" },
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
[PKMAP_BASE_NR] = { 0UL, "Persistent kmap() Area" },
|
||||
#endif
|
||||
# ifdef CONFIG_X86_ESPFIX64
|
||||
{ ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
|
||||
# endif
|
||||
# ifdef CONFIG_EFI
|
||||
{ EFI_VA_END, "EFI Runtime Services" },
|
||||
# endif
|
||||
{ __START_KERNEL_map, "High Kernel Mapping" },
|
||||
{ MODULES_VADDR, "Modules" },
|
||||
{ MODULES_END, "End Modules" },
|
||||
#else
|
||||
{ PAGE_OFFSET, "Kernel Mapping" },
|
||||
{ 0/* VMALLOC_START */, "vmalloc() Area" },
|
||||
{ 0/*VMALLOC_END*/, "vmalloc() End" },
|
||||
# ifdef CONFIG_HIGHMEM
|
||||
{ 0/*PKMAP_BASE*/, "Persistent kmap() Area" },
|
||||
# endif
|
||||
{ 0/*FIXADDR_START*/, "Fixmap Area" },
|
||||
#endif
|
||||
{ -1, NULL } /* End of list */
|
||||
[CPU_ENTRY_AREA_NR] = { 0UL, "CPU entry area" },
|
||||
[FIXADDR_START_NR] = { 0UL, "Fixmap area" },
|
||||
[END_OF_SPACE_NR] = { -1, NULL }
|
||||
};
|
||||
|
||||
#endif /* !CONFIG_X86_64 */
|
||||
|
||||
/* Multipliers for offsets within the PTEs */
|
||||
#define PTE_LEVEL_MULT (PAGE_SIZE)
|
||||
#define PMD_LEVEL_MULT (PTRS_PER_PTE * PTE_LEVEL_MULT)
|
||||
|
@ -140,7 +160,7 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
|
|||
static const char * const level_name[] =
|
||||
{ "cr3", "pgd", "p4d", "pud", "pmd", "pte" };
|
||||
|
||||
if (!pgprot_val(prot)) {
|
||||
if (!(pr & _PAGE_PRESENT)) {
|
||||
/* Not present */
|
||||
pt_dump_cont_printf(m, dmsg, " ");
|
||||
} else {
|
||||
|
@ -525,8 +545,8 @@ static int __init pt_dump_init(void)
|
|||
address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE;
|
||||
# endif
|
||||
address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
|
||||
address_markers[CPU_ENTRY_AREA_NR].start_address = CPU_ENTRY_AREA_BASE;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(pt_dump_init);
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <asm/setup.h>
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/page_types.h>
|
||||
#include <asm/cpu_entry_area.h>
|
||||
#include <asm/init.h>
|
||||
|
||||
#include "mm_internal.h"
|
||||
|
@ -766,6 +767,7 @@ void __init mem_init(void)
|
|||
mem_init_print_info(NULL);
|
||||
printk(KERN_INFO "virtual kernel memory layout:\n"
|
||||
" fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
|
||||
" cpu_entry : 0x%08lx - 0x%08lx (%4ld kB)\n"
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
" pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
|
||||
#endif
|
||||
|
@ -777,6 +779,10 @@ void __init mem_init(void)
|
|||
FIXADDR_START, FIXADDR_TOP,
|
||||
(FIXADDR_TOP - FIXADDR_START) >> 10,
|
||||
|
||||
CPU_ENTRY_AREA_BASE,
|
||||
CPU_ENTRY_AREA_BASE + CPU_ENTRY_AREA_MAP_SIZE,
|
||||
CPU_ENTRY_AREA_MAP_SIZE >> 10,
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE,
|
||||
(LAST_PKMAP*PAGE_SIZE) >> 10,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <asm/tlbflush.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/cpu_entry_area.h>
|
||||
|
||||
extern struct range pfn_mapped[E820_MAX_ENTRIES];
|
||||
|
||||
|
@ -322,31 +323,33 @@ void __init kasan_init(void)
|
|||
map_range(&pfn_mapped[i]);
|
||||
}
|
||||
|
||||
shadow_cpu_entry_begin = (void *)CPU_ENTRY_AREA_BASE;
|
||||
shadow_cpu_entry_begin = kasan_mem_to_shadow(shadow_cpu_entry_begin);
|
||||
shadow_cpu_entry_begin = (void *)round_down((unsigned long)shadow_cpu_entry_begin,
|
||||
PAGE_SIZE);
|
||||
|
||||
shadow_cpu_entry_end = (void *)(CPU_ENTRY_AREA_BASE +
|
||||
CPU_ENTRY_AREA_MAP_SIZE);
|
||||
shadow_cpu_entry_end = kasan_mem_to_shadow(shadow_cpu_entry_end);
|
||||
shadow_cpu_entry_end = (void *)round_up((unsigned long)shadow_cpu_entry_end,
|
||||
PAGE_SIZE);
|
||||
|
||||
kasan_populate_zero_shadow(
|
||||
kasan_mem_to_shadow((void *)PAGE_OFFSET + MAXMEM),
|
||||
kasan_mem_to_shadow((void *)__START_KERNEL_map));
|
||||
shadow_cpu_entry_begin);
|
||||
|
||||
kasan_populate_shadow((unsigned long)shadow_cpu_entry_begin,
|
||||
(unsigned long)shadow_cpu_entry_end, 0);
|
||||
|
||||
kasan_populate_zero_shadow(shadow_cpu_entry_end,
|
||||
kasan_mem_to_shadow((void *)__START_KERNEL_map));
|
||||
|
||||
kasan_populate_shadow((unsigned long)kasan_mem_to_shadow(_stext),
|
||||
(unsigned long)kasan_mem_to_shadow(_end),
|
||||
early_pfn_to_nid(__pa(_stext)));
|
||||
|
||||
shadow_cpu_entry_begin = (void *)__fix_to_virt(FIX_CPU_ENTRY_AREA_BOTTOM);
|
||||
shadow_cpu_entry_begin = kasan_mem_to_shadow(shadow_cpu_entry_begin);
|
||||
shadow_cpu_entry_begin = (void *)round_down((unsigned long)shadow_cpu_entry_begin,
|
||||
PAGE_SIZE);
|
||||
|
||||
shadow_cpu_entry_end = (void *)(__fix_to_virt(FIX_CPU_ENTRY_AREA_TOP) + PAGE_SIZE);
|
||||
shadow_cpu_entry_end = kasan_mem_to_shadow(shadow_cpu_entry_end);
|
||||
shadow_cpu_entry_end = (void *)round_up((unsigned long)shadow_cpu_entry_end,
|
||||
PAGE_SIZE);
|
||||
|
||||
kasan_populate_zero_shadow(kasan_mem_to_shadow((void *)MODULES_END),
|
||||
shadow_cpu_entry_begin);
|
||||
|
||||
kasan_populate_shadow((unsigned long)shadow_cpu_entry_begin,
|
||||
(unsigned long)shadow_cpu_entry_end, 0);
|
||||
|
||||
kasan_populate_zero_shadow(shadow_cpu_entry_end, (void *)KASAN_SHADOW_END);
|
||||
(void *)KASAN_SHADOW_END);
|
||||
|
||||
load_cr3(init_top_pgt);
|
||||
__flush_tlb_all();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/pagemap.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/cpu_entry_area.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/fixmap.h>
|
||||
|
|
|
@ -128,7 +128,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
|
|||
* isn't free.
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_VM
|
||||
if (WARN_ON_ONCE(__read_cr3() != build_cr3(real_prev, prev_asid))) {
|
||||
if (WARN_ON_ONCE(__read_cr3() != build_cr3(real_prev->pgd, prev_asid))) {
|
||||
/*
|
||||
* If we were to BUG here, we'd be very likely to kill
|
||||
* the system so hard that we don't see the call trace.
|
||||
|
@ -195,7 +195,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
|
|||
if (need_flush) {
|
||||
this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id);
|
||||
this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen);
|
||||
write_cr3(build_cr3(next, new_asid));
|
||||
write_cr3(build_cr3(next->pgd, new_asid));
|
||||
|
||||
/*
|
||||
* NB: This gets called via leave_mm() in the idle path
|
||||
|
@ -208,7 +208,7 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
|
|||
trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
|
||||
} else {
|
||||
/* The new ASID is already up to date. */
|
||||
write_cr3(build_cr3_noflush(next, new_asid));
|
||||
write_cr3(build_cr3_noflush(next->pgd, new_asid));
|
||||
|
||||
/* See above wrt _rcuidle. */
|
||||
trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, 0);
|
||||
|
@ -288,7 +288,7 @@ void initialize_tlbstate_and_flush(void)
|
|||
!(cr4_read_shadow() & X86_CR4_PCIDE));
|
||||
|
||||
/* Force ASID 0 and force a TLB flush. */
|
||||
write_cr3(build_cr3(mm, 0));
|
||||
write_cr3(build_cr3(mm->pgd, 0));
|
||||
|
||||
/* Reinitialize tlbstate. */
|
||||
this_cpu_write(cpu_tlbstate.loaded_mm_asid, 0);
|
||||
|
@ -551,7 +551,7 @@ static void do_kernel_range_flush(void *info)
|
|||
|
||||
/* flush range by one by one 'invlpg' */
|
||||
for (addr = f->start; addr < f->end; addr += PAGE_SIZE)
|
||||
__flush_tlb_single(addr);
|
||||
__flush_tlb_one(addr);
|
||||
}
|
||||
|
||||
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
|
|
|
@ -299,7 +299,7 @@ static void bau_process_message(struct msg_desc *mdp, struct bau_control *bcp,
|
|||
local_flush_tlb();
|
||||
stat->d_alltlb++;
|
||||
} else {
|
||||
__flush_tlb_one(msg->address);
|
||||
__flush_tlb_single(msg->address);
|
||||
stat->d_onetlb++;
|
||||
}
|
||||
stat->d_requestee++;
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
|
||||
#include <linux/bootmem.h>
|
||||
#endif
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/kexec.h>
|
||||
|
||||
#include <xen/features.h>
|
||||
#include <xen/page.h>
|
||||
#include <xen/interface/memory.h>
|
||||
|
||||
#include <asm/xen/hypercall.h>
|
||||
#include <asm/xen/hypervisor.h>
|
||||
|
@ -331,3 +335,80 @@ void xen_arch_unregister_cpu(int num)
|
|||
}
|
||||
EXPORT_SYMBOL(xen_arch_unregister_cpu);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
|
||||
void __init arch_xen_balloon_init(struct resource *hostmem_resource)
|
||||
{
|
||||
struct xen_memory_map memmap;
|
||||
int rc;
|
||||
unsigned int i, last_guest_ram;
|
||||
phys_addr_t max_addr = PFN_PHYS(max_pfn);
|
||||
struct e820_table *xen_e820_table;
|
||||
const struct e820_entry *entry;
|
||||
struct resource *res;
|
||||
|
||||
if (!xen_initial_domain())
|
||||
return;
|
||||
|
||||
xen_e820_table = kmalloc(sizeof(*xen_e820_table), GFP_KERNEL);
|
||||
if (!xen_e820_table)
|
||||
return;
|
||||
|
||||
memmap.nr_entries = ARRAY_SIZE(xen_e820_table->entries);
|
||||
set_xen_guest_handle(memmap.buffer, xen_e820_table->entries);
|
||||
rc = HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap);
|
||||
if (rc) {
|
||||
pr_warn("%s: Can't read host e820 (%d)\n", __func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
last_guest_ram = 0;
|
||||
for (i = 0; i < memmap.nr_entries; i++) {
|
||||
if (xen_e820_table->entries[i].addr >= max_addr)
|
||||
break;
|
||||
if (xen_e820_table->entries[i].type == E820_TYPE_RAM)
|
||||
last_guest_ram = i;
|
||||
}
|
||||
|
||||
entry = &xen_e820_table->entries[last_guest_ram];
|
||||
if (max_addr >= entry->addr + entry->size)
|
||||
goto out; /* No unallocated host RAM. */
|
||||
|
||||
hostmem_resource->start = max_addr;
|
||||
hostmem_resource->end = entry->addr + entry->size;
|
||||
|
||||
/*
|
||||
* Mark non-RAM regions between the end of dom0 RAM and end of host RAM
|
||||
* as unavailable. The rest of that region can be used for hotplug-based
|
||||
* ballooning.
|
||||
*/
|
||||
for (; i < memmap.nr_entries; i++) {
|
||||
entry = &xen_e820_table->entries[i];
|
||||
|
||||
if (entry->type == E820_TYPE_RAM)
|
||||
continue;
|
||||
|
||||
if (entry->addr >= hostmem_resource->end)
|
||||
break;
|
||||
|
||||
res = kzalloc(sizeof(*res), GFP_KERNEL);
|
||||
if (!res)
|
||||
goto out;
|
||||
|
||||
res->name = "Unavailable host RAM";
|
||||
res->start = entry->addr;
|
||||
res->end = (entry->addr + entry->size < hostmem_resource->end) ?
|
||||
entry->addr + entry->size : hostmem_resource->end;
|
||||
rc = insert_resource(hostmem_resource, res);
|
||||
if (rc) {
|
||||
pr_warn("%s: Can't insert [%llx - %llx) (%d)\n",
|
||||
__func__, res->start, res->end, rc);
|
||||
kfree(res);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(xen_e820_table);
|
||||
}
|
||||
#endif /* CONFIG_XEN_BALLOON_MEMORY_HOTPLUG */
|
||||
|
|
|
@ -88,6 +88,8 @@
|
|||
#include "multicalls.h"
|
||||
#include "pmu.h"
|
||||
|
||||
#include "../kernel/cpu/cpu.h" /* get_cpu_cap() */
|
||||
|
||||
void *xen_initial_gdt;
|
||||
|
||||
static int xen_cpu_up_prepare_pv(unsigned int cpu);
|
||||
|
@ -1258,6 +1260,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
|
|||
__userpte_alloc_gfp &= ~__GFP_HIGHMEM;
|
||||
|
||||
/* Work out if we support NX */
|
||||
get_cpu_cap(&boot_cpu_data);
|
||||
x86_configure_nx();
|
||||
|
||||
/* Get mfn list */
|
||||
|
|
|
@ -1902,6 +1902,18 @@ void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
|
|||
/* Graft it onto L4[511][510] */
|
||||
copy_page(level2_kernel_pgt, l2);
|
||||
|
||||
/*
|
||||
* Zap execute permission from the ident map. Due to the sharing of
|
||||
* L1 entries we need to do this in the L2.
|
||||
*/
|
||||
if (__supported_pte_mask & _PAGE_NX) {
|
||||
for (i = 0; i < PTRS_PER_PMD; ++i) {
|
||||
if (pmd_none(level2_ident_pgt[i]))
|
||||
continue;
|
||||
level2_ident_pgt[i] = pmd_set_flags(level2_ident_pgt[i], _PAGE_NX);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the initial P->M table mappings if necessary. */
|
||||
i = pgd_index(xen_start_info->mfn_list);
|
||||
if (i && i < pgd_index(__START_KERNEL_map))
|
||||
|
@ -2261,7 +2273,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
|
|||
|
||||
switch (idx) {
|
||||
case FIX_BTMAP_END ... FIX_BTMAP_BEGIN:
|
||||
case FIX_RO_IDT:
|
||||
#ifdef CONFIG_X86_32
|
||||
case FIX_WP_TEST:
|
||||
# ifdef CONFIG_HIGHMEM
|
||||
|
@ -2272,7 +2283,6 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
|
|||
#endif
|
||||
case FIX_TEXT_POKE0:
|
||||
case FIX_TEXT_POKE1:
|
||||
case FIX_CPU_ENTRY_AREA_TOP ... FIX_CPU_ENTRY_AREA_BOTTOM:
|
||||
/* All local page mappings */
|
||||
pte = pfn_pte(phys, prot);
|
||||
break;
|
||||
|
|
|
@ -808,7 +808,6 @@ char * __init xen_memory_setup(void)
|
|||
addr = xen_e820_table.entries[0].addr;
|
||||
size = xen_e820_table.entries[0].size;
|
||||
while (i < xen_e820_table.nr_entries) {
|
||||
bool discard = false;
|
||||
|
||||
chunk_size = size;
|
||||
type = xen_e820_table.entries[i].type;
|
||||
|
@ -824,11 +823,10 @@ char * __init xen_memory_setup(void)
|
|||
xen_add_extra_mem(pfn_s, n_pfns);
|
||||
xen_max_p2m_pfn = pfn_s + n_pfns;
|
||||
} else
|
||||
discard = true;
|
||||
type = E820_TYPE_UNUSABLE;
|
||||
}
|
||||
|
||||
if (!discard)
|
||||
xen_align_and_add_e820_region(addr, chunk_size, type);
|
||||
xen_align_and_add_e820_region(addr, chunk_size, type);
|
||||
|
||||
addr += chunk_size;
|
||||
size -= chunk_size;
|
||||
|
|
|
@ -1138,12 +1138,6 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags,
|
|||
if (!af_alg_readable(sk))
|
||||
break;
|
||||
|
||||
if (!ctx->used) {
|
||||
err = af_alg_wait_for_data(sk, flags);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
seglen = min_t(size_t, (maxsize - len),
|
||||
msg_data_left(msg));
|
||||
|
||||
|
|
|
@ -111,6 +111,12 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
size_t usedpages = 0; /* [in] RX bufs to be used from user */
|
||||
size_t processed = 0; /* [in] TX bufs to be consumed */
|
||||
|
||||
if (!ctx->used) {
|
||||
err = af_alg_wait_for_data(sk, flags);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data length provided by caller via sendmsg/sendpage that has not
|
||||
* yet been processed.
|
||||
|
@ -285,6 +291,10 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
/* AIO operation */
|
||||
sock_hold(sk);
|
||||
areq->iocb = msg->msg_iocb;
|
||||
|
||||
/* Remember output size that will be generated. */
|
||||
areq->outlen = outlen;
|
||||
|
||||
aead_request_set_callback(&areq->cra_u.aead_req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
af_alg_async_cb, areq);
|
||||
|
@ -292,12 +302,8 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
crypto_aead_decrypt(&areq->cra_u.aead_req);
|
||||
|
||||
/* AIO operation in progress */
|
||||
if (err == -EINPROGRESS || err == -EBUSY) {
|
||||
/* Remember output size that will be generated. */
|
||||
areq->outlen = outlen;
|
||||
|
||||
if (err == -EINPROGRESS || err == -EBUSY)
|
||||
return -EIOCBQUEUED;
|
||||
}
|
||||
|
||||
sock_put(sk);
|
||||
} else {
|
||||
|
|
|
@ -72,6 +72,12 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
int err = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if (!ctx->used) {
|
||||
err = af_alg_wait_for_data(sk, flags);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Allocate cipher request for current operation. */
|
||||
areq = af_alg_alloc_areq(sk, sizeof(struct af_alg_async_req) +
|
||||
crypto_skcipher_reqsize(tfm));
|
||||
|
@ -119,6 +125,10 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
/* AIO operation */
|
||||
sock_hold(sk);
|
||||
areq->iocb = msg->msg_iocb;
|
||||
|
||||
/* Remember output size that will be generated. */
|
||||
areq->outlen = len;
|
||||
|
||||
skcipher_request_set_callback(&areq->cra_u.skcipher_req,
|
||||
CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
af_alg_async_cb, areq);
|
||||
|
@ -127,12 +137,8 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
crypto_skcipher_decrypt(&areq->cra_u.skcipher_req);
|
||||
|
||||
/* AIO operation in progress */
|
||||
if (err == -EINPROGRESS || err == -EBUSY) {
|
||||
/* Remember output size that will be generated. */
|
||||
areq->outlen = len;
|
||||
|
||||
if (err == -EINPROGRESS || err == -EBUSY)
|
||||
return -EIOCBQUEUED;
|
||||
}
|
||||
|
||||
sock_put(sk);
|
||||
} else {
|
||||
|
|
|
@ -81,6 +81,7 @@ static int mcryptd_init_queue(struct mcryptd_queue *queue,
|
|||
pr_debug("cpu_queue #%d %p\n", cpu, queue->cpu_queue);
|
||||
crypto_init_queue(&cpu_queue->queue, max_cpu_qlen);
|
||||
INIT_WORK(&cpu_queue->work, mcryptd_queue_worker);
|
||||
spin_lock_init(&cpu_queue->q_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,15 +105,16 @@ static int mcryptd_enqueue_request(struct mcryptd_queue *queue,
|
|||
int cpu, err;
|
||||
struct mcryptd_cpu_queue *cpu_queue;
|
||||
|
||||
cpu = get_cpu();
|
||||
cpu_queue = this_cpu_ptr(queue->cpu_queue);
|
||||
rctx->tag.cpu = cpu;
|
||||
cpu_queue = raw_cpu_ptr(queue->cpu_queue);
|
||||
spin_lock(&cpu_queue->q_lock);
|
||||
cpu = smp_processor_id();
|
||||
rctx->tag.cpu = smp_processor_id();
|
||||
|
||||
err = crypto_enqueue_request(&cpu_queue->queue, request);
|
||||
pr_debug("enqueue request: cpu %d cpu_queue %p request %p\n",
|
||||
cpu, cpu_queue, request);
|
||||
spin_unlock(&cpu_queue->q_lock);
|
||||
queue_work_on(cpu, kcrypto_wq, &cpu_queue->work);
|
||||
put_cpu();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -161,16 +163,11 @@ static void mcryptd_queue_worker(struct work_struct *work)
|
|||
cpu_queue = container_of(work, struct mcryptd_cpu_queue, work);
|
||||
i = 0;
|
||||
while (i < MCRYPTD_BATCH || single_task_running()) {
|
||||
/*
|
||||
* preempt_disable/enable is used to prevent
|
||||
* being preempted by mcryptd_enqueue_request()
|
||||
*/
|
||||
local_bh_disable();
|
||||
preempt_disable();
|
||||
|
||||
spin_lock_bh(&cpu_queue->q_lock);
|
||||
backlog = crypto_get_backlog(&cpu_queue->queue);
|
||||
req = crypto_dequeue_request(&cpu_queue->queue);
|
||||
preempt_enable();
|
||||
local_bh_enable();
|
||||
spin_unlock_bh(&cpu_queue->q_lock);
|
||||
|
||||
if (!req) {
|
||||
mcryptd_opportunistic_flush();
|
||||
|
@ -185,7 +182,7 @@ static void mcryptd_queue_worker(struct work_struct *work)
|
|||
++i;
|
||||
}
|
||||
if (cpu_queue->queue.qlen)
|
||||
queue_work(kcrypto_wq, &cpu_queue->work);
|
||||
queue_work_on(smp_processor_id(), kcrypto_wq, &cpu_queue->work);
|
||||
}
|
||||
|
||||
void mcryptd_flusher(struct work_struct *__work)
|
||||
|
|
|
@ -449,6 +449,8 @@ static int skcipher_walk_skcipher(struct skcipher_walk *walk,
|
|||
|
||||
walk->total = req->cryptlen;
|
||||
walk->nbytes = 0;
|
||||
walk->iv = req->iv;
|
||||
walk->oiv = req->iv;
|
||||
|
||||
if (unlikely(!walk->total))
|
||||
return 0;
|
||||
|
@ -456,9 +458,6 @@ static int skcipher_walk_skcipher(struct skcipher_walk *walk,
|
|||
scatterwalk_start(&walk->in, req->src);
|
||||
scatterwalk_start(&walk->out, req->dst);
|
||||
|
||||
walk->iv = req->iv;
|
||||
walk->oiv = req->iv;
|
||||
|
||||
walk->flags &= ~SKCIPHER_WALK_SLEEP;
|
||||
walk->flags |= req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ?
|
||||
SKCIPHER_WALK_SLEEP : 0;
|
||||
|
@ -510,6 +509,8 @@ static int skcipher_walk_aead_common(struct skcipher_walk *walk,
|
|||
int err;
|
||||
|
||||
walk->nbytes = 0;
|
||||
walk->iv = req->iv;
|
||||
walk->oiv = req->iv;
|
||||
|
||||
if (unlikely(!walk->total))
|
||||
return 0;
|
||||
|
@ -525,9 +526,6 @@ static int skcipher_walk_aead_common(struct skcipher_walk *walk,
|
|||
scatterwalk_done(&walk->in, 0, walk->total);
|
||||
scatterwalk_done(&walk->out, 0, walk->total);
|
||||
|
||||
walk->iv = req->iv;
|
||||
walk->oiv = req->iv;
|
||||
|
||||
if (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP)
|
||||
walk->flags |= SKCIPHER_WALK_SLEEP;
|
||||
else
|
||||
|
|
|
@ -1670,6 +1670,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
|
|||
dev_name(&adev_dimm->dev));
|
||||
return -ENXIO;
|
||||
}
|
||||
/*
|
||||
* Record nfit_mem for the notification path to track back to
|
||||
* the nfit sysfs attributes for this dimm device object.
|
||||
*/
|
||||
dev_set_drvdata(&adev_dimm->dev, nfit_mem);
|
||||
|
||||
/*
|
||||
* Until standardization materializes we need to consider 4
|
||||
|
@ -1752,9 +1757,11 @@ static void shutdown_dimm_notify(void *data)
|
|||
sysfs_put(nfit_mem->flags_attr);
|
||||
nfit_mem->flags_attr = NULL;
|
||||
}
|
||||
if (adev_dimm)
|
||||
if (adev_dimm) {
|
||||
acpi_remove_notify_handler(adev_dimm->handle,
|
||||
ACPI_DEVICE_NOTIFY, acpi_nvdimm_notify);
|
||||
dev_set_drvdata(&adev_dimm->dev, NULL);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&acpi_desc->init_mutex);
|
||||
}
|
||||
|
|
|
@ -220,7 +220,8 @@ static bool clk_core_is_enabled(struct clk_core *core)
|
|||
|
||||
ret = core->ops->is_enabled(core->hw);
|
||||
done:
|
||||
clk_pm_runtime_put(core);
|
||||
if (core->dev)
|
||||
pm_runtime_put(core->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1564,6 +1565,9 @@ static void clk_change_rate(struct clk_core *core)
|
|||
best_parent_rate = core->parent->rate;
|
||||
}
|
||||
|
||||
if (clk_pm_runtime_get(core))
|
||||
return;
|
||||
|
||||
if (core->flags & CLK_SET_RATE_UNGATE) {
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -1634,6 +1638,8 @@ static void clk_change_rate(struct clk_core *core)
|
|||
/* handle the new child who might not be in core->children yet */
|
||||
if (core->new_child)
|
||||
clk_change_rate(core->new_child);
|
||||
|
||||
clk_pm_runtime_put(core);
|
||||
}
|
||||
|
||||
static int clk_core_set_rate_nolock(struct clk_core *core,
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
@ -83,9 +84,20 @@ static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sun9i_mmc_reset_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
sun9i_mmc_reset_assert(rcdev, id);
|
||||
udelay(10);
|
||||
sun9i_mmc_reset_deassert(rcdev, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct reset_control_ops sun9i_mmc_reset_ops = {
|
||||
.assert = sun9i_mmc_reset_assert,
|
||||
.deassert = sun9i_mmc_reset_deassert,
|
||||
.reset = sun9i_mmc_reset_reset,
|
||||
};
|
||||
|
||||
static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -103,8 +103,8 @@ static int gpio_reg_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||
struct gpio_reg *r = to_gpio_reg(gc);
|
||||
int irq = r->irqs[offset];
|
||||
|
||||
if (irq >= 0 && r->irq.domain)
|
||||
irq = irq_find_mapping(r->irq.domain, irq);
|
||||
if (irq >= 0 && r->irqdomain)
|
||||
irq = irq_find_mapping(r->irqdomain, irq);
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
|
|
@ -1074,7 +1074,7 @@ void acpi_gpiochip_add(struct gpio_chip *chip)
|
|||
}
|
||||
|
||||
if (!chip->names)
|
||||
devprop_gpiochip_set_names(chip);
|
||||
devprop_gpiochip_set_names(chip, dev_fwnode(chip->parent));
|
||||
|
||||
acpi_gpiochip_request_regions(acpi_gpio);
|
||||
acpi_gpiochip_scan_gpios(acpi_gpio);
|
||||
|
|
|
@ -19,30 +19,27 @@
|
|||
/**
|
||||
* devprop_gpiochip_set_names - Set GPIO line names using device properties
|
||||
* @chip: GPIO chip whose lines should be named, if possible
|
||||
* @fwnode: Property Node containing the gpio-line-names property
|
||||
*
|
||||
* Looks for device property "gpio-line-names" and if it exists assigns
|
||||
* GPIO line names for the chip. The memory allocated for the assigned
|
||||
* names belong to the underlying firmware node and should not be released
|
||||
* by the caller.
|
||||
*/
|
||||
void devprop_gpiochip_set_names(struct gpio_chip *chip)
|
||||
void devprop_gpiochip_set_names(struct gpio_chip *chip,
|
||||
const struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct gpio_device *gdev = chip->gpiodev;
|
||||
const char **names;
|
||||
int ret, i;
|
||||
|
||||
if (!chip->parent) {
|
||||
dev_warn(&gdev->dev, "GPIO chip parent is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = device_property_read_string_array(chip->parent, "gpio-line-names",
|
||||
ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
|
||||
NULL, 0);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (ret != gdev->ngpio) {
|
||||
dev_warn(chip->parent,
|
||||
dev_warn(&gdev->dev,
|
||||
"names %d do not match number of GPIOs %d\n", ret,
|
||||
gdev->ngpio);
|
||||
return;
|
||||
|
@ -52,10 +49,10 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip)
|
|||
if (!names)
|
||||
return;
|
||||
|
||||
ret = device_property_read_string_array(chip->parent, "gpio-line-names",
|
||||
ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
|
||||
names, gdev->ngpio);
|
||||
if (ret < 0) {
|
||||
dev_warn(chip->parent, "failed to read GPIO line names\n");
|
||||
dev_warn(&gdev->dev, "failed to read GPIO line names\n");
|
||||
kfree(names);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -493,7 +493,8 @@ int of_gpiochip_add(struct gpio_chip *chip)
|
|||
|
||||
/* If the chip defines names itself, these take precedence */
|
||||
if (!chip->names)
|
||||
devprop_gpiochip_set_names(chip);
|
||||
devprop_gpiochip_set_names(chip,
|
||||
of_fwnode_handle(chip->of_node));
|
||||
|
||||
of_node_get(chip->of_node);
|
||||
|
||||
|
|
|
@ -228,7 +228,8 @@ static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
|
|||
return desc - &desc->gdev->descs[0];
|
||||
}
|
||||
|
||||
void devprop_gpiochip_set_names(struct gpio_chip *chip);
|
||||
void devprop_gpiochip_set_names(struct gpio_chip *chip,
|
||||
const struct fwnode_handle *fwnode);
|
||||
|
||||
/* With descriptor prefix */
|
||||
|
||||
|
|
|
@ -2467,7 +2467,7 @@ static int gfx_v9_0_kiq_kcq_enable(struct amdgpu_device *adev)
|
|||
PACKET3_MAP_QUEUES_PIPE(ring->pipe) |
|
||||
PACKET3_MAP_QUEUES_ME((ring->me == 1 ? 0 : 1)) |
|
||||
PACKET3_MAP_QUEUES_QUEUE_TYPE(0) | /*queue_type: normal compute queue */
|
||||
PACKET3_MAP_QUEUES_ALLOC_FORMAT(1) | /* alloc format: all_on_one_pipe */
|
||||
PACKET3_MAP_QUEUES_ALLOC_FORMAT(0) | /* alloc format: all_on_one_pipe */
|
||||
PACKET3_MAP_QUEUES_ENGINE_SEL(0) | /* engine_sel: compute */
|
||||
PACKET3_MAP_QUEUES_NUM_QUEUES(1)); /* num_queues: must be 1 */
|
||||
amdgpu_ring_write(kiq_ring, PACKET3_MAP_QUEUES_DOORBELL_OFFSET(ring->doorbell_index));
|
||||
|
|
|
@ -2336,7 +2336,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
|
|||
const struct dm_connector_state *dm_state)
|
||||
{
|
||||
struct drm_display_mode *preferred_mode = NULL;
|
||||
const struct drm_connector *drm_connector;
|
||||
struct drm_connector *drm_connector;
|
||||
struct dc_stream_state *stream = NULL;
|
||||
struct drm_display_mode mode = *drm_mode;
|
||||
bool native_mode_found = false;
|
||||
|
@ -2355,11 +2355,13 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
|
|||
|
||||
if (!aconnector->dc_sink) {
|
||||
/*
|
||||
* Exclude MST from creating fake_sink
|
||||
* TODO: need to enable MST into fake_sink feature
|
||||
* Create dc_sink when necessary to MST
|
||||
* Don't apply fake_sink to MST
|
||||
*/
|
||||
if (aconnector->mst_port)
|
||||
goto stream_create_fail;
|
||||
if (aconnector->mst_port) {
|
||||
dm_dp_mst_dc_sink_create(drm_connector);
|
||||
goto mst_dc_sink_create_done;
|
||||
}
|
||||
|
||||
if (create_fake_sink(aconnector))
|
||||
goto stream_create_fail;
|
||||
|
@ -2410,6 +2412,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
|
|||
stream_create_fail:
|
||||
dm_state_null:
|
||||
drm_connector_null:
|
||||
mst_dc_sink_create_done:
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,8 @@ struct amdgpu_dm_connector {
|
|||
struct mutex hpd_lock;
|
||||
|
||||
bool fake_enable;
|
||||
|
||||
bool mst_connected;
|
||||
};
|
||||
|
||||
#define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base)
|
||||
|
|
|
@ -185,6 +185,42 @@ static int dm_connector_update_modes(struct drm_connector *connector,
|
|||
return ret;
|
||||
}
|
||||
|
||||
void dm_dp_mst_dc_sink_create(struct drm_connector *connector)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
struct edid *edid;
|
||||
struct dc_sink *dc_sink;
|
||||
struct dc_sink_init_data init_params = {
|
||||
.link = aconnector->dc_link,
|
||||
.sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST };
|
||||
|
||||
edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
|
||||
|
||||
if (!edid) {
|
||||
drm_mode_connector_update_edid_property(
|
||||
&aconnector->base,
|
||||
NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
aconnector->edid = edid;
|
||||
|
||||
dc_sink = dc_link_add_remote_sink(
|
||||
aconnector->dc_link,
|
||||
(uint8_t *)aconnector->edid,
|
||||
(aconnector->edid->extensions + 1) * EDID_LENGTH,
|
||||
&init_params);
|
||||
|
||||
dc_sink->priv = aconnector;
|
||||
aconnector->dc_sink = dc_sink;
|
||||
|
||||
amdgpu_dm_add_sink_to_freesync_module(
|
||||
connector, aconnector->edid);
|
||||
|
||||
drm_mode_connector_update_edid_property(
|
||||
&aconnector->base, aconnector->edid);
|
||||
}
|
||||
|
||||
static int dm_dp_mst_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
@ -311,6 +347,7 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|||
drm_mode_connector_set_path_property(connector, pathprop);
|
||||
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
aconnector->mst_connected = true;
|
||||
return &aconnector->base;
|
||||
}
|
||||
}
|
||||
|
@ -363,6 +400,8 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|||
*/
|
||||
amdgpu_dm_connector_funcs_reset(connector);
|
||||
|
||||
aconnector->mst_connected = true;
|
||||
|
||||
DRM_INFO("DM_MST: added connector: %p [id: %d] [master: %p]\n",
|
||||
aconnector, connector->base.id, aconnector->mst_port);
|
||||
|
||||
|
@ -394,6 +433,8 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
|
|||
drm_mode_connector_update_edid_property(
|
||||
&aconnector->base,
|
||||
NULL);
|
||||
|
||||
aconnector->mst_connected = false;
|
||||
}
|
||||
|
||||
static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
|
||||
|
@ -404,10 +445,18 @@ static void dm_dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr)
|
|||
drm_kms_helper_hotplug_event(dev);
|
||||
}
|
||||
|
||||
static void dm_dp_mst_link_status_reset(struct drm_connector *connector)
|
||||
{
|
||||
mutex_lock(&connector->dev->mode_config.mutex);
|
||||
drm_mode_connector_set_link_status_property(connector, DRM_MODE_LINK_STATUS_BAD);
|
||||
mutex_unlock(&connector->dev->mode_config.mutex);
|
||||
}
|
||||
|
||||
static void dm_dp_mst_register_connector(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct amdgpu_device *adev = dev->dev_private;
|
||||
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
|
||||
|
||||
if (adev->mode_info.rfbdev)
|
||||
drm_fb_helper_add_one_connector(&adev->mode_info.rfbdev->helper, connector);
|
||||
|
@ -416,6 +465,8 @@ static void dm_dp_mst_register_connector(struct drm_connector *connector)
|
|||
|
||||
drm_connector_register(connector);
|
||||
|
||||
if (aconnector->mst_connected)
|
||||
dm_dp_mst_link_status_reset(connector);
|
||||
}
|
||||
|
||||
static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
|
||||
|
|
|
@ -31,5 +31,6 @@ struct amdgpu_dm_connector;
|
|||
|
||||
void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
|
||||
struct amdgpu_dm_connector *aconnector);
|
||||
void dm_dp_mst_dc_sink_create(struct drm_connector *connector);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -900,6 +900,15 @@ bool dcn_validate_bandwidth(
|
|||
v->override_vta_ps[input_idx] = pipe->plane_res.scl_data.taps.v_taps;
|
||||
v->override_hta_pschroma[input_idx] = pipe->plane_res.scl_data.taps.h_taps_c;
|
||||
v->override_vta_pschroma[input_idx] = pipe->plane_res.scl_data.taps.v_taps_c;
|
||||
/*
|
||||
* Spreadsheet doesn't handle taps_c is one properly,
|
||||
* need to force Chroma to always be scaled to pass
|
||||
* bandwidth validation.
|
||||
*/
|
||||
if (v->override_hta_pschroma[input_idx] == 1)
|
||||
v->override_hta_pschroma[input_idx] = 2;
|
||||
if (v->override_vta_pschroma[input_idx] == 1)
|
||||
v->override_vta_pschroma[input_idx] = 2;
|
||||
v->source_scan[input_idx] = (pipe->plane_state->rotation % 2) ? dcn_bw_vert : dcn_bw_hor;
|
||||
}
|
||||
if (v->is_line_buffer_bpp_fixed == dcn_bw_yes)
|
||||
|
|
|
@ -1801,7 +1801,7 @@ static void disable_link(struct dc_link *link, enum signal_type signal)
|
|||
link->link_enc->funcs->disable_output(link->link_enc, signal, link);
|
||||
}
|
||||
|
||||
bool dp_active_dongle_validate_timing(
|
||||
static bool dp_active_dongle_validate_timing(
|
||||
const struct dc_crtc_timing *timing,
|
||||
const struct dc_dongle_caps *dongle_caps)
|
||||
{
|
||||
|
@ -1833,6 +1833,8 @@ bool dp_active_dongle_validate_timing(
|
|||
/* Check Color Depth and Pixel Clock */
|
||||
if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420)
|
||||
required_pix_clk /= 2;
|
||||
else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
|
||||
required_pix_clk = required_pix_clk * 2 / 3;
|
||||
|
||||
switch (timing->display_color_depth) {
|
||||
case COLOR_DEPTH_666:
|
||||
|
|
|
@ -2866,16 +2866,19 @@ static void dce110_apply_ctx_for_surface(
|
|||
int num_planes,
|
||||
struct dc_state *context)
|
||||
{
|
||||
int i, be_idx;
|
||||
int i;
|
||||
|
||||
if (num_planes == 0)
|
||||
return;
|
||||
|
||||
be_idx = -1;
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
if (stream == context->res_ctx.pipe_ctx[i].stream) {
|
||||
be_idx = context->res_ctx.pipe_ctx[i].stream_res.tg->inst;
|
||||
break;
|
||||
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
|
||||
struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
|
||||
|
||||
if (stream == pipe_ctx->stream) {
|
||||
if (!pipe_ctx->top_pipe &&
|
||||
(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
|
||||
dc->hwss.pipe_control_lock(dc, pipe_ctx, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2895,9 +2898,22 @@ static void dce110_apply_ctx_for_surface(
|
|||
context->stream_count);
|
||||
|
||||
dce110_program_front_end_for_pipe(dc, pipe_ctx);
|
||||
|
||||
dc->hwss.update_plane_addr(dc, pipe_ctx);
|
||||
|
||||
program_surface_visibility(dc, pipe_ctx);
|
||||
|
||||
}
|
||||
|
||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
|
||||
struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
|
||||
|
||||
if ((stream == pipe_ctx->stream) &&
|
||||
(!pipe_ctx->top_pipe) &&
|
||||
(pipe_ctx->plane_state || old_pipe_ctx->plane_state))
|
||||
dc->hwss.pipe_control_lock(dc, pipe_ctx, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void dce110_power_down_fe(struct dc *dc, int fe_idx)
|
||||
|
|
|
@ -159,11 +159,10 @@ bool dpp_get_optimal_number_of_taps(
|
|||
scl_data->taps.h_taps = 1;
|
||||
if (IDENTITY_RATIO(scl_data->ratios.vert))
|
||||
scl_data->taps.v_taps = 1;
|
||||
/*
|
||||
* Spreadsheet doesn't handle taps_c is one properly,
|
||||
* need to force Chroma to always be scaled to pass
|
||||
* bandwidth validation.
|
||||
*/
|
||||
if (IDENTITY_RATIO(scl_data->ratios.horz_c))
|
||||
scl_data->taps.h_taps_c = 1;
|
||||
if (IDENTITY_RATIO(scl_data->ratios.vert_c))
|
||||
scl_data->taps.v_taps_c = 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -220,17 +220,6 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
|
|||
|
||||
mutex_lock(&dev->mode_config.idr_mutex);
|
||||
|
||||
/* Insert the new lessee into the tree */
|
||||
id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
error = id;
|
||||
goto out_lessee;
|
||||
}
|
||||
|
||||
lessee->lessee_id = id;
|
||||
lessee->lessor = drm_master_get(lessor);
|
||||
list_add_tail(&lessee->lessee_list, &lessor->lessees);
|
||||
|
||||
idr_for_each_entry(leases, entry, object) {
|
||||
error = 0;
|
||||
if (!idr_find(&dev->mode_config.crtc_idr, object))
|
||||
|
@ -246,6 +235,17 @@ static struct drm_master *drm_lease_create(struct drm_master *lessor, struct idr
|
|||
}
|
||||
}
|
||||
|
||||
/* Insert the new lessee into the tree */
|
||||
id = idr_alloc(&(drm_lease_owner(lessor)->lessee_idr), lessee, 1, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
error = id;
|
||||
goto out_lessee;
|
||||
}
|
||||
|
||||
lessee->lessee_id = id;
|
||||
lessee->lessor = drm_master_get(lessor);
|
||||
list_add_tail(&lessee->lessee_list, &lessor->lessees);
|
||||
|
||||
/* Move the leases over */
|
||||
lessee->leases = *leases;
|
||||
DRM_DEBUG_LEASE("new lessee %d %p, lessor %d %p\n", lessee->lessee_id, lessee, lessor->lessee_id, lessor);
|
||||
|
|
|
@ -558,11 +558,10 @@ int drm_plane_check_pixel_format(const struct drm_plane *plane, u32 format)
|
|||
}
|
||||
|
||||
/*
|
||||
* setplane_internal - setplane handler for internal callers
|
||||
* __setplane_internal - setplane handler for internal callers
|
||||
*
|
||||
* Note that we assume an extra reference has already been taken on fb. If the
|
||||
* update fails, this reference will be dropped before return; if it succeeds,
|
||||
* the previous framebuffer (if any) will be unreferenced instead.
|
||||
* This function will take a reference on the new fb for the plane
|
||||
* on success.
|
||||
*
|
||||
* src_{x,y,w,h} are provided in 16.16 fixed point format
|
||||
*/
|
||||
|
@ -630,14 +629,12 @@ static int __setplane_internal(struct drm_plane *plane,
|
|||
if (!ret) {
|
||||
plane->crtc = crtc;
|
||||
plane->fb = fb;
|
||||
fb = NULL;
|
||||
drm_framebuffer_get(plane->fb);
|
||||
} else {
|
||||
plane->old_fb = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
if (fb)
|
||||
drm_framebuffer_put(fb);
|
||||
if (plane->old_fb)
|
||||
drm_framebuffer_put(plane->old_fb);
|
||||
plane->old_fb = NULL;
|
||||
|
@ -685,6 +682,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|||
struct drm_plane *plane;
|
||||
struct drm_crtc *crtc = NULL;
|
||||
struct drm_framebuffer *fb = NULL;
|
||||
int ret;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return -EINVAL;
|
||||
|
@ -717,15 +715,16 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* setplane_internal will take care of deref'ing either the old or new
|
||||
* framebuffer depending on success.
|
||||
*/
|
||||
return setplane_internal(plane, crtc, fb,
|
||||
plane_req->crtc_x, plane_req->crtc_y,
|
||||
plane_req->crtc_w, plane_req->crtc_h,
|
||||
plane_req->src_x, plane_req->src_y,
|
||||
plane_req->src_w, plane_req->src_h);
|
||||
ret = setplane_internal(plane, crtc, fb,
|
||||
plane_req->crtc_x, plane_req->crtc_y,
|
||||
plane_req->crtc_w, plane_req->crtc_h,
|
||||
plane_req->src_x, plane_req->src_y,
|
||||
plane_req->src_w, plane_req->src_h);
|
||||
|
||||
if (fb)
|
||||
drm_framebuffer_put(fb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
||||
|
@ -788,13 +787,12 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc,
|
|||
src_h = fb->height << 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* setplane_internal will take care of deref'ing either the old or new
|
||||
* framebuffer depending on success.
|
||||
*/
|
||||
ret = __setplane_internal(crtc->cursor, crtc, fb,
|
||||
crtc_x, crtc_y, crtc_w, crtc_h,
|
||||
0, 0, src_w, src_h, ctx);
|
||||
crtc_x, crtc_y, crtc_w, crtc_h,
|
||||
0, 0, src_w, src_h, ctx);
|
||||
|
||||
if (fb)
|
||||
drm_framebuffer_put(fb);
|
||||
|
||||
/* Update successful; save new cursor position, if necessary */
|
||||
if (ret == 0 && req->flags & DRM_MODE_CURSOR_MOVE) {
|
||||
|
|
|
@ -369,40 +369,26 @@ static const struct file_operations drm_syncobj_file_fops = {
|
|||
.release = drm_syncobj_file_release,
|
||||
};
|
||||
|
||||
static int drm_syncobj_alloc_file(struct drm_syncobj *syncobj)
|
||||
{
|
||||
struct file *file = anon_inode_getfile("syncobj_file",
|
||||
&drm_syncobj_file_fops,
|
||||
syncobj, 0);
|
||||
if (IS_ERR(file))
|
||||
return PTR_ERR(file);
|
||||
|
||||
drm_syncobj_get(syncobj);
|
||||
if (cmpxchg(&syncobj->file, NULL, file)) {
|
||||
/* lost the race */
|
||||
fput(file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd)
|
||||
{
|
||||
int ret;
|
||||
struct file *file;
|
||||
int fd;
|
||||
|
||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (!syncobj->file) {
|
||||
ret = drm_syncobj_alloc_file(syncobj);
|
||||
if (ret) {
|
||||
put_unused_fd(fd);
|
||||
return ret;
|
||||
}
|
||||
file = anon_inode_getfile("syncobj_file",
|
||||
&drm_syncobj_file_fops,
|
||||
syncobj, 0);
|
||||
if (IS_ERR(file)) {
|
||||
put_unused_fd(fd);
|
||||
return PTR_ERR(file);
|
||||
}
|
||||
fd_install(fd, syncobj->file);
|
||||
|
||||
drm_syncobj_get(syncobj);
|
||||
fd_install(fd, file);
|
||||
|
||||
*p_fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
@ -422,31 +408,24 @@ static int drm_syncobj_handle_to_fd(struct drm_file *file_private,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct drm_syncobj *drm_syncobj_fdget(int fd)
|
||||
{
|
||||
struct file *file = fget(fd);
|
||||
|
||||
if (!file)
|
||||
return NULL;
|
||||
if (file->f_op != &drm_syncobj_file_fops)
|
||||
goto err;
|
||||
|
||||
return file->private_data;
|
||||
err:
|
||||
fput(file);
|
||||
return NULL;
|
||||
};
|
||||
|
||||
static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
|
||||
int fd, u32 *handle)
|
||||
{
|
||||
struct drm_syncobj *syncobj = drm_syncobj_fdget(fd);
|
||||
struct drm_syncobj *syncobj;
|
||||
struct file *file;
|
||||
int ret;
|
||||
|
||||
if (!syncobj)
|
||||
file = fget(fd);
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
if (file->f_op != &drm_syncobj_file_fops) {
|
||||
fput(file);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* take a reference to put in the idr */
|
||||
syncobj = file->private_data;
|
||||
drm_syncobj_get(syncobj);
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
|
@ -455,12 +434,14 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private,
|
|||
spin_unlock(&file_private->syncobj_table_lock);
|
||||
idr_preload_end();
|
||||
|
||||
if (ret < 0) {
|
||||
fput(syncobj->file);
|
||||
return ret;
|
||||
}
|
||||
*handle = ret;
|
||||
return 0;
|
||||
if (ret > 0) {
|
||||
*handle = ret;
|
||||
ret = 0;
|
||||
} else
|
||||
drm_syncobj_put(syncobj);
|
||||
|
||||
fput(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
|
||||
|
|
|
@ -266,6 +266,8 @@ static void emulate_monitor_status_change(struct intel_vgpu *vgpu)
|
|||
/* Clear host CRT status, so guest couldn't detect this host CRT. */
|
||||
if (IS_BROADWELL(dev_priv))
|
||||
vgpu_vreg(vgpu, PCH_ADPA) &= ~ADPA_CRT_HOTPLUG_MONITOR_MASK;
|
||||
|
||||
vgpu_vreg(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE;
|
||||
}
|
||||
|
||||
static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num)
|
||||
|
@ -282,7 +284,6 @@ static void clean_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num)
|
|||
static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
|
||||
int type, unsigned int resolution)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
|
||||
struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num);
|
||||
|
||||
if (WARN_ON(resolution >= GVT_EDID_NUM))
|
||||
|
@ -308,7 +309,7 @@ static int setup_virtual_dp_monitor(struct intel_vgpu *vgpu, int port_num,
|
|||
port->type = type;
|
||||
|
||||
emulate_monitor_status_change(vgpu);
|
||||
vgpu_vreg(vgpu, PIPECONF(PIPE_A)) |= PIPECONF_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -330,17 +330,10 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj)
|
|||
* must wait for all rendering to complete to the object (as unbinding
|
||||
* must anyway), and retire the requests.
|
||||
*/
|
||||
ret = i915_gem_object_wait(obj,
|
||||
I915_WAIT_INTERRUPTIBLE |
|
||||
I915_WAIT_LOCKED |
|
||||
I915_WAIT_ALL,
|
||||
MAX_SCHEDULE_TIMEOUT,
|
||||
NULL);
|
||||
ret = i915_gem_object_set_to_cpu_domain(obj, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i915_gem_retire_requests(to_i915(obj->base.dev));
|
||||
|
||||
while ((vma = list_first_entry_or_null(&obj->vma_list,
|
||||
struct i915_vma,
|
||||
obj_link))) {
|
||||
|
|
|
@ -367,6 +367,7 @@ struct i915_sw_dma_fence_cb {
|
|||
struct dma_fence *dma;
|
||||
struct timer_list timer;
|
||||
struct irq_work work;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
static void timer_i915_sw_fence_wake(struct timer_list *t)
|
||||
|
@ -406,7 +407,7 @@ static void irq_i915_sw_fence_work(struct irq_work *wrk)
|
|||
del_timer_sync(&cb->timer);
|
||||
dma_fence_put(cb->dma);
|
||||
|
||||
kfree(cb);
|
||||
kfree_rcu(cb, rcu);
|
||||
}
|
||||
|
||||
int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
|
||||
|
|
|
@ -186,7 +186,7 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
|
|||
struct intel_wait *wait, *n, *first;
|
||||
|
||||
if (!b->irq_armed)
|
||||
return;
|
||||
goto wakeup_signaler;
|
||||
|
||||
/* We only disarm the irq when we are idle (all requests completed),
|
||||
* so if the bottom-half remains asleep, it missed the request
|
||||
|
@ -208,6 +208,14 @@ void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
|
|||
b->waiters = RB_ROOT;
|
||||
|
||||
spin_unlock_irq(&b->rb_lock);
|
||||
|
||||
/*
|
||||
* The signaling thread may be asleep holding a reference to a request,
|
||||
* that had its signaling cancelled prior to being preempted. We need
|
||||
* to kick the signaler, just in case, to release any such reference.
|
||||
*/
|
||||
wakeup_signaler:
|
||||
wake_up_process(b->signaler);
|
||||
}
|
||||
|
||||
static bool use_fake_irq(const struct intel_breadcrumbs *b)
|
||||
|
@ -651,23 +659,15 @@ static int intel_breadcrumbs_signaler(void *arg)
|
|||
}
|
||||
|
||||
if (unlikely(do_schedule)) {
|
||||
DEFINE_WAIT(exec);
|
||||
|
||||
if (kthread_should_park())
|
||||
kthread_parkme();
|
||||
|
||||
if (kthread_should_stop()) {
|
||||
GEM_BUG_ON(request);
|
||||
if (unlikely(kthread_should_stop())) {
|
||||
i915_gem_request_put(request);
|
||||
break;
|
||||
}
|
||||
|
||||
if (request)
|
||||
add_wait_queue(&request->execute, &exec);
|
||||
|
||||
schedule();
|
||||
|
||||
if (request)
|
||||
remove_wait_queue(&request->execute, &exec);
|
||||
}
|
||||
i915_gem_request_put(request);
|
||||
} while (1);
|
||||
|
|
|
@ -2128,6 +2128,8 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,
|
|||
if (WARN_ON(!pll))
|
||||
return;
|
||||
|
||||
mutex_lock(&dev_priv->dpll_lock);
|
||||
|
||||
if (IS_CANNONLAKE(dev_priv)) {
|
||||
/* Configure DPCLKA_CFGCR0 to map the DPLL to the DDI. */
|
||||
val = I915_READ(DPCLKA_CFGCR0);
|
||||
|
@ -2157,6 +2159,8 @@ static void intel_ddi_clk_select(struct intel_encoder *encoder,
|
|||
} else if (INTEL_INFO(dev_priv)->gen < 9) {
|
||||
I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));
|
||||
}
|
||||
|
||||
mutex_unlock(&dev_priv->dpll_lock);
|
||||
}
|
||||
|
||||
static void intel_ddi_clk_disable(struct intel_encoder *encoder)
|
||||
|
|
|
@ -9944,11 +9944,10 @@ found:
|
|||
}
|
||||
|
||||
ret = intel_modeset_setup_plane_state(state, crtc, mode, fb, 0, 0);
|
||||
drm_framebuffer_put(fb);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
drm_framebuffer_put(fb);
|
||||
|
||||
ret = drm_atomic_set_mode_for_crtc(&crtc_state->base, mode);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
@ -13195,7 +13194,7 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
|
|||
primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe);
|
||||
primary->check_plane = intel_check_primary_plane;
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv)) {
|
||||
if (INTEL_GEN(dev_priv) >= 10) {
|
||||
intel_primary_formats = skl_primary_formats;
|
||||
num_formats = ARRAY_SIZE(skl_primary_formats);
|
||||
modifiers = skl_format_modifiers_ccs;
|
||||
|
|
|
@ -193,7 +193,7 @@ static bool lpe_audio_detect(struct drm_i915_private *dev_priv)
|
|||
};
|
||||
|
||||
if (!pci_dev_present(atom_hdaudio_ids)) {
|
||||
DRM_INFO("%s\n", "HDaudio controller not detected, using LPE audio instead\n");
|
||||
DRM_INFO("HDaudio controller not detected, using LPE audio instead\n");
|
||||
lpe_present = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
|
|||
/* Determine if we can get a cache-coherent map, forcing
|
||||
* uncached mapping if we can't.
|
||||
*/
|
||||
if (mmu->type[drm->ttm.type_host].type & NVIF_MEM_UNCACHED)
|
||||
if (!nouveau_drm_use_coherent_gpu_mapping(drm))
|
||||
nvbo->force_coherent = true;
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,8 @@ nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
|
|||
if (cli->device.info.family > NV_DEVICE_INFO_V0_CURIE &&
|
||||
(flags & TTM_PL_FLAG_VRAM) && !vmm->page[i].vram)
|
||||
continue;
|
||||
if ((flags & TTM_PL_FLAG_TT ) && !vmm->page[i].host)
|
||||
if ((flags & TTM_PL_FLAG_TT) &&
|
||||
(!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT))
|
||||
continue;
|
||||
|
||||
/* Select this page size if it's the first that supports
|
||||
|
|
|
@ -152,9 +152,9 @@ nouveau_cli_work_queue(struct nouveau_cli *cli, struct dma_fence *fence,
|
|||
work->cli = cli;
|
||||
mutex_lock(&cli->lock);
|
||||
list_add_tail(&work->head, &cli->worker);
|
||||
mutex_unlock(&cli->lock);
|
||||
if (dma_fence_add_callback(fence, &work->cb, nouveau_cli_work_fence))
|
||||
nouveau_cli_work_fence(fence, &work->cb);
|
||||
mutex_unlock(&cli->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -157,8 +157,8 @@ struct nouveau_drm {
|
|||
struct nvif_object copy;
|
||||
int mtrr;
|
||||
int type_vram;
|
||||
int type_host;
|
||||
int type_ncoh;
|
||||
int type_host[2];
|
||||
int type_ncoh[2];
|
||||
} ttm;
|
||||
|
||||
/* GEM interface support */
|
||||
|
@ -217,6 +217,13 @@ nouveau_drm(struct drm_device *dev)
|
|||
return dev->dev_private;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
nouveau_drm_use_coherent_gpu_mapping(struct nouveau_drm *drm)
|
||||
{
|
||||
struct nvif_mmu *mmu = &drm->client.mmu;
|
||||
return !(mmu->type[drm->ttm.type_host[0]].type & NVIF_MEM_UNCACHED);
|
||||
}
|
||||
|
||||
int nouveau_pmops_suspend(struct device *);
|
||||
int nouveau_pmops_resume(struct device *);
|
||||
bool nouveau_pmops_runtime(void);
|
||||
|
|
|
@ -429,7 +429,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
|
|||
drm_fb_helper_unregister_fbi(&fbcon->helper);
|
||||
drm_fb_helper_fini(&fbcon->helper);
|
||||
|
||||
if (nouveau_fb->nvbo) {
|
||||
if (nouveau_fb && nouveau_fb->nvbo) {
|
||||
nouveau_vma_del(&nouveau_fb->vma);
|
||||
nouveau_bo_unmap(nouveau_fb->nvbo);
|
||||
nouveau_bo_unpin(nouveau_fb->nvbo);
|
||||
|
|
|
@ -103,10 +103,10 @@ nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt)
|
|||
u8 type;
|
||||
int ret;
|
||||
|
||||
if (mmu->type[drm->ttm.type_host].type & NVIF_MEM_UNCACHED)
|
||||
type = drm->ttm.type_ncoh;
|
||||
if (!nouveau_drm_use_coherent_gpu_mapping(drm))
|
||||
type = drm->ttm.type_ncoh[!!mem->kind];
|
||||
else
|
||||
type = drm->ttm.type_host;
|
||||
type = drm->ttm.type_host[0];
|
||||
|
||||
if (mem->kind && !(mmu->type[type].type & NVIF_MEM_KIND))
|
||||
mem->comp = mem->kind = 0;
|
||||
|
|
|
@ -235,6 +235,27 @@ nouveau_ttm_global_release(struct nouveau_drm *drm)
|
|||
drm->ttm.mem_global_ref.release = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind)
|
||||
{
|
||||
struct nvif_mmu *mmu = &drm->client.mmu;
|
||||
int typei;
|
||||
|
||||
typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE |
|
||||
kind | NVIF_MEM_COHERENT);
|
||||
if (typei < 0)
|
||||
return -ENOSYS;
|
||||
|
||||
drm->ttm.type_host[!!kind] = typei;
|
||||
|
||||
typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE | kind);
|
||||
if (typei < 0)
|
||||
return -ENOSYS;
|
||||
|
||||
drm->ttm.type_ncoh[!!kind] = typei;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_ttm_init(struct nouveau_drm *drm)
|
||||
{
|
||||
|
@ -244,18 +265,16 @@ nouveau_ttm_init(struct nouveau_drm *drm)
|
|||
struct drm_device *dev = drm->dev;
|
||||
int typei, ret;
|
||||
|
||||
typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE |
|
||||
NVIF_MEM_COHERENT);
|
||||
if (typei < 0)
|
||||
return -ENOSYS;
|
||||
ret = nouveau_ttm_init_host(drm, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drm->ttm.type_host = typei;
|
||||
|
||||
typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE);
|
||||
if (typei < 0)
|
||||
return -ENOSYS;
|
||||
|
||||
drm->ttm.type_ncoh = typei;
|
||||
if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
|
||||
drm->client.device.info.chipset != 0x50) {
|
||||
ret = nouveau_ttm_init_host(drm, NVIF_MEM_KIND);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (drm->client.device.info.platform != NV_DEVICE_INFO_V0_SOC &&
|
||||
drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
|
||||
|
|
|
@ -67,8 +67,8 @@ nouveau_vma_del(struct nouveau_vma **pvma)
|
|||
nvif_vmm_put(&vma->vmm->vmm, &tmp);
|
||||
}
|
||||
list_del(&vma->head);
|
||||
*pvma = NULL;
|
||||
kfree(*pvma);
|
||||
*pvma = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2369,7 +2369,7 @@ nv13b_chipset = {
|
|||
.imem = gk20a_instmem_new,
|
||||
.ltc = gp100_ltc_new,
|
||||
.mc = gp10b_mc_new,
|
||||
.mmu = gf100_mmu_new,
|
||||
.mmu = gp10b_mmu_new,
|
||||
.secboot = gp10b_secboot_new,
|
||||
.pmu = gm20b_pmu_new,
|
||||
.timer = gk20a_timer_new,
|
||||
|
|
|
@ -36,6 +36,7 @@ nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
|
|||
if (data) {
|
||||
*ver = nvbios_rd08(bios, data + 0x00);
|
||||
switch (*ver) {
|
||||
case 0x20:
|
||||
case 0x21:
|
||||
case 0x30:
|
||||
case 0x40:
|
||||
|
@ -63,6 +64,7 @@ nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx,
|
|||
if (data && idx < *cnt) {
|
||||
u16 outp = nvbios_rd16(bios, data + *hdr + idx * *len);
|
||||
switch (*ver * !!outp) {
|
||||
case 0x20:
|
||||
case 0x21:
|
||||
case 0x30:
|
||||
*hdr = nvbios_rd08(bios, data + 0x04);
|
||||
|
@ -96,12 +98,16 @@ nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx,
|
|||
info->type = nvbios_rd16(bios, data + 0x00);
|
||||
info->mask = nvbios_rd16(bios, data + 0x02);
|
||||
switch (*ver) {
|
||||
case 0x20:
|
||||
info->mask |= 0x00c0; /* match any link */
|
||||
/* fall-through */
|
||||
case 0x21:
|
||||
case 0x30:
|
||||
info->flags = nvbios_rd08(bios, data + 0x05);
|
||||
info->script[0] = nvbios_rd16(bios, data + 0x06);
|
||||
info->script[1] = nvbios_rd16(bios, data + 0x08);
|
||||
info->lnkcmp = nvbios_rd16(bios, data + 0x0a);
|
||||
if (*len >= 0x0c)
|
||||
info->lnkcmp = nvbios_rd16(bios, data + 0x0a);
|
||||
if (*len >= 0x0f) {
|
||||
info->script[2] = nvbios_rd16(bios, data + 0x0c);
|
||||
info->script[3] = nvbios_rd16(bios, data + 0x0e);
|
||||
|
@ -170,6 +176,7 @@ nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
|
|||
memset(info, 0x00, sizeof(*info));
|
||||
if (data) {
|
||||
switch (*ver) {
|
||||
case 0x20:
|
||||
case 0x21:
|
||||
info->dc = nvbios_rd08(bios, data + 0x02);
|
||||
info->pe = nvbios_rd08(bios, data + 0x03);
|
||||
|
|
|
@ -249,7 +249,7 @@ nv50_instobj_acquire(struct nvkm_memory *memory)
|
|||
iobj->base.memory.ptrs = &nv50_instobj_fast;
|
||||
else
|
||||
iobj->base.memory.ptrs = &nv50_instobj_slow;
|
||||
refcount_inc(&iobj->maps);
|
||||
refcount_set(&iobj->maps, 1);
|
||||
}
|
||||
|
||||
mutex_unlock(&imem->subdev.mutex);
|
||||
|
|
|
@ -136,6 +136,13 @@ nvkm_pci_init(struct nvkm_subdev *subdev)
|
|||
return ret;
|
||||
|
||||
pci->irq = pdev->irq;
|
||||
|
||||
/* Ensure MSI interrupts are armed, for the case where there are
|
||||
* already interrupts pending (for whatever reason) at load time.
|
||||
*/
|
||||
if (pci->msi)
|
||||
pci->func->msi_rearm(pci);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -175,11 +175,31 @@ static void sun4i_hdmi_mode_set(struct drm_encoder *encoder,
|
|||
writel(val, hdmi->base + SUN4I_HDMI_VID_TIMING_POL_REG);
|
||||
}
|
||||
|
||||
static enum drm_mode_status sun4i_hdmi_mode_valid(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct sun4i_hdmi *hdmi = drm_encoder_to_sun4i_hdmi(encoder);
|
||||
unsigned long rate = mode->clock * 1000;
|
||||
unsigned long diff = rate / 200; /* +-0.5% allowed by HDMI spec */
|
||||
long rounded_rate;
|
||||
|
||||
/* 165 MHz is the typical max pixelclock frequency for HDMI <= 1.2 */
|
||||
if (rate > 165000000)
|
||||
return MODE_CLOCK_HIGH;
|
||||
rounded_rate = clk_round_rate(hdmi->tmds_clk, rate);
|
||||
if (rounded_rate > 0 &&
|
||||
max_t(unsigned long, rounded_rate, rate) -
|
||||
min_t(unsigned long, rounded_rate, rate) < diff)
|
||||
return MODE_OK;
|
||||
return MODE_NOCLOCK;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs sun4i_hdmi_helper_funcs = {
|
||||
.atomic_check = sun4i_hdmi_atomic_check,
|
||||
.disable = sun4i_hdmi_disable,
|
||||
.enable = sun4i_hdmi_enable,
|
||||
.mode_set = sun4i_hdmi_mode_set,
|
||||
.mode_valid = sun4i_hdmi_mode_valid,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs sun4i_hdmi_funcs = {
|
||||
|
|
|
@ -724,12 +724,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
|
|||
if (IS_ERR(tcon->crtc)) {
|
||||
dev_err(dev, "Couldn't create our CRTC\n");
|
||||
ret = PTR_ERR(tcon->crtc);
|
||||
goto err_free_clocks;
|
||||
goto err_free_dotclock;
|
||||
}
|
||||
|
||||
ret = sun4i_rgb_init(drm, tcon);
|
||||
if (ret < 0)
|
||||
goto err_free_clocks;
|
||||
goto err_free_dotclock;
|
||||
|
||||
if (tcon->quirks->needs_de_be_mux) {
|
||||
/*
|
||||
|
|
|
@ -455,6 +455,7 @@ ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
|
|||
freed += (nr_free_pool - shrink_pages) << pool->order;
|
||||
if (freed >= sc->nr_to_scan)
|
||||
break;
|
||||
shrink_pages <<= pool->order;
|
||||
}
|
||||
mutex_unlock(&lock);
|
||||
return freed;
|
||||
|
@ -543,7 +544,7 @@ static int ttm_alloc_new_pages(struct list_head *pages, gfp_t gfp_flags,
|
|||
int r = 0;
|
||||
unsigned i, j, cpages;
|
||||
unsigned npages = 1 << order;
|
||||
unsigned max_cpages = min(count, (unsigned)NUM_PAGES_TO_ALLOC);
|
||||
unsigned max_cpages = min(count << order, (unsigned)NUM_PAGES_TO_ALLOC);
|
||||
|
||||
/* allocate array for page caching change */
|
||||
caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL);
|
||||
|
|
|
@ -143,6 +143,7 @@ static int hwmon_thermal_add_sensor(struct device *dev,
|
|||
struct hwmon_device *hwdev, int index)
|
||||
{
|
||||
struct hwmon_thermal_data *tdata;
|
||||
struct thermal_zone_device *tzd;
|
||||
|
||||
tdata = devm_kzalloc(dev, sizeof(*tdata), GFP_KERNEL);
|
||||
if (!tdata)
|
||||
|
@ -151,8 +152,14 @@ static int hwmon_thermal_add_sensor(struct device *dev,
|
|||
tdata->hwdev = hwdev;
|
||||
tdata->index = index;
|
||||
|
||||
devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata,
|
||||
&hwmon_thermal_ops);
|
||||
tzd = devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata,
|
||||
&hwmon_thermal_ops);
|
||||
/*
|
||||
* If CONFIG_THERMAL_OF is disabled, this returns -ENODEV,
|
||||
* so ignore that error but forward any other error.
|
||||
*/
|
||||
if (IS_ERR(tzd) && (PTR_ERR(tzd) != -ENODEV))
|
||||
return PTR_ERR(tzd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -621,14 +628,20 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata,
|
|||
if (!chip->ops->is_visible(drvdata, hwmon_temp,
|
||||
hwmon_temp_input, j))
|
||||
continue;
|
||||
if (info[i]->config[j] & HWMON_T_INPUT)
|
||||
hwmon_thermal_add_sensor(dev, hwdev, j);
|
||||
if (info[i]->config[j] & HWMON_T_INPUT) {
|
||||
err = hwmon_thermal_add_sensor(dev,
|
||||
hwdev, j);
|
||||
if (err)
|
||||
goto free_device;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hdev;
|
||||
|
||||
free_device:
|
||||
device_unregister(hdev);
|
||||
free_hwmon:
|
||||
kfree(hwdev);
|
||||
ida_remove:
|
||||
|
|
|
@ -386,6 +386,9 @@ int ib_open_shared_qp_security(struct ib_qp *qp, struct ib_device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!qp->qp_sec)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&real_qp->qp_sec->mutex);
|
||||
ret = check_qp_port_pkey_settings(real_qp->qp_sec->ports_pkeys,
|
||||
qp->qp_sec);
|
||||
|
|
|
@ -2074,8 +2074,8 @@ int ib_uverbs_ex_modify_qp(struct ib_uverbs_file *file,
|
|||
return -EOPNOTSUPP;
|
||||
|
||||
if (ucore->inlen > sizeof(cmd)) {
|
||||
if (ib_is_udata_cleared(ucore, sizeof(cmd),
|
||||
ucore->inlen - sizeof(cmd)))
|
||||
if (!ib_is_udata_cleared(ucore, sizeof(cmd),
|
||||
ucore->inlen - sizeof(cmd)))
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
|
|
@ -1438,7 +1438,8 @@ int ib_close_qp(struct ib_qp *qp)
|
|||
spin_unlock_irqrestore(&real_qp->device->event_handler_lock, flags);
|
||||
|
||||
atomic_dec(&real_qp->usecnt);
|
||||
ib_close_shared_qp_security(qp->qp_sec);
|
||||
if (qp->qp_sec)
|
||||
ib_close_shared_qp_security(qp->qp_sec);
|
||||
kfree(qp);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -395,7 +395,7 @@ next_cqe:
|
|||
|
||||
static int cqe_completes_wr(struct t4_cqe *cqe, struct t4_wq *wq)
|
||||
{
|
||||
if (CQE_OPCODE(cqe) == C4IW_DRAIN_OPCODE) {
|
||||
if (DRAIN_CQE(cqe)) {
|
||||
WARN_ONCE(1, "Unexpected DRAIN CQE qp id %u!\n", wq->sq.qid);
|
||||
return 0;
|
||||
}
|
||||
|
@ -494,7 +494,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
|
|||
/*
|
||||
* Special cqe for drain WR completions...
|
||||
*/
|
||||
if (CQE_OPCODE(hw_cqe) == C4IW_DRAIN_OPCODE) {
|
||||
if (DRAIN_CQE(hw_cqe)) {
|
||||
*cookie = CQE_DRAIN_COOKIE(hw_cqe);
|
||||
*cqe = *hw_cqe;
|
||||
goto skip_cqe;
|
||||
|
@ -571,10 +571,10 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
|
|||
ret = -EAGAIN;
|
||||
goto skip_cqe;
|
||||
}
|
||||
if (unlikely((CQE_WRID_MSN(hw_cqe) != (wq->rq.msn)))) {
|
||||
if (unlikely(!CQE_STATUS(hw_cqe) &&
|
||||
CQE_WRID_MSN(hw_cqe) != wq->rq.msn)) {
|
||||
t4_set_wq_in_error(wq);
|
||||
hw_cqe->header |= htonl(CQE_STATUS_V(T4_ERR_MSN));
|
||||
goto proc_cqe;
|
||||
hw_cqe->header |= cpu_to_be32(CQE_STATUS_V(T4_ERR_MSN));
|
||||
}
|
||||
goto proc_cqe;
|
||||
}
|
||||
|
@ -748,9 +748,6 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
|
|||
c4iw_invalidate_mr(qhp->rhp,
|
||||
CQE_WRID_FR_STAG(&cqe));
|
||||
break;
|
||||
case C4IW_DRAIN_OPCODE:
|
||||
wc->opcode = IB_WC_SEND;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unexpected opcode %d in the CQE received for QPID=0x%0x\n",
|
||||
CQE_OPCODE(&cqe), CQE_QPID(&cqe));
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue