mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 14:04:54 +02:00
Linux 5.11-rc4
-----BEGIN PGP SIGNATURE----- iQFSBAABCAA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAmAE2DEeHHRvcnZhbGRz QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiGgeUH/jmfqv+ieSitqsnO fmOp6w0Ia8w/PnvUq6cp+4hrhnxrjpN+dnoMgnSZ92g98zDQWamn3Wp6Anc/KSCJ MdBxTRJtgzu/b1+zqZm7tu1W+HPedwT3/kFStF4QQWgfveg/0EHr3TDfKQSBscCV gP21L7FKSaTBVJdIBvkYdlHq/bIuNdKaen+JBG28w3/WqTJDmCCU3Pw8vQYEMACq C/exg0XQDndPpGKnnCOcG2wy2VjmUvg96cVWpYnQC8Rwqy9AHPFdKI4Y9F86lRpq 7bLGenP8UadUkSOhunv359TDb0L3j6l8qjZ41LwgbtkT2ZkgWjfWwDqSPZnJQ4ZO 0G1j8Io= =gBVY -----END PGP SIGNATURE----- Merge v5.11-rc4 into android-mainline Linux 5.11-rc4 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Id18fa2761612efa7e1e8d03f4225bfac40064004
This commit is contained in:
commit
902943e032
|
|
@ -5976,6 +5976,10 @@
|
|||
This option is obsoleted by the "nopv" option, which
|
||||
has equivalent effect for XEN platform.
|
||||
|
||||
xen_no_vector_callback
|
||||
[KNL,X86,XEN] Disable the vector callback for Xen
|
||||
event channel interrupts.
|
||||
|
||||
xen_scrub_pages= [XEN]
|
||||
Boolean option to control scrubbing pages before giving them back
|
||||
to Xen, for use by other domains. Can be also changed at runtime
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ The following files belong to it:
|
|||
0x00000010 Memory Uncorrectable non-fatal
|
||||
0x00000020 Memory Uncorrectable fatal
|
||||
0x00000040 PCI Express Correctable
|
||||
0x00000080 PCI Express Uncorrectable fatal
|
||||
0x00000100 PCI Express Uncorrectable non-fatal
|
||||
0x00000080 PCI Express Uncorrectable non-fatal
|
||||
0x00000100 PCI Express Uncorrectable fatal
|
||||
0x00000200 Platform Correctable
|
||||
0x00000400 Platform Uncorrectable non-fatal
|
||||
0x00000800 Platform Uncorrectable fatal
|
||||
|
|
|
|||
|
|
@ -16326,6 +16326,7 @@ M: Pekka Enberg <penberg@kernel.org>
|
|||
M: David Rientjes <rientjes@google.com>
|
||||
M: Joonsoo Kim <iamjoonsoo.kim@lge.com>
|
||||
M: Andrew Morton <akpm@linux-foundation.org>
|
||||
M: Vlastimil Babka <vbabka@suse.cz>
|
||||
L: linux-mm@kvack.org
|
||||
S: Maintained
|
||||
F: include/linux/sl?b*.h
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
VERSION = 5
|
||||
PATCHLEVEL = 11
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc3
|
||||
EXTRAVERSION = -rc4
|
||||
NAME = Kleptomaniac Octopus
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ static int __init xen_guest_init(void)
|
|||
}
|
||||
gnttab_init();
|
||||
if (!xen_initial_domain())
|
||||
xenbus_probe(NULL);
|
||||
xenbus_probe();
|
||||
|
||||
/*
|
||||
* Making sure board specific code will not set up ops for
|
||||
|
|
|
|||
|
|
@ -174,8 +174,6 @@ config ARM64
|
|||
select HAVE_NMI
|
||||
select HAVE_PATA_PLATFORM
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_PERF_EVENTS_NMI if ARM64_PSEUDO_NMI && HW_PERF_EVENTS
|
||||
select HAVE_HARDLOCKUP_DETECTOR_PERF if PERF_EVENTS && HAVE_PERF_EVENTS_NMI
|
||||
select HAVE_PERF_REGS
|
||||
select HAVE_PERF_USER_STACK_DUMP
|
||||
select HAVE_REGS_AND_STACK_ACCESS_API
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#include <asm/lse.h>
|
||||
|
||||
#define ATOMIC_OP(op) \
|
||||
static inline void arch_##op(int i, atomic_t *v) \
|
||||
static __always_inline void arch_##op(int i, atomic_t *v) \
|
||||
{ \
|
||||
__lse_ll_sc_body(op, i, v); \
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ ATOMIC_OP(atomic_sub)
|
|||
#undef ATOMIC_OP
|
||||
|
||||
#define ATOMIC_FETCH_OP(name, op) \
|
||||
static inline int arch_##op##name(int i, atomic_t *v) \
|
||||
static __always_inline int arch_##op##name(int i, atomic_t *v) \
|
||||
{ \
|
||||
return __lse_ll_sc_body(op##name, i, v); \
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ ATOMIC_FETCH_OPS(atomic_sub_return)
|
|||
#undef ATOMIC_FETCH_OPS
|
||||
|
||||
#define ATOMIC64_OP(op) \
|
||||
static inline void arch_##op(long i, atomic64_t *v) \
|
||||
static __always_inline void arch_##op(long i, atomic64_t *v) \
|
||||
{ \
|
||||
__lse_ll_sc_body(op, i, v); \
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ ATOMIC64_OP(atomic64_sub)
|
|||
#undef ATOMIC64_OP
|
||||
|
||||
#define ATOMIC64_FETCH_OP(name, op) \
|
||||
static inline long arch_##op##name(long i, atomic64_t *v) \
|
||||
static __always_inline long arch_##op##name(long i, atomic64_t *v) \
|
||||
{ \
|
||||
return __lse_ll_sc_body(op##name, i, v); \
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ ATOMIC64_FETCH_OPS(atomic64_sub_return)
|
|||
#undef ATOMIC64_FETCH_OP
|
||||
#undef ATOMIC64_FETCH_OPS
|
||||
|
||||
static inline long arch_atomic64_dec_if_positive(atomic64_t *v)
|
||||
static __always_inline long arch_atomic64_dec_if_positive(atomic64_t *v)
|
||||
{
|
||||
return __lse_ll_sc_body(atomic64_dec_if_positive, v);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,8 +95,7 @@
|
|||
#endif /* CONFIG_ARM64_FORCE_52BIT */
|
||||
|
||||
extern phys_addr_t arm64_dma_phys_limit;
|
||||
extern phys_addr_t arm64_dma32_phys_limit;
|
||||
#define ARCH_LOW_ADDRESS_LIMIT ((arm64_dma_phys_limit ? : arm64_dma32_phys_limit) - 1)
|
||||
#define ARCH_LOW_ADDRESS_LIMIT (arm64_dma_phys_limit - 1)
|
||||
|
||||
struct debug_info {
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ int main(void)
|
|||
DEFINE(S_SDEI_TTBR1, offsetof(struct pt_regs, sdei_ttbr1));
|
||||
DEFINE(S_PMR_SAVE, offsetof(struct pt_regs, pmr_save));
|
||||
DEFINE(S_STACKFRAME, offsetof(struct pt_regs, stackframe));
|
||||
DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs));
|
||||
DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
|
||||
BLANK();
|
||||
#ifdef CONFIG_COMPAT
|
||||
DEFINE(COMPAT_SIGFRAME_REGS_OFFSET, offsetof(struct compat_sigframe, uc.uc_mcontext.arm_r0));
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
*/
|
||||
.macro ftrace_regs_entry, allregs=0
|
||||
/* Make room for pt_regs, plus a callee frame */
|
||||
sub sp, sp, #(S_FRAME_SIZE + 16)
|
||||
sub sp, sp, #(PT_REGS_SIZE + 16)
|
||||
|
||||
/* Save function arguments (and x9 for simplicity) */
|
||||
stp x0, x1, [sp, #S_X0]
|
||||
|
|
@ -61,15 +61,15 @@
|
|||
.endif
|
||||
|
||||
/* Save the callsite's SP and LR */
|
||||
add x10, sp, #(S_FRAME_SIZE + 16)
|
||||
add x10, sp, #(PT_REGS_SIZE + 16)
|
||||
stp x9, x10, [sp, #S_LR]
|
||||
|
||||
/* Save the PC after the ftrace callsite */
|
||||
str x30, [sp, #S_PC]
|
||||
|
||||
/* Create a frame record for the callsite above pt_regs */
|
||||
stp x29, x9, [sp, #S_FRAME_SIZE]
|
||||
add x29, sp, #S_FRAME_SIZE
|
||||
stp x29, x9, [sp, #PT_REGS_SIZE]
|
||||
add x29, sp, #PT_REGS_SIZE
|
||||
|
||||
/* Create our frame record within pt_regs. */
|
||||
stp x29, x30, [sp, #S_STACKFRAME]
|
||||
|
|
@ -120,7 +120,7 @@ ftrace_common_return:
|
|||
ldr x9, [sp, #S_PC]
|
||||
|
||||
/* Restore the callsite's SP */
|
||||
add sp, sp, #S_FRAME_SIZE + 16
|
||||
add sp, sp, #PT_REGS_SIZE + 16
|
||||
|
||||
ret x9
|
||||
SYM_CODE_END(ftrace_common)
|
||||
|
|
@ -130,7 +130,7 @@ SYM_CODE_START(ftrace_graph_caller)
|
|||
ldr x0, [sp, #S_PC]
|
||||
sub x0, x0, #AARCH64_INSN_SIZE // ip (callsite's BL insn)
|
||||
add x1, sp, #S_LR // parent_ip (callsite's LR)
|
||||
ldr x2, [sp, #S_FRAME_SIZE] // parent fp (callsite's FP)
|
||||
ldr x2, [sp, #PT_REGS_SIZE] // parent fp (callsite's FP)
|
||||
bl prepare_ftrace_return
|
||||
b ftrace_common_return
|
||||
SYM_CODE_END(ftrace_graph_caller)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ alternative_else_nop_endif
|
|||
.endif
|
||||
#endif
|
||||
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
#ifdef CONFIG_VMAP_STACK
|
||||
/*
|
||||
* Test whether the SP has overflowed, without corrupting a GPR.
|
||||
|
|
@ -96,7 +96,7 @@ alternative_else_nop_endif
|
|||
* userspace, and can clobber EL0 registers to free up GPRs.
|
||||
*/
|
||||
|
||||
/* Stash the original SP (minus S_FRAME_SIZE) in tpidr_el0. */
|
||||
/* Stash the original SP (minus PT_REGS_SIZE) in tpidr_el0. */
|
||||
msr tpidr_el0, x0
|
||||
|
||||
/* Recover the original x0 value and stash it in tpidrro_el0 */
|
||||
|
|
@ -253,7 +253,7 @@ alternative_else_nop_endif
|
|||
|
||||
scs_load tsk, x20
|
||||
.else
|
||||
add x21, sp, #S_FRAME_SIZE
|
||||
add x21, sp, #PT_REGS_SIZE
|
||||
get_current_task tsk
|
||||
.endif /* \el == 0 */
|
||||
mrs x22, elr_el1
|
||||
|
|
@ -377,7 +377,7 @@ alternative_else_nop_endif
|
|||
ldp x26, x27, [sp, #16 * 13]
|
||||
ldp x28, x29, [sp, #16 * 14]
|
||||
ldr lr, [sp, #S_LR]
|
||||
add sp, sp, #S_FRAME_SIZE // restore sp
|
||||
add sp, sp, #PT_REGS_SIZE // restore sp
|
||||
|
||||
.if \el == 0
|
||||
alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
|
||||
|
|
@ -580,12 +580,12 @@ __bad_stack:
|
|||
|
||||
/*
|
||||
* Store the original GPRs to the new stack. The orginal SP (minus
|
||||
* S_FRAME_SIZE) was stashed in tpidr_el0 by kernel_ventry.
|
||||
* PT_REGS_SIZE) was stashed in tpidr_el0 by kernel_ventry.
|
||||
*/
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
kernel_entry 1
|
||||
mrs x0, tpidr_el0
|
||||
add x0, x0, #S_FRAME_SIZE
|
||||
add x0, x0, #PT_REGS_SIZE
|
||||
str x0, [sp, #S_SP]
|
||||
|
||||
/* Stash the regs for handle_bad_stack */
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/cpufreq.h>
|
||||
|
||||
/* ARMv8 Cortex-A53 specific event types. */
|
||||
#define ARMV8_A53_PERFCTR_PREF_LINEFILL 0xC2
|
||||
|
|
@ -1250,21 +1248,10 @@ static struct platform_driver armv8_pmu_driver = {
|
|||
|
||||
static int __init armv8_pmu_driver_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (acpi_disabled)
|
||||
ret = platform_driver_register(&armv8_pmu_driver);
|
||||
return platform_driver_register(&armv8_pmu_driver);
|
||||
else
|
||||
ret = arm_pmu_acpi_probe(armv8_pmuv3_init);
|
||||
|
||||
/*
|
||||
* Try to re-initialize lockup detector after PMU init in
|
||||
* case PMU events are triggered via NMIs.
|
||||
*/
|
||||
if (ret == 0 && arm_pmu_irq_is_nmi())
|
||||
lockup_detector_init();
|
||||
|
||||
return ret;
|
||||
return arm_pmu_acpi_probe(armv8_pmuv3_init);
|
||||
}
|
||||
device_initcall(armv8_pmu_driver_init)
|
||||
|
||||
|
|
@ -1322,27 +1309,3 @@ void arch_perf_update_userpage(struct perf_event *event,
|
|||
userpg->cap_user_time_zero = 1;
|
||||
userpg->cap_user_time_short = 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF
|
||||
/*
|
||||
* Safe maximum CPU frequency in case a particular platform doesn't implement
|
||||
* cpufreq driver. Although, architecture doesn't put any restrictions on
|
||||
* maximum frequency but 5 GHz seems to be safe maximum given the available
|
||||
* Arm CPUs in the market which are clocked much less than 5 GHz. On the other
|
||||
* hand, we can't make it much higher as it would lead to a large hard-lockup
|
||||
* detection timeout on parts which are running slower (eg. 1GHz on
|
||||
* Developerbox) and doesn't possess a cpufreq driver.
|
||||
*/
|
||||
#define SAFE_MAX_CPU_FREQ 5000000000UL // 5 GHz
|
||||
u64 hw_nmi_get_sample_period(int watchdog_thresh)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
unsigned long max_cpu_freq;
|
||||
|
||||
max_cpu_freq = cpufreq_get_hw_max_freq(cpu) * 1000UL;
|
||||
if (!max_cpu_freq)
|
||||
max_cpu_freq = SAFE_MAX_CPU_FREQ;
|
||||
|
||||
return (u64)max_cpu_freq * watchdog_thresh;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
stp x24, x25, [sp, #S_X24]
|
||||
stp x26, x27, [sp, #S_X26]
|
||||
stp x28, x29, [sp, #S_X28]
|
||||
add x0, sp, #S_FRAME_SIZE
|
||||
add x0, sp, #PT_REGS_SIZE
|
||||
stp lr, x0, [sp, #S_LR]
|
||||
/*
|
||||
* Construct a useful saved PSTATE
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
.endm
|
||||
|
||||
SYM_CODE_START(kretprobe_trampoline)
|
||||
sub sp, sp, #S_FRAME_SIZE
|
||||
sub sp, sp, #PT_REGS_SIZE
|
||||
|
||||
save_all_base_regs
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ SYM_CODE_START(kretprobe_trampoline)
|
|||
|
||||
restore_all_base_regs
|
||||
|
||||
add sp, sp, #S_FRAME_SIZE
|
||||
add sp, sp, #PT_REGS_SIZE
|
||||
ret
|
||||
|
||||
SYM_CODE_END(kretprobe_trampoline)
|
||||
|
|
|
|||
|
|
@ -947,13 +947,6 @@ static void set_32bit_cpus_allowed(void)
|
|||
asmlinkage void do_notify_resume(struct pt_regs *regs,
|
||||
unsigned long thread_flags)
|
||||
{
|
||||
/*
|
||||
* The assembly code enters us with IRQs off, but it hasn't
|
||||
* informed the tracing code of that for efficiency reasons.
|
||||
* Update the trace code with the current status.
|
||||
*/
|
||||
trace_hardirqs_off();
|
||||
|
||||
do {
|
||||
if (thread_flags & _TIF_NEED_RESCHED) {
|
||||
/* Unmask Debug and SError for the next task */
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <asm/daifflags.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
#include <asm/exception.h>
|
||||
#include <asm/fpsimd.h>
|
||||
#include <asm/syscall.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
|
@ -165,15 +166,8 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
|
|||
if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
|
||||
local_daif_mask();
|
||||
flags = current_thread_info()->flags;
|
||||
if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP)) {
|
||||
/*
|
||||
* We're off to userspace, where interrupts are
|
||||
* always enabled after we restore the flags from
|
||||
* the SPSR.
|
||||
*/
|
||||
trace_hardirqs_on();
|
||||
if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP))
|
||||
return;
|
||||
}
|
||||
local_daif_restore(DAIF_PROCCTX);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,13 +53,13 @@ s64 memstart_addr __ro_after_init = -1;
|
|||
EXPORT_SYMBOL(memstart_addr);
|
||||
|
||||
/*
|
||||
* We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of
|
||||
* memory as some devices, namely the Raspberry Pi 4, have peripherals with
|
||||
* this limited view of the memory. ZONE_DMA32 will cover the rest of the 32
|
||||
* bit addressable memory area.
|
||||
* If the corresponding config options are enabled, we create both ZONE_DMA
|
||||
* and ZONE_DMA32. By default ZONE_DMA covers the 32-bit addressable memory
|
||||
* unless restricted on specific platforms (e.g. 30-bit on Raspberry Pi 4).
|
||||
* In such case, ZONE_DMA32 covers the rest of the 32-bit addressable memory,
|
||||
* otherwise it is empty.
|
||||
*/
|
||||
phys_addr_t arm64_dma_phys_limit __ro_after_init;
|
||||
phys_addr_t arm64_dma32_phys_limit __ro_after_init;
|
||||
|
||||
#ifdef CONFIG_KEXEC_CORE
|
||||
/*
|
||||
|
|
@ -84,7 +84,7 @@ static void __init reserve_crashkernel(void)
|
|||
|
||||
if (crash_base == 0) {
|
||||
/* Current arm64 boot protocol requires 2MB alignment */
|
||||
crash_base = memblock_find_in_range(0, arm64_dma32_phys_limit,
|
||||
crash_base = memblock_find_in_range(0, arm64_dma_phys_limit,
|
||||
crash_size, SZ_2M);
|
||||
if (crash_base == 0) {
|
||||
pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
|
||||
|
|
@ -196,6 +196,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
|
|||
unsigned long max_zone_pfns[MAX_NR_ZONES] = {0};
|
||||
unsigned int __maybe_unused acpi_zone_dma_bits;
|
||||
unsigned int __maybe_unused dt_zone_dma_bits;
|
||||
phys_addr_t __maybe_unused dma32_phys_limit = max_zone_phys(32);
|
||||
|
||||
#ifdef CONFIG_ZONE_DMA
|
||||
acpi_zone_dma_bits = fls64(acpi_iort_dma_get_max_cpu_address());
|
||||
|
|
@ -205,8 +206,12 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
|
|||
max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit);
|
||||
#endif
|
||||
#ifdef CONFIG_ZONE_DMA32
|
||||
max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit);
|
||||
max_zone_pfns[ZONE_DMA32] = PFN_DOWN(dma32_phys_limit);
|
||||
if (!arm64_dma_phys_limit)
|
||||
arm64_dma_phys_limit = dma32_phys_limit;
|
||||
#endif
|
||||
if (!arm64_dma_phys_limit)
|
||||
arm64_dma_phys_limit = PHYS_MASK + 1;
|
||||
max_zone_pfns[ZONE_NORMAL] = max;
|
||||
|
||||
free_area_init(max_zone_pfns);
|
||||
|
|
@ -394,16 +399,9 @@ void __init arm64_memblock_init(void)
|
|||
|
||||
early_init_fdt_scan_reserved_mem();
|
||||
|
||||
if (IS_ENABLED(CONFIG_ZONE_DMA32))
|
||||
arm64_dma32_phys_limit = max_zone_phys(32);
|
||||
else
|
||||
arm64_dma32_phys_limit = PHYS_MASK + 1;
|
||||
|
||||
reserve_elfcorehdr();
|
||||
|
||||
high_memory = __va(memblock_end_of_DRAM() - 1) + 1;
|
||||
|
||||
dma_contiguous_reserve(arm64_dma32_phys_limit);
|
||||
}
|
||||
|
||||
void __init bootmem_init(void)
|
||||
|
|
@ -438,6 +436,11 @@ void __init bootmem_init(void)
|
|||
sparse_init();
|
||||
zone_sizes_init(min, max);
|
||||
|
||||
/*
|
||||
* Reserve the CMA area after arm64_dma_phys_limit was initialised.
|
||||
*/
|
||||
dma_contiguous_reserve(arm64_dma_phys_limit);
|
||||
|
||||
/*
|
||||
* request_standard_resources() depends on crashkernel's memory being
|
||||
* reserved, so do it here.
|
||||
|
|
@ -455,7 +458,7 @@ void __init bootmem_init(void)
|
|||
void __init mem_init(void)
|
||||
{
|
||||
if (swiotlb_force == SWIOTLB_FORCE ||
|
||||
max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit))
|
||||
max_pfn > PFN_DOWN(arm64_dma_phys_limit))
|
||||
swiotlb_init(1);
|
||||
else
|
||||
swiotlb_force = SWIOTLB_NO_FORCE;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/libfdt.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/*
|
||||
* These two variables specify the free mem region
|
||||
|
|
@ -117,7 +118,7 @@ void decompress_kernel(unsigned long boot_heap_start)
|
|||
dtb_size = fdt_totalsize((void *)&__appended_dtb);
|
||||
|
||||
/* last four bytes is always image size in little endian */
|
||||
image_size = le32_to_cpup((void *)&__image_end - 4);
|
||||
image_size = get_unaligned_le32((void *)&__image_end - 4);
|
||||
|
||||
/* copy dtb to where the booted kernel will expect it */
|
||||
memcpy((void *)VMLINUX_LOAD_ADDRESS_ULL + image_size,
|
||||
|
|
|
|||
|
|
@ -1444,7 +1444,7 @@ static void octeon_irq_setup_secondary_ciu2(void)
|
|||
static int __init octeon_irq_init_ciu(
|
||||
struct device_node *ciu_node, struct device_node *parent)
|
||||
{
|
||||
unsigned int i, r;
|
||||
int i, r;
|
||||
struct irq_chip *chip;
|
||||
struct irq_chip *chip_edge;
|
||||
struct irq_chip *chip_mbox;
|
||||
|
|
|
|||
|
|
@ -103,4 +103,11 @@ jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value)
|
|||
#undef ns_to_kernel_old_timeval
|
||||
#define ns_to_kernel_old_timeval ns_to_old_timeval32
|
||||
|
||||
/*
|
||||
* Some data types as stored in coredump.
|
||||
*/
|
||||
#define user_long_t compat_long_t
|
||||
#define user_siginfo_t compat_siginfo_t
|
||||
#define copy_siginfo_to_external copy_siginfo_to_external32
|
||||
|
||||
#include "../../../fs/binfmt_elf.c"
|
||||
|
|
|
|||
|
|
@ -106,4 +106,11 @@ jiffies_to_old_timeval32(unsigned long jiffies, struct old_timeval32 *value)
|
|||
#undef ns_to_kernel_old_timeval
|
||||
#define ns_to_kernel_old_timeval ns_to_old_timeval32
|
||||
|
||||
/*
|
||||
* Some data types as stored in coredump.
|
||||
*/
|
||||
#define user_long_t compat_long_t
|
||||
#define user_siginfo_t compat_siginfo_t
|
||||
#define copy_siginfo_to_external copy_siginfo_to_external32
|
||||
|
||||
#include "../../../fs/binfmt_elf.c"
|
||||
|
|
|
|||
|
|
@ -187,8 +187,14 @@ static int __init relocate_exception_table(long offset)
|
|||
static inline __init unsigned long rotate_xor(unsigned long hash,
|
||||
const void *area, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
unsigned long *ptr = (unsigned long *)area;
|
||||
const typeof(hash) *ptr = PTR_ALIGN(area, sizeof(hash));
|
||||
size_t diff, i;
|
||||
|
||||
diff = (void *)ptr - area;
|
||||
if (unlikely(size < diff + sizeof(hash)))
|
||||
return hash;
|
||||
|
||||
size = ALIGN_DOWN(size - diff, sizeof(hash));
|
||||
|
||||
for (i = 0; i < size / sizeof(hash); i++) {
|
||||
/* Rotate by odd number of bits and XOR. */
|
||||
|
|
|
|||
|
|
@ -103,6 +103,8 @@ int gettimeofday_fallback(struct __kernel_old_timeval *_tv, struct timezone *_tz
|
|||
return do_syscall_2(__NR_gettimeofday, (unsigned long)_tv, (unsigned long)_tz);
|
||||
}
|
||||
|
||||
#ifdef __powerpc64__
|
||||
|
||||
static __always_inline
|
||||
int clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
||||
{
|
||||
|
|
@ -115,10 +117,22 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
|||
return do_syscall_2(__NR_clock_getres, _clkid, (unsigned long)_ts);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VDSO32
|
||||
#else
|
||||
|
||||
#define BUILD_VDSO32 1
|
||||
|
||||
static __always_inline
|
||||
int clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
||||
{
|
||||
return do_syscall_2(__NR_clock_gettime64, _clkid, (unsigned long)_ts);
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
|
||||
{
|
||||
return do_syscall_2(__NR_clock_getres_time64, _clkid, (unsigned long)_ts);
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
int clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -187,6 +187,12 @@ SECTIONS
|
|||
.init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
|
||||
_sinittext = .;
|
||||
INIT_TEXT
|
||||
|
||||
/*
|
||||
*.init.text might be RO so we must ensure this section ends on
|
||||
* a page boundary.
|
||||
*/
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
_einittext = .;
|
||||
#ifdef CONFIG_PPC64
|
||||
*(.tramp.ftrace.init);
|
||||
|
|
@ -200,6 +206,8 @@ SECTIONS
|
|||
EXIT_TEXT
|
||||
}
|
||||
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
|
||||
INIT_DATA_SECTION(16)
|
||||
|
||||
. = ALIGN(8);
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ config PA_BITS
|
|||
|
||||
config PAGE_OFFSET
|
||||
hex
|
||||
default 0xC0000000 if 32BIT && MAXPHYSMEM_2GB
|
||||
default 0xC0000000 if 32BIT && MAXPHYSMEM_1GB
|
||||
default 0x80000000 if 64BIT && !MMU
|
||||
default 0xffffffff80000000 if 64BIT && MAXPHYSMEM_2GB
|
||||
default 0xffffffe000000000 if 64BIT && MAXPHYSMEM_128GB
|
||||
|
|
@ -247,10 +247,12 @@ config MODULE_SECTIONS
|
|||
|
||||
choice
|
||||
prompt "Maximum Physical Memory"
|
||||
default MAXPHYSMEM_2GB if 32BIT
|
||||
default MAXPHYSMEM_1GB if 32BIT
|
||||
default MAXPHYSMEM_2GB if 64BIT && CMODEL_MEDLOW
|
||||
default MAXPHYSMEM_128GB if 64BIT && CMODEL_MEDANY
|
||||
|
||||
config MAXPHYSMEM_1GB
|
||||
bool "1GiB"
|
||||
config MAXPHYSMEM_2GB
|
||||
bool "2GiB"
|
||||
config MAXPHYSMEM_128GB
|
||||
|
|
|
|||
|
|
@ -88,7 +88,9 @@ ð0 {
|
|||
phy-mode = "gmii";
|
||||
phy-handle = <&phy0>;
|
||||
phy0: ethernet-phy@0 {
|
||||
compatible = "ethernet-phy-id0007.0771";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio 12 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ CONFIG_HW_RANDOM=y
|
|||
CONFIG_HW_RANDOM_VIRTIO=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_SIFIVE=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIO_SIFIVE=y
|
||||
# CONFIG_PTP_1588_CLOCK is not set
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_DRM=y
|
||||
|
|
|
|||
|
|
@ -99,7 +99,6 @@
|
|||
| _PAGE_DIRTY)
|
||||
|
||||
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
|
||||
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
|
||||
#define PAGE_KERNEL_READ __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
|
||||
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL | _PAGE_EXEC)
|
||||
#define PAGE_KERNEL_READ_EXEC __pgprot((_PAGE_KERNEL & ~_PAGE_WRITE) \
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifndef GENERIC_TIME_VSYSCALL
|
||||
#ifndef CONFIG_GENERIC_TIME_VSYSCALL
|
||||
struct vdso_data {
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -26,7 +26,16 @@ cache_get_priv_group(struct cacheinfo *this_leaf)
|
|||
|
||||
static struct cacheinfo *get_cacheinfo(u32 level, enum cache_type type)
|
||||
{
|
||||
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(smp_processor_id());
|
||||
/*
|
||||
* Using raw_smp_processor_id() elides a preemptability check, but this
|
||||
* is really indicative of a larger problem: the cacheinfo UABI assumes
|
||||
* that cores have a homonogenous view of the cache hierarchy. That
|
||||
* happens to be the case for the current set of RISC-V systems, but
|
||||
* likely won't be true in general. Since there's no way to provide
|
||||
* correct information for these systems via the current UABI we're
|
||||
* just eliding the check for now.
|
||||
*/
|
||||
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(raw_smp_processor_id());
|
||||
struct cacheinfo *this_leaf;
|
||||
int index;
|
||||
|
||||
|
|
|
|||
|
|
@ -124,15 +124,15 @@ skip_context_tracking:
|
|||
REG_L a1, (a1)
|
||||
jr a1
|
||||
1:
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
call trace_hardirqs_on
|
||||
#endif
|
||||
/*
|
||||
* Exceptions run with interrupts enabled or disabled depending on the
|
||||
* state of SR_PIE in m/sstatus.
|
||||
*/
|
||||
andi t0, s1, SR_PIE
|
||||
beqz t0, 1f
|
||||
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||
call trace_hardirqs_on
|
||||
#endif
|
||||
csrs CSR_STATUS, SR_IE
|
||||
|
||||
1:
|
||||
|
|
@ -155,6 +155,15 @@ skip_context_tracking:
|
|||
tail do_trap_unknown
|
||||
|
||||
handle_syscall:
|
||||
#ifdef CONFIG_RISCV_M_MODE
|
||||
/*
|
||||
* When running is M-Mode (no MMU config), MPIE does not get set.
|
||||
* As a result, we need to force enable interrupts here because
|
||||
* handle_exception did not do set SR_IE as it always sees SR_PIE
|
||||
* being cleared.
|
||||
*/
|
||||
csrs CSR_STATUS, SR_IE
|
||||
#endif
|
||||
#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING)
|
||||
/* Recover a0 - a7 for system calls */
|
||||
REG_L a0, PT_A0(sp)
|
||||
|
|
@ -186,14 +195,7 @@ check_syscall_nr:
|
|||
* Syscall number held in a7.
|
||||
* If syscall number is above allowed value, redirect to ni_syscall.
|
||||
*/
|
||||
bge a7, t0, 1f
|
||||
/*
|
||||
* Check if syscall is rejected by tracer, i.e., a7 == -1.
|
||||
* If yes, we pretend it was executed.
|
||||
*/
|
||||
li t1, -1
|
||||
beq a7, t1, ret_from_syscall_rejected
|
||||
blt a7, t1, 1f
|
||||
bgeu a7, t0, 1f
|
||||
/* Call syscall */
|
||||
la s0, sys_call_table
|
||||
slli t0, a7, RISCV_LGPTR
|
||||
|
|
|
|||
|
|
@ -127,7 +127,9 @@ static void __init init_resources(void)
|
|||
{
|
||||
struct memblock_region *region = NULL;
|
||||
struct resource *res = NULL;
|
||||
int ret = 0;
|
||||
struct resource *mem_res = NULL;
|
||||
size_t mem_res_sz = 0;
|
||||
int ret = 0, i = 0;
|
||||
|
||||
code_res.start = __pa_symbol(_text);
|
||||
code_res.end = __pa_symbol(_etext) - 1;
|
||||
|
|
@ -145,16 +147,17 @@ static void __init init_resources(void)
|
|||
bss_res.end = __pa_symbol(__bss_stop) - 1;
|
||||
bss_res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
|
||||
|
||||
mem_res_sz = (memblock.memory.cnt + memblock.reserved.cnt) * sizeof(*mem_res);
|
||||
mem_res = memblock_alloc(mem_res_sz, SMP_CACHE_BYTES);
|
||||
if (!mem_res)
|
||||
panic("%s: Failed to allocate %zu bytes\n", __func__, mem_res_sz);
|
||||
/*
|
||||
* Start by adding the reserved regions, if they overlap
|
||||
* with /memory regions, insert_resource later on will take
|
||||
* care of it.
|
||||
*/
|
||||
for_each_reserved_mem_region(region) {
|
||||
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
|
||||
if (!res)
|
||||
panic("%s: Failed to allocate %zu bytes\n", __func__,
|
||||
sizeof(struct resource));
|
||||
res = &mem_res[i++];
|
||||
|
||||
res->name = "Reserved";
|
||||
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
|
||||
|
|
@ -171,8 +174,10 @@ static void __init init_resources(void)
|
|||
* Ignore any other reserved regions within
|
||||
* system memory.
|
||||
*/
|
||||
if (memblock_is_memory(res->start))
|
||||
if (memblock_is_memory(res->start)) {
|
||||
memblock_free((phys_addr_t) res, sizeof(struct resource));
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = add_resource(&iomem_resource, res);
|
||||
if (ret < 0)
|
||||
|
|
@ -181,10 +186,7 @@ static void __init init_resources(void)
|
|||
|
||||
/* Add /memory regions to the resource tree */
|
||||
for_each_mem_region(region) {
|
||||
res = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);
|
||||
if (!res)
|
||||
panic("%s: Failed to allocate %zu bytes\n", __func__,
|
||||
sizeof(struct resource));
|
||||
res = &mem_res[i++];
|
||||
|
||||
if (unlikely(memblock_is_nomap(region))) {
|
||||
res->name = "Reserved";
|
||||
|
|
@ -205,9 +207,9 @@ static void __init init_resources(void)
|
|||
return;
|
||||
|
||||
error:
|
||||
memblock_free((phys_addr_t) res, sizeof(struct resource));
|
||||
/* Better an empty resource tree than an inconsistent one */
|
||||
release_child_resources(&iomem_resource);
|
||||
memblock_free((phys_addr_t) mem_res, mem_res_sz);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
register unsigned long sp_in_global __asm__("sp");
|
||||
register const unsigned long sp_in_global __asm__("sp");
|
||||
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
|
||||
|
|
@ -28,9 +28,8 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
|
|||
sp = user_stack_pointer(regs);
|
||||
pc = instruction_pointer(regs);
|
||||
} else if (task == NULL || task == current) {
|
||||
const register unsigned long current_sp = sp_in_global;
|
||||
fp = (unsigned long)__builtin_frame_address(0);
|
||||
sp = current_sp;
|
||||
sp = sp_in_global;
|
||||
pc = (unsigned long)walk_stackframe;
|
||||
} else {
|
||||
/* task blocked in __switch_to */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* Copyright (C) 2017 SiFive
|
||||
*/
|
||||
|
||||
#include <linux/of_clk.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/sbi.h>
|
||||
|
|
@ -24,6 +25,8 @@ void __init time_init(void)
|
|||
riscv_timebase = prop;
|
||||
|
||||
lpj_fine = riscv_timebase / HZ;
|
||||
|
||||
of_clk_init(NULL);
|
||||
timer_probe();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#include <linux/binfmts.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/page.h>
|
||||
#ifdef GENERIC_TIME_VSYSCALL
|
||||
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
|
||||
#include <vdso/datapage.h>
|
||||
#else
|
||||
#include <asm/vdso.h>
|
||||
|
|
|
|||
|
|
@ -157,9 +157,10 @@ static void __init setup_initrd(void)
|
|||
void __init setup_bootmem(void)
|
||||
{
|
||||
phys_addr_t mem_start = 0;
|
||||
phys_addr_t start, end = 0;
|
||||
phys_addr_t start, dram_end, end = 0;
|
||||
phys_addr_t vmlinux_end = __pa_symbol(&_end);
|
||||
phys_addr_t vmlinux_start = __pa_symbol(&_start);
|
||||
phys_addr_t max_mapped_addr = __pa(~(ulong)0);
|
||||
u64 i;
|
||||
|
||||
/* Find the memory region containing the kernel */
|
||||
|
|
@ -181,7 +182,18 @@ void __init setup_bootmem(void)
|
|||
/* Reserve from the start of the kernel to the end of the kernel */
|
||||
memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
|
||||
|
||||
max_pfn = PFN_DOWN(memblock_end_of_DRAM());
|
||||
dram_end = memblock_end_of_DRAM();
|
||||
|
||||
/*
|
||||
* memblock allocator is not aware of the fact that last 4K bytes of
|
||||
* the addressable memory can not be mapped because of IS_ERR_VALUE
|
||||
* macro. Make sure that last 4k bytes are not usable by memblock
|
||||
* if end of dram is equal to maximum addressable memory.
|
||||
*/
|
||||
if (max_mapped_addr == (dram_end - 1))
|
||||
memblock_set_current_limit(max_mapped_addr - 4096);
|
||||
|
||||
max_pfn = PFN_DOWN(dram_end);
|
||||
max_low_pfn = max_pfn;
|
||||
dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn));
|
||||
set_max_mapnr(max_low_pfn);
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ void __init kasan_init(void)
|
|||
VMALLOC_END));
|
||||
|
||||
for_each_mem_range(i, &_start, &_end) {
|
||||
void *start = (void *)_start;
|
||||
void *end = (void *)_end;
|
||||
void *start = (void *)__va(_start);
|
||||
void *end = (void *)__va(_end);
|
||||
|
||||
if (start >= end)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -164,10 +164,10 @@ static int xen_cpu_up_prepare_hvm(unsigned int cpu)
|
|||
else
|
||||
per_cpu(xen_vcpu_id, cpu) = cpu;
|
||||
rc = xen_vcpu_setup(cpu);
|
||||
if (rc)
|
||||
if (rc || !xen_have_vector_callback)
|
||||
return rc;
|
||||
|
||||
if (xen_have_vector_callback && xen_feature(XENFEAT_hvm_safe_pvclock))
|
||||
if (xen_feature(XENFEAT_hvm_safe_pvclock))
|
||||
xen_setup_timer(cpu);
|
||||
|
||||
rc = xen_smp_intr_init(cpu);
|
||||
|
|
@ -188,6 +188,8 @@ static int xen_cpu_dead_hvm(unsigned int cpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool no_vector_callback __initdata;
|
||||
|
||||
static void __init xen_hvm_guest_init(void)
|
||||
{
|
||||
if (xen_pv_domain())
|
||||
|
|
@ -207,7 +209,7 @@ static void __init xen_hvm_guest_init(void)
|
|||
|
||||
xen_panic_handler_init();
|
||||
|
||||
if (xen_feature(XENFEAT_hvm_callback_vector))
|
||||
if (!no_vector_callback && xen_feature(XENFEAT_hvm_callback_vector))
|
||||
xen_have_vector_callback = 1;
|
||||
|
||||
xen_hvm_smp_init();
|
||||
|
|
@ -233,6 +235,13 @@ static __init int xen_parse_nopv(char *arg)
|
|||
}
|
||||
early_param("xen_nopv", xen_parse_nopv);
|
||||
|
||||
static __init int xen_parse_no_vector_callback(char *arg)
|
||||
{
|
||||
no_vector_callback = true;
|
||||
return 0;
|
||||
}
|
||||
early_param("xen_no_vector_callback", xen_parse_no_vector_callback);
|
||||
|
||||
bool __init xen_hvm_need_lapic(void)
|
||||
{
|
||||
if (xen_pv_domain())
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
|
|||
int cpu;
|
||||
|
||||
native_smp_prepare_cpus(max_cpus);
|
||||
WARN_ON(xen_smp_intr_init(0));
|
||||
|
||||
xen_init_lock_cpu(0);
|
||||
if (xen_have_vector_callback) {
|
||||
WARN_ON(xen_smp_intr_init(0));
|
||||
xen_init_lock_cpu(0);
|
||||
}
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (cpu == 0)
|
||||
|
|
@ -50,9 +52,11 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
|
|||
static void xen_hvm_cpu_die(unsigned int cpu)
|
||||
{
|
||||
if (common_cpu_die(cpu) == 0) {
|
||||
xen_smp_intr_free(cpu);
|
||||
xen_uninit_lock_cpu(cpu);
|
||||
xen_teardown_timer(cpu);
|
||||
if (xen_have_vector_callback) {
|
||||
xen_smp_intr_free(cpu);
|
||||
xen_uninit_lock_cpu(cpu);
|
||||
xen_teardown_timer(cpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
@ -64,14 +68,17 @@ static void xen_hvm_cpu_die(unsigned int cpu)
|
|||
|
||||
void __init xen_hvm_smp_init(void)
|
||||
{
|
||||
if (!xen_have_vector_callback)
|
||||
return;
|
||||
|
||||
smp_ops.smp_prepare_boot_cpu = xen_hvm_smp_prepare_boot_cpu;
|
||||
smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
|
||||
smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
|
||||
smp_ops.smp_cpus_done = xen_smp_cpus_done;
|
||||
smp_ops.cpu_die = xen_hvm_cpu_die;
|
||||
|
||||
if (!xen_have_vector_callback) {
|
||||
nopvspin = true;
|
||||
return;
|
||||
}
|
||||
|
||||
smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
|
||||
smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
|
||||
smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi;
|
||||
smp_ops.smp_prepare_boot_cpu = xen_hvm_smp_prepare_boot_cpu;
|
||||
smp_ops.smp_cpus_done = xen_smp_cpus_done;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ void acpi_scan_table_handler(u32 event, void *table, void *context);
|
|||
extern struct list_head acpi_bus_id_list;
|
||||
|
||||
struct acpi_device_bus_id {
|
||||
char bus_id[15];
|
||||
const char *bus_id;
|
||||
unsigned int instance_no;
|
||||
struct list_head node;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -486,6 +486,7 @@ static void acpi_device_del(struct acpi_device *device)
|
|||
acpi_device_bus_id->instance_no--;
|
||||
else {
|
||||
list_del(&acpi_device_bus_id->node);
|
||||
kfree_const(acpi_device_bus_id->bus_id);
|
||||
kfree(acpi_device_bus_id);
|
||||
}
|
||||
break;
|
||||
|
|
@ -674,7 +675,14 @@ int acpi_device_add(struct acpi_device *device,
|
|||
}
|
||||
if (!found) {
|
||||
acpi_device_bus_id = new_bus_id;
|
||||
strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device));
|
||||
acpi_device_bus_id->bus_id =
|
||||
kstrdup_const(acpi_device_hid(device), GFP_KERNEL);
|
||||
if (!acpi_device_bus_id->bus_id) {
|
||||
pr_err(PREFIX "Memory allocation error for bus id\n");
|
||||
result = -ENOMEM;
|
||||
goto err_free_new_bus_id;
|
||||
}
|
||||
|
||||
acpi_device_bus_id->instance_no = 0;
|
||||
list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
|
||||
}
|
||||
|
|
@ -709,6 +717,11 @@ int acpi_device_add(struct acpi_device *device,
|
|||
if (device->parent)
|
||||
list_del(&device->node);
|
||||
list_del(&device->wakeup_list);
|
||||
|
||||
err_free_new_bus_id:
|
||||
if (!found)
|
||||
kfree(new_bus_id);
|
||||
|
||||
mutex_unlock(&acpi_device_lock);
|
||||
|
||||
err_detach:
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ nouveau-y += dispnv50/wimmc37b.o
|
|||
nouveau-y += dispnv50/wndw.o
|
||||
nouveau-y += dispnv50/wndwc37e.o
|
||||
nouveau-y += dispnv50/wndwc57e.o
|
||||
nouveau-y += dispnv50/wndwc67e.o
|
||||
|
||||
nouveau-y += dispnv50/base.o
|
||||
nouveau-y += dispnv50/base507c.o
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ nv50_core_new(struct nouveau_drm *drm, struct nv50_core **pcore)
|
|||
int version;
|
||||
int (*new)(struct nouveau_drm *, s32, struct nv50_core **);
|
||||
} cores[] = {
|
||||
{ GA102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
|
||||
{ TU102_DISP_CORE_CHANNEL_DMA, 0, corec57d_new },
|
||||
{ GV100_DISP_CORE_CHANNEL_DMA, 0, corec37d_new },
|
||||
{ GP102_DISP_CORE_CHANNEL_DMA, 0, core917d_new },
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ nv50_curs_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw)
|
|||
int version;
|
||||
int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
|
||||
} curses[] = {
|
||||
{ GA102_DISP_CURSOR, 0, cursc37a_new },
|
||||
{ TU102_DISP_CURSOR, 0, cursc37a_new },
|
||||
{ GV100_DISP_CURSOR, 0, cursc37a_new },
|
||||
{ GK104_DISP_CURSOR, 0, curs907a_new },
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ nv50_wimm_init(struct nouveau_drm *drm, struct nv50_wndw *wndw)
|
|||
int version;
|
||||
int (*init)(struct nouveau_drm *, s32, struct nv50_wndw *);
|
||||
} wimms[] = {
|
||||
{ GA102_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
|
||||
{ TU102_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
|
||||
{ GV100_DISP_WINDOW_IMM_CHANNEL_DMA, 0, wimmc37b_init },
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -784,6 +784,7 @@ nv50_wndw_new(struct nouveau_drm *drm, enum drm_plane_type type, int index,
|
|||
int (*new)(struct nouveau_drm *, enum drm_plane_type,
|
||||
int, s32, struct nv50_wndw **);
|
||||
} wndws[] = {
|
||||
{ GA102_DISP_WINDOW_CHANNEL_DMA, 0, wndwc67e_new },
|
||||
{ TU102_DISP_WINDOW_CHANNEL_DMA, 0, wndwc57e_new },
|
||||
{ GV100_DISP_WINDOW_CHANNEL_DMA, 0, wndwc37e_new },
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,14 @@ int wndwc37e_update(struct nv50_wndw *, u32 *);
|
|||
|
||||
int wndwc57e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
|
||||
struct nv50_wndw **);
|
||||
bool wndwc57e_ilut(struct nv50_wndw *, struct nv50_wndw_atom *, int);
|
||||
int wndwc57e_ilut_set(struct nv50_wndw *, struct nv50_wndw_atom *);
|
||||
int wndwc57e_ilut_clr(struct nv50_wndw *);
|
||||
int wndwc57e_csc_set(struct nv50_wndw *, struct nv50_wndw_atom *);
|
||||
int wndwc57e_csc_clr(struct nv50_wndw *);
|
||||
|
||||
int wndwc67e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
|
||||
struct nv50_wndw **);
|
||||
|
||||
int nv50_wndw_new(struct nouveau_drm *, enum drm_plane_type, int index,
|
||||
struct nv50_wndw **);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ wndwc57e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
wndwc57e_csc_clr(struct nv50_wndw *wndw)
|
||||
{
|
||||
struct nvif_push *push = wndw->wndw.push;
|
||||
|
|
@ -98,7 +98,7 @@ wndwc57e_csc_clr(struct nv50_wndw *wndw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
wndwc57e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
|
||||
{
|
||||
struct nvif_push *push = wndw->wndw.push;
|
||||
|
|
@ -111,7 +111,7 @@ wndwc57e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
wndwc57e_ilut_clr(struct nv50_wndw *wndw)
|
||||
{
|
||||
struct nvif_push *push = wndw->wndw.push;
|
||||
|
|
@ -124,7 +124,7 @@ wndwc57e_ilut_clr(struct nv50_wndw *wndw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
wndwc57e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
|
||||
{
|
||||
struct nvif_push *push = wndw->wndw.push;
|
||||
|
|
@ -179,7 +179,7 @@ wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem)
|
|||
writew(readw(mem - 4), mem + 4);
|
||||
}
|
||||
|
||||
static bool
|
||||
bool
|
||||
wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size)
|
||||
{
|
||||
if (size = size ? size : 1024, size != 256 && size != 1024)
|
||||
|
|
|
|||
106
drivers/gpu/drm/nouveau/dispnv50/wndwc67e.c
Normal file
106
drivers/gpu/drm/nouveau/dispnv50/wndwc67e.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "wndw.h"
|
||||
#include "atom.h"
|
||||
|
||||
#include <nvif/pushc37b.h>
|
||||
|
||||
#include <nvhw/class/clc57e.h>
|
||||
|
||||
static int
|
||||
wndwc67e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
|
||||
{
|
||||
struct nvif_push *push = wndw->wndw.push;
|
||||
int ret;
|
||||
|
||||
if ((ret = PUSH_WAIT(push, 17)))
|
||||
return ret;
|
||||
|
||||
PUSH_MTHD(push, NVC57E, SET_PRESENT_CONTROL,
|
||||
NVVAL(NVC57E, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval) |
|
||||
NVVAL(NVC57E, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) |
|
||||
NVDEF(NVC57E, SET_PRESENT_CONTROL, TIMESTAMP_MODE, DISABLE));
|
||||
|
||||
PUSH_MTHD(push, NVC57E, SET_SIZE,
|
||||
NVVAL(NVC57E, SET_SIZE, WIDTH, asyw->image.w) |
|
||||
NVVAL(NVC57E, SET_SIZE, HEIGHT, asyw->image.h),
|
||||
|
||||
SET_STORAGE,
|
||||
NVVAL(NVC57E, SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh),
|
||||
|
||||
SET_PARAMS,
|
||||
NVVAL(NVC57E, SET_PARAMS, FORMAT, asyw->image.format) |
|
||||
NVDEF(NVC57E, SET_PARAMS, CLAMP_BEFORE_BLEND, DISABLE) |
|
||||
NVDEF(NVC57E, SET_PARAMS, SWAP_UV, DISABLE) |
|
||||
NVDEF(NVC57E, SET_PARAMS, FMT_ROUNDING_MODE, ROUND_TO_NEAREST),
|
||||
|
||||
SET_PLANAR_STORAGE(0),
|
||||
NVVAL(NVC57E, SET_PLANAR_STORAGE, PITCH, asyw->image.blocks[0]) |
|
||||
NVVAL(NVC57E, SET_PLANAR_STORAGE, PITCH, asyw->image.pitch[0] >> 6));
|
||||
|
||||
PUSH_MTHD(push, NVC57E, SET_CONTEXT_DMA_ISO(0), asyw->image.handle, 1);
|
||||
PUSH_MTHD(push, NVC57E, SET_OFFSET(0), asyw->image.offset[0] >> 8);
|
||||
|
||||
PUSH_MTHD(push, NVC57E, SET_POINT_IN(0),
|
||||
NVVAL(NVC57E, SET_POINT_IN, X, asyw->state.src_x >> 16) |
|
||||
NVVAL(NVC57E, SET_POINT_IN, Y, asyw->state.src_y >> 16));
|
||||
|
||||
PUSH_MTHD(push, NVC57E, SET_SIZE_IN,
|
||||
NVVAL(NVC57E, SET_SIZE_IN, WIDTH, asyw->state.src_w >> 16) |
|
||||
NVVAL(NVC57E, SET_SIZE_IN, HEIGHT, asyw->state.src_h >> 16));
|
||||
|
||||
PUSH_MTHD(push, NVC57E, SET_SIZE_OUT,
|
||||
NVVAL(NVC57E, SET_SIZE_OUT, WIDTH, asyw->state.crtc_w) |
|
||||
NVVAL(NVC57E, SET_SIZE_OUT, HEIGHT, asyw->state.crtc_h));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nv50_wndw_func
|
||||
wndwc67e = {
|
||||
.acquire = wndwc37e_acquire,
|
||||
.release = wndwc37e_release,
|
||||
.sema_set = wndwc37e_sema_set,
|
||||
.sema_clr = wndwc37e_sema_clr,
|
||||
.ntfy_set = wndwc37e_ntfy_set,
|
||||
.ntfy_clr = wndwc37e_ntfy_clr,
|
||||
.ntfy_reset = corec37d_ntfy_init,
|
||||
.ntfy_wait_begun = base507c_ntfy_wait_begun,
|
||||
.ilut = wndwc57e_ilut,
|
||||
.ilut_identity = true,
|
||||
.ilut_size = 1024,
|
||||
.xlut_set = wndwc57e_ilut_set,
|
||||
.xlut_clr = wndwc57e_ilut_clr,
|
||||
.csc = base907c_csc,
|
||||
.csc_set = wndwc57e_csc_set,
|
||||
.csc_clr = wndwc57e_csc_clr,
|
||||
.image_set = wndwc67e_image_set,
|
||||
.image_clr = wndwc37e_image_clr,
|
||||
.blend_set = wndwc37e_blend_set,
|
||||
.update = wndwc37e_update,
|
||||
};
|
||||
|
||||
int
|
||||
wndwc67e_new(struct nouveau_drm *drm, enum drm_plane_type type, int index,
|
||||
s32 oclass, struct nv50_wndw **pwndw)
|
||||
{
|
||||
return wndwc37e_new_(&wndwc67e, drm, type, index, oclass, BIT(index >> 1), pwndw);
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ struct nv_device_info_v0 {
|
|||
#define NV_DEVICE_INFO_V0_PASCAL 0x0a
|
||||
#define NV_DEVICE_INFO_V0_VOLTA 0x0b
|
||||
#define NV_DEVICE_INFO_V0_TURING 0x0c
|
||||
#define NV_DEVICE_INFO_V0_AMPERE 0x0d
|
||||
__u8 family;
|
||||
__u8 pad06[2];
|
||||
__u64 ram_size;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@
|
|||
#define GP102_DISP /* cl5070.h */ 0x00009870
|
||||
#define GV100_DISP /* cl5070.h */ 0x0000c370
|
||||
#define TU102_DISP /* cl5070.h */ 0x0000c570
|
||||
#define GA102_DISP /* cl5070.h */ 0x0000c670
|
||||
|
||||
#define GV100_DISP_CAPS 0x0000c373
|
||||
|
||||
|
|
@ -103,6 +104,7 @@
|
|||
#define GK104_DISP_CURSOR /* cl507a.h */ 0x0000917a
|
||||
#define GV100_DISP_CURSOR /* cl507a.h */ 0x0000c37a
|
||||
#define TU102_DISP_CURSOR /* cl507a.h */ 0x0000c57a
|
||||
#define GA102_DISP_CURSOR /* cl507a.h */ 0x0000c67a
|
||||
|
||||
#define NV50_DISP_OVERLAY /* cl507b.h */ 0x0000507b
|
||||
#define G82_DISP_OVERLAY /* cl507b.h */ 0x0000827b
|
||||
|
|
@ -112,6 +114,7 @@
|
|||
|
||||
#define GV100_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c37b
|
||||
#define TU102_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c57b
|
||||
#define GA102_DISP_WINDOW_IMM_CHANNEL_DMA /* clc37b.h */ 0x0000c67b
|
||||
|
||||
#define NV50_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000507c
|
||||
#define G82_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000827c
|
||||
|
|
@ -135,6 +138,7 @@
|
|||
#define GP102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000987d
|
||||
#define GV100_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c37d
|
||||
#define TU102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c57d
|
||||
#define GA102_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000c67d
|
||||
|
||||
#define NV50_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000507e
|
||||
#define G82_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000827e
|
||||
|
|
@ -145,6 +149,7 @@
|
|||
|
||||
#define GV100_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c37e
|
||||
#define TU102_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c57e
|
||||
#define GA102_DISP_WINDOW_CHANNEL_DMA /* clc37e.h */ 0x0000c67e
|
||||
|
||||
#define NV50_TESLA 0x00005097
|
||||
#define G82_TESLA 0x00008297
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ struct nvkm_device {
|
|||
GP100 = 0x130,
|
||||
GV100 = 0x140,
|
||||
TU100 = 0x160,
|
||||
GA100 = 0x170,
|
||||
} card_type;
|
||||
u32 chipset;
|
||||
u8 chiprev;
|
||||
|
|
|
|||
|
|
@ -37,4 +37,5 @@ int gp100_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
|
|||
int gp102_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
|
||||
int gv100_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
|
||||
int tu102_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
|
||||
int ga102_disp_new(struct nvkm_device *, int, struct nvkm_disp **);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,4 +32,5 @@ int gm107_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
|
|||
int gm200_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
|
||||
int gv100_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
|
||||
int tu102_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
|
||||
int ga100_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ int gp100_fb_new(struct nvkm_device *, int, struct nvkm_fb **);
|
|||
int gp102_fb_new(struct nvkm_device *, int, struct nvkm_fb **);
|
||||
int gp10b_fb_new(struct nvkm_device *, int, struct nvkm_fb **);
|
||||
int gv100_fb_new(struct nvkm_device *, int, struct nvkm_fb **);
|
||||
int ga100_fb_new(struct nvkm_device *, int, struct nvkm_fb **);
|
||||
int ga102_fb_new(struct nvkm_device *, int, struct nvkm_fb **);
|
||||
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/ramcfg.h>
|
||||
|
|
|
|||
|
|
@ -37,4 +37,5 @@ int nv50_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **);
|
|||
int g94_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **);
|
||||
int gf119_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **);
|
||||
int gk104_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **);
|
||||
int ga102_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,4 +32,5 @@ int gk20a_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
|
|||
int gp100_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
|
||||
int gp10b_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
|
||||
int tu102_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
|
||||
int ga100_mc_new(struct nvkm_device *, int, struct nvkm_mc **);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ nouveau_backlight_init(struct drm_connector *connector)
|
|||
case NV_DEVICE_INFO_V0_PASCAL:
|
||||
case NV_DEVICE_INFO_V0_VOLTA:
|
||||
case NV_DEVICE_INFO_V0_TURING:
|
||||
case NV_DEVICE_INFO_V0_AMPERE: //XXX: not confirmed
|
||||
ret = nv50_backlight_init(nv_encoder, &props, &ops);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ nvif_disp_ctor(struct nvif_device *device, const char *name, s32 oclass,
|
|||
struct nvif_disp *disp)
|
||||
{
|
||||
static const struct nvif_mclass disps[] = {
|
||||
{ GA102_DISP, -1 },
|
||||
{ TU102_DISP, -1 },
|
||||
{ GV100_DISP, -1 },
|
||||
{ GP102_DISP, -1 },
|
||||
|
|
|
|||
|
|
@ -2652,6 +2652,61 @@ nv168_chipset = {
|
|||
.sec2 = tu102_sec2_new,
|
||||
};
|
||||
|
||||
static const struct nvkm_device_chip
|
||||
nv170_chipset = {
|
||||
.name = "GA100",
|
||||
.bar = tu102_bar_new,
|
||||
.bios = nvkm_bios_new,
|
||||
.devinit = ga100_devinit_new,
|
||||
.fb = ga100_fb_new,
|
||||
.gpio = gk104_gpio_new,
|
||||
.i2c = gm200_i2c_new,
|
||||
.ibus = gm200_ibus_new,
|
||||
.imem = nv50_instmem_new,
|
||||
.mc = ga100_mc_new,
|
||||
.mmu = tu102_mmu_new,
|
||||
.pci = gp100_pci_new,
|
||||
.timer = gk20a_timer_new,
|
||||
};
|
||||
|
||||
static const struct nvkm_device_chip
|
||||
nv172_chipset = {
|
||||
.name = "GA102",
|
||||
.bar = tu102_bar_new,
|
||||
.bios = nvkm_bios_new,
|
||||
.devinit = ga100_devinit_new,
|
||||
.fb = ga102_fb_new,
|
||||
.gpio = ga102_gpio_new,
|
||||
.i2c = gm200_i2c_new,
|
||||
.ibus = gm200_ibus_new,
|
||||
.imem = nv50_instmem_new,
|
||||
.mc = ga100_mc_new,
|
||||
.mmu = tu102_mmu_new,
|
||||
.pci = gp100_pci_new,
|
||||
.timer = gk20a_timer_new,
|
||||
.disp = ga102_disp_new,
|
||||
.dma = gv100_dma_new,
|
||||
};
|
||||
|
||||
static const struct nvkm_device_chip
|
||||
nv174_chipset = {
|
||||
.name = "GA104",
|
||||
.bar = tu102_bar_new,
|
||||
.bios = nvkm_bios_new,
|
||||
.devinit = ga100_devinit_new,
|
||||
.fb = ga102_fb_new,
|
||||
.gpio = ga102_gpio_new,
|
||||
.i2c = gm200_i2c_new,
|
||||
.ibus = gm200_ibus_new,
|
||||
.imem = nv50_instmem_new,
|
||||
.mc = ga100_mc_new,
|
||||
.mmu = tu102_mmu_new,
|
||||
.pci = gp100_pci_new,
|
||||
.timer = gk20a_timer_new,
|
||||
.disp = ga102_disp_new,
|
||||
.dma = gv100_dma_new,
|
||||
};
|
||||
|
||||
static int
|
||||
nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
|
||||
struct nvkm_notify *notify)
|
||||
|
|
@ -3063,6 +3118,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
|
|||
case 0x130: device->card_type = GP100; break;
|
||||
case 0x140: device->card_type = GV100; break;
|
||||
case 0x160: device->card_type = TU100; break;
|
||||
case 0x170: device->card_type = GA100; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -3160,10 +3216,23 @@ nvkm_device_ctor(const struct nvkm_device_func *func,
|
|||
case 0x166: device->chip = &nv166_chipset; break;
|
||||
case 0x167: device->chip = &nv167_chipset; break;
|
||||
case 0x168: device->chip = &nv168_chipset; break;
|
||||
case 0x172: device->chip = &nv172_chipset; break;
|
||||
case 0x174: device->chip = &nv174_chipset; break;
|
||||
default:
|
||||
nvdev_error(device, "unknown chipset (%08x)\n", boot0);
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
if (nvkm_boolopt(device->cfgopt, "NvEnableUnsupportedChipsets", false)) {
|
||||
switch (device->chipset) {
|
||||
case 0x170: device->chip = &nv170_chipset; break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device->chip) {
|
||||
nvdev_error(device, "unknown chipset (%08x)\n", boot0);
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
nvdev_info(device, "NVIDIA %s (%08x)\n",
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size)
|
|||
case GP100: args->v0.family = NV_DEVICE_INFO_V0_PASCAL; break;
|
||||
case GV100: args->v0.family = NV_DEVICE_INFO_V0_VOLTA; break;
|
||||
case TU100: args->v0.family = NV_DEVICE_INFO_V0_TURING; break;
|
||||
case GA100: args->v0.family = NV_DEVICE_INFO_V0_AMPERE; break;
|
||||
default:
|
||||
args->v0.family = 0;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ nvkm-y += nvkm/engine/disp/gp100.o
|
|||
nvkm-y += nvkm/engine/disp/gp102.o
|
||||
nvkm-y += nvkm/engine/disp/gv100.o
|
||||
nvkm-y += nvkm/engine/disp/tu102.o
|
||||
nvkm-y += nvkm/engine/disp/ga102.o
|
||||
nvkm-y += nvkm/engine/disp/vga.o
|
||||
|
||||
nvkm-y += nvkm/engine/disp/head.o
|
||||
|
|
@ -42,6 +43,7 @@ nvkm-y += nvkm/engine/disp/sorgm200.o
|
|||
nvkm-y += nvkm/engine/disp/sorgp100.o
|
||||
nvkm-y += nvkm/engine/disp/sorgv100.o
|
||||
nvkm-y += nvkm/engine/disp/sortu102.o
|
||||
nvkm-y += nvkm/engine/disp/sorga102.o
|
||||
|
||||
nvkm-y += nvkm/engine/disp/outp.o
|
||||
nvkm-y += nvkm/engine/disp/dp.o
|
||||
|
|
@ -75,6 +77,7 @@ nvkm-y += nvkm/engine/disp/rootgp100.o
|
|||
nvkm-y += nvkm/engine/disp/rootgp102.o
|
||||
nvkm-y += nvkm/engine/disp/rootgv100.o
|
||||
nvkm-y += nvkm/engine/disp/roottu102.o
|
||||
nvkm-y += nvkm/engine/disp/rootga102.o
|
||||
|
||||
nvkm-y += nvkm/engine/disp/capsgv100.o
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,12 @@
|
|||
|
||||
#include <nvif/event.h>
|
||||
|
||||
/* IED scripts are no longer used by UEFI/RM from Ampere, but have been updated for
|
||||
* the x86 option ROM. However, the relevant VBIOS table versions weren't modified,
|
||||
* so we're unable to detect this in a nice way.
|
||||
*/
|
||||
#define AMPERE_IED_HACK(disp) ((disp)->engine.subdev.device->card_type >= GA100)
|
||||
|
||||
struct lt_state {
|
||||
struct nvkm_dp *dp;
|
||||
u8 stat[6];
|
||||
|
|
@ -238,6 +244,19 @@ nvkm_dp_train_links(struct nvkm_dp *dp)
|
|||
dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED;
|
||||
lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED;
|
||||
|
||||
if (AMPERE_IED_HACK(disp) && (lnkcmp = lt.dp->info.script[0])) {
|
||||
/* Execute BeforeLinkTraining script from DP Info table. */
|
||||
while (ior->dp.bw < nvbios_rd08(bios, lnkcmp))
|
||||
lnkcmp += 3;
|
||||
lnkcmp = nvbios_rd16(bios, lnkcmp + 1);
|
||||
|
||||
nvbios_init(&dp->outp.disp->engine.subdev, lnkcmp,
|
||||
init.outp = &dp->outp.info;
|
||||
init.or = ior->id;
|
||||
init.link = ior->asy.link;
|
||||
);
|
||||
}
|
||||
|
||||
/* Set desired link configuration on the source. */
|
||||
if ((lnkcmp = lt.dp->info.lnkcmp)) {
|
||||
if (dp->version < 0x30) {
|
||||
|
|
@ -316,12 +335,14 @@ nvkm_dp_train_init(struct nvkm_dp *dp)
|
|||
);
|
||||
}
|
||||
|
||||
/* Execute BeforeLinkTraining script from DP Info table. */
|
||||
nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[0],
|
||||
init.outp = &dp->outp.info;
|
||||
init.or = dp->outp.ior->id;
|
||||
init.link = dp->outp.ior->asy.link;
|
||||
);
|
||||
if (!AMPERE_IED_HACK(dp->outp.disp)) {
|
||||
/* Execute BeforeLinkTraining script from DP Info table. */
|
||||
nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[0],
|
||||
init.outp = &dp->outp.info;
|
||||
init.or = dp->outp.ior->id;
|
||||
init.link = dp->outp.ior->asy.link;
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dp_rates {
|
||||
|
|
|
|||
46
drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
Normal file
46
drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nv50.h"
|
||||
#include "head.h"
|
||||
#include "ior.h"
|
||||
#include "channv50.h"
|
||||
#include "rootnv50.h"
|
||||
|
||||
static const struct nv50_disp_func
|
||||
ga102_disp = {
|
||||
.init = tu102_disp_init,
|
||||
.fini = gv100_disp_fini,
|
||||
.intr = gv100_disp_intr,
|
||||
.uevent = &gv100_disp_chan_uevent,
|
||||
.super = gv100_disp_super,
|
||||
.root = &ga102_disp_root_oclass,
|
||||
.wndw = { .cnt = gv100_disp_wndw_cnt },
|
||||
.head = { .cnt = gv100_head_cnt, .new = gv100_head_new },
|
||||
.sor = { .cnt = gv100_sor_cnt, .new = ga102_sor_new },
|
||||
.ramht_size = 0x2000,
|
||||
};
|
||||
|
||||
int
|
||||
ga102_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp)
|
||||
{
|
||||
return nv50_disp_new_(&ga102_disp, device, index, pdisp);
|
||||
}
|
||||
|
|
@ -150,6 +150,8 @@ void gv100_sor_dp_audio(struct nvkm_ior *, int, bool);
|
|||
void gv100_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32);
|
||||
void gv100_sor_dp_watermark(struct nvkm_ior *, int, u8);
|
||||
|
||||
void tu102_sor_dp_vcpi(struct nvkm_ior *, int, u8, u8, u16, u16);
|
||||
|
||||
void g84_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
|
||||
void gt215_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
|
||||
void gf119_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8);
|
||||
|
|
@ -207,4 +209,6 @@ int gv100_sor_cnt(struct nvkm_disp *, unsigned long *);
|
|||
int gv100_sor_new(struct nvkm_disp *, int);
|
||||
|
||||
int tu102_sor_new(struct nvkm_disp *, int);
|
||||
|
||||
int ga102_sor_new(struct nvkm_disp *, int);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ void gv100_disp_intr(struct nv50_disp *);
|
|||
void gv100_disp_super(struct work_struct *);
|
||||
int gv100_disp_wndw_cnt(struct nvkm_disp *, unsigned long *);
|
||||
|
||||
int tu102_disp_init(struct nv50_disp *);
|
||||
|
||||
void nv50_disp_dptmds_war_2(struct nv50_disp *, struct dcb_output *);
|
||||
void nv50_disp_dptmds_war_3(struct nv50_disp *, struct dcb_output *);
|
||||
void nv50_disp_update_sppll1(struct nv50_disp *);
|
||||
|
|
|
|||
52
drivers/gpu/drm/nouveau/nvkm/engine/disp/rootga102.c
Normal file
52
drivers/gpu/drm/nouveau/nvkm/engine/disp/rootga102.c
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "rootnv50.h"
|
||||
#include "channv50.h"
|
||||
|
||||
#include <nvif/class.h>
|
||||
|
||||
static const struct nv50_disp_root_func
|
||||
ga102_disp_root = {
|
||||
.user = {
|
||||
{{-1,-1,GV100_DISP_CAPS }, gv100_disp_caps_new },
|
||||
{{0,0,GA102_DISP_CURSOR }, gv100_disp_curs_new },
|
||||
{{0,0,GA102_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
|
||||
{{0,0,GA102_DISP_CORE_CHANNEL_DMA }, gv100_disp_core_new },
|
||||
{{0,0,GA102_DISP_WINDOW_CHANNEL_DMA }, gv100_disp_wndw_new },
|
||||
{}
|
||||
},
|
||||
};
|
||||
|
||||
static int
|
||||
ga102_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass,
|
||||
void *data, u32 size, struct nvkm_object **pobject)
|
||||
{
|
||||
return nv50_disp_root_new_(&ga102_disp_root, disp, oclass, data, size, pobject);
|
||||
}
|
||||
|
||||
const struct nvkm_disp_oclass
|
||||
ga102_disp_root_oclass = {
|
||||
.base.oclass = GA102_DISP,
|
||||
.base.minver = -1,
|
||||
.base.maxver = -1,
|
||||
.ctor = ga102_disp_root_new,
|
||||
};
|
||||
|
|
@ -41,4 +41,5 @@ extern const struct nvkm_disp_oclass gp100_disp_root_oclass;
|
|||
extern const struct nvkm_disp_oclass gp102_disp_root_oclass;
|
||||
extern const struct nvkm_disp_oclass gv100_disp_root_oclass;
|
||||
extern const struct nvkm_disp_oclass tu102_disp_root_oclass;
|
||||
extern const struct nvkm_disp_oclass ga102_disp_root_oclass;
|
||||
#endif
|
||||
|
|
|
|||
140
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c
Normal file
140
drivers/gpu/drm/nouveau/nvkm/engine/disp/sorga102.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ior.h"
|
||||
|
||||
#include <subdev/timer.h>
|
||||
|
||||
static int
|
||||
ga102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux)
|
||||
{
|
||||
struct nvkm_device *device = sor->disp->engine.subdev.device;
|
||||
const u32 soff = nv50_ior_base(sor);
|
||||
const u32 loff = nv50_sor_link(sor);
|
||||
u32 dpctrl = 0x00000000;
|
||||
u32 clksor = 0x00000000;
|
||||
|
||||
switch (sor->dp.bw) {
|
||||
case 0x06: clksor |= 0x00000000; break;
|
||||
case 0x0a: clksor |= 0x00040000; break;
|
||||
case 0x14: clksor |= 0x00080000; break;
|
||||
case 0x1e: clksor |= 0x000c0000; break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dpctrl |= ((1 << sor->dp.nr) - 1) << 16;
|
||||
if (sor->dp.mst)
|
||||
dpctrl |= 0x40000000;
|
||||
if (sor->dp.ef)
|
||||
dpctrl |= 0x00004000;
|
||||
|
||||
nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor);
|
||||
|
||||
/*XXX*/
|
||||
nvkm_msec(device, 40, NVKM_DELAY);
|
||||
nvkm_mask(device, 0x612300 + soff, 0x00030000, 0x00010000);
|
||||
nvkm_mask(device, 0x61c10c + loff, 0x00000003, 0x00000001);
|
||||
|
||||
nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ga102_sor_clock(struct nvkm_ior *sor)
|
||||
{
|
||||
struct nvkm_device *device = sor->disp->engine.subdev.device;
|
||||
u32 div2 = 0;
|
||||
if (sor->asy.proto == TMDS) {
|
||||
if (sor->tmds.high_speed)
|
||||
div2 = 1;
|
||||
}
|
||||
nvkm_wr32(device, 0x00ec08 + (sor->id * 0x10), 0x00000000);
|
||||
nvkm_wr32(device, 0x00ec04 + (sor->id * 0x10), div2);
|
||||
}
|
||||
|
||||
static const struct nvkm_ior_func
|
||||
ga102_sor_hda = {
|
||||
.route = {
|
||||
.get = gm200_sor_route_get,
|
||||
.set = gm200_sor_route_set,
|
||||
},
|
||||
.state = gv100_sor_state,
|
||||
.power = nv50_sor_power,
|
||||
.clock = ga102_sor_clock,
|
||||
.hdmi = {
|
||||
.ctrl = gv100_hdmi_ctrl,
|
||||
.scdc = gm200_hdmi_scdc,
|
||||
},
|
||||
.dp = {
|
||||
.lanes = { 0, 1, 2, 3 },
|
||||
.links = ga102_sor_dp_links,
|
||||
.power = g94_sor_dp_power,
|
||||
.pattern = gm107_sor_dp_pattern,
|
||||
.drive = gm200_sor_dp_drive,
|
||||
.vcpi = tu102_sor_dp_vcpi,
|
||||
.audio = gv100_sor_dp_audio,
|
||||
.audio_sym = gv100_sor_dp_audio_sym,
|
||||
.watermark = gv100_sor_dp_watermark,
|
||||
},
|
||||
.hda = {
|
||||
.hpd = gf119_hda_hpd,
|
||||
.eld = gf119_hda_eld,
|
||||
.device_entry = gv100_hda_device_entry,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct nvkm_ior_func
|
||||
ga102_sor = {
|
||||
.route = {
|
||||
.get = gm200_sor_route_get,
|
||||
.set = gm200_sor_route_set,
|
||||
},
|
||||
.state = gv100_sor_state,
|
||||
.power = nv50_sor_power,
|
||||
.clock = ga102_sor_clock,
|
||||
.hdmi = {
|
||||
.ctrl = gv100_hdmi_ctrl,
|
||||
.scdc = gm200_hdmi_scdc,
|
||||
},
|
||||
.dp = {
|
||||
.lanes = { 0, 1, 2, 3 },
|
||||
.links = ga102_sor_dp_links,
|
||||
.power = g94_sor_dp_power,
|
||||
.pattern = gm107_sor_dp_pattern,
|
||||
.drive = gm200_sor_dp_drive,
|
||||
.vcpi = tu102_sor_dp_vcpi,
|
||||
.audio = gv100_sor_dp_audio,
|
||||
.audio_sym = gv100_sor_dp_audio_sym,
|
||||
.watermark = gv100_sor_dp_watermark,
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
ga102_sor_new(struct nvkm_disp *disp, int id)
|
||||
{
|
||||
struct nvkm_device *device = disp->engine.subdev.device;
|
||||
u32 hda = nvkm_rd32(device, 0x08a15c);
|
||||
if (hda & BIT(id))
|
||||
return nvkm_ior_new_(&ga102_sor_hda, disp, SOR, id);
|
||||
return nvkm_ior_new_(&ga102_sor, disp, SOR, id);
|
||||
}
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <subdev/timer.h>
|
||||
|
||||
static void
|
||||
void
|
||||
tu102_sor_dp_vcpi(struct nvkm_ior *sor, int head,
|
||||
u8 slot, u8 slot_nr, u16 pbn, u16 aligned)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include <core/gpuobj.h>
|
||||
#include <subdev/timer.h>
|
||||
|
||||
static int
|
||||
int
|
||||
tu102_disp_init(struct nv50_disp *disp)
|
||||
{
|
||||
struct nvkm_device *device = disp->base.engine.subdev.device;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,9 @@ pramin_init(struct nvkm_bios *bios, const char *name)
|
|||
return NULL;
|
||||
|
||||
/* we can't get the bios image pointer without PDISP */
|
||||
if (device->card_type >= GA100)
|
||||
addr = device->chipset == 0x170; /*XXX: find the fuse reg for this */
|
||||
else
|
||||
if (device->card_type >= GM100)
|
||||
addr = nvkm_rd32(device, 0x021c04);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@ nvkm-y += nvkm/subdev/devinit/gm107.o
|
|||
nvkm-y += nvkm/subdev/devinit/gm200.o
|
||||
nvkm-y += nvkm/subdev/devinit/gv100.o
|
||||
nvkm-y += nvkm/subdev/devinit/tu102.o
|
||||
nvkm-y += nvkm/subdev/devinit/ga100.o
|
||||
|
|
|
|||
76
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/ga100.c
Normal file
76
drivers/gpu/drm/nouveau/nvkm/subdev/devinit/ga100.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nv50.h"
|
||||
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/pll.h>
|
||||
#include <subdev/clk/pll.h>
|
||||
|
||||
static int
|
||||
ga100_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &init->subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
struct nvbios_pll info;
|
||||
int head = type - PLL_VPLL0;
|
||||
int N, fN, M, P;
|
||||
int ret;
|
||||
|
||||
ret = nvbios_pll_parse(device->bios, type, &info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = gt215_pll_calc(subdev, &info, freq, &N, &fN, &M, &P);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (info.type) {
|
||||
case PLL_VPLL0:
|
||||
case PLL_VPLL1:
|
||||
case PLL_VPLL2:
|
||||
case PLL_VPLL3:
|
||||
nvkm_wr32(device, 0x00ef00 + (head * 0x40), 0x02080004);
|
||||
nvkm_wr32(device, 0x00ef18 + (head * 0x40), (N << 16) | fN);
|
||||
nvkm_wr32(device, 0x00ef04 + (head * 0x40), (P << 16) | M);
|
||||
nvkm_wr32(device, 0x00e9c0 + (head * 0x04), 0x00000001);
|
||||
break;
|
||||
default:
|
||||
nvkm_warn(subdev, "%08x/%dKhz unimplemented\n", type, freq);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nvkm_devinit_func
|
||||
ga100_devinit = {
|
||||
.init = nv50_devinit_init,
|
||||
.post = tu102_devinit_post,
|
||||
.pll_set = ga100_devinit_pll_set,
|
||||
};
|
||||
|
||||
int
|
||||
ga100_devinit_new(struct nvkm_device *device, int index, struct nvkm_devinit **pinit)
|
||||
{
|
||||
return nv50_devinit_new_(&ga100_devinit, device, index, pinit);
|
||||
}
|
||||
|
|
@ -19,4 +19,5 @@ void nvkm_devinit_ctor(const struct nvkm_devinit_func *, struct nvkm_device *,
|
|||
int index, struct nvkm_devinit *);
|
||||
|
||||
int nv04_devinit_post(struct nvkm_devinit *, bool);
|
||||
int tu102_devinit_post(struct nvkm_devinit *, bool);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ tu102_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
tu102_devinit_post(struct nvkm_devinit *base, bool post)
|
||||
{
|
||||
struct nv50_devinit *init = nv50_devinit(base);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ nvkm-y += nvkm/subdev/fb/gp100.o
|
|||
nvkm-y += nvkm/subdev/fb/gp102.o
|
||||
nvkm-y += nvkm/subdev/fb/gp10b.o
|
||||
nvkm-y += nvkm/subdev/fb/gv100.o
|
||||
nvkm-y += nvkm/subdev/fb/ga100.o
|
||||
nvkm-y += nvkm/subdev/fb/ga102.o
|
||||
|
||||
nvkm-y += nvkm/subdev/fb/ram.o
|
||||
nvkm-y += nvkm/subdev/fb/ramnv04.o
|
||||
|
|
@ -52,6 +54,7 @@ nvkm-y += nvkm/subdev/fb/ramgk104.o
|
|||
nvkm-y += nvkm/subdev/fb/ramgm107.o
|
||||
nvkm-y += nvkm/subdev/fb/ramgm200.o
|
||||
nvkm-y += nvkm/subdev/fb/ramgp100.o
|
||||
nvkm-y += nvkm/subdev/fb/ramga102.o
|
||||
nvkm-y += nvkm/subdev/fb/sddr2.o
|
||||
nvkm-y += nvkm/subdev/fb/sddr3.o
|
||||
nvkm-y += nvkm/subdev/fb/gddr3.o
|
||||
|
|
|
|||
40
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c
Normal file
40
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga100.c
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "gf100.h"
|
||||
#include "ram.h"
|
||||
|
||||
static const struct nvkm_fb_func
|
||||
ga100_fb = {
|
||||
.dtor = gf100_fb_dtor,
|
||||
.oneinit = gf100_fb_oneinit,
|
||||
.init = gp100_fb_init,
|
||||
.init_page = gv100_fb_init_page,
|
||||
.init_unkn = gp100_fb_init_unkn,
|
||||
.ram_new = gp100_ram_new,
|
||||
.default_bigpage = 16,
|
||||
};
|
||||
|
||||
int
|
||||
ga100_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb)
|
||||
{
|
||||
return gp102_fb_new_(&ga100_fb, device, index, pfb);
|
||||
}
|
||||
40
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
Normal file
40
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ga102.c
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "gf100.h"
|
||||
#include "ram.h"
|
||||
|
||||
static const struct nvkm_fb_func
|
||||
ga102_fb = {
|
||||
.dtor = gf100_fb_dtor,
|
||||
.oneinit = gf100_fb_oneinit,
|
||||
.init = gp100_fb_init,
|
||||
.init_page = gv100_fb_init_page,
|
||||
.init_unkn = gp100_fb_init_unkn,
|
||||
.ram_new = ga102_ram_new,
|
||||
.default_bigpage = 16,
|
||||
};
|
||||
|
||||
int
|
||||
ga102_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb)
|
||||
{
|
||||
return gp102_fb_new_(&ga102_fb, device, index, pfb);
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
#include "gf100.h"
|
||||
#include "ram.h"
|
||||
|
||||
static int
|
||||
int
|
||||
gv100_fb_init_page(struct nvkm_fb *fb)
|
||||
{
|
||||
return (fb->page == 16) ? 0 : -EINVAL;
|
||||
|
|
|
|||
|
|
@ -82,4 +82,6 @@ int gp102_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, int,
|
|||
struct nvkm_fb **);
|
||||
bool gp102_fb_vpr_scrub_required(struct nvkm_fb *);
|
||||
int gp102_fb_vpr_scrub(struct nvkm_fb *);
|
||||
|
||||
int gv100_fb_init_page(struct nvkm_fb *);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -70,4 +70,5 @@ int gk104_ram_new(struct nvkm_fb *, struct nvkm_ram **);
|
|||
int gm107_ram_new(struct nvkm_fb *, struct nvkm_ram **);
|
||||
int gm200_ram_new(struct nvkm_fb *, struct nvkm_ram **);
|
||||
int gp100_ram_new(struct nvkm_fb *, struct nvkm_ram **);
|
||||
int ga102_ram_new(struct nvkm_fb *, struct nvkm_ram **);
|
||||
#endif
|
||||
|
|
|
|||
40
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramga102.c
Normal file
40
drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramga102.c
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "ram.h"
|
||||
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/init.h>
|
||||
#include <subdev/bios/rammap.h>
|
||||
|
||||
static const struct nvkm_ram_func
|
||||
ga102_ram = {
|
||||
};
|
||||
|
||||
int
|
||||
ga102_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
|
||||
{
|
||||
struct nvkm_device *device = fb->subdev.device;
|
||||
enum nvkm_ram_type type = nvkm_fb_bios_memtype(device->bios);
|
||||
u32 size = nvkm_rd32(device, 0x1183a4);
|
||||
|
||||
return nvkm_ram_new_(&ga102_ram, fb, type, (u64)size << 20, pram);
|
||||
}
|
||||
|
|
@ -5,3 +5,4 @@ nvkm-y += nvkm/subdev/gpio/nv50.o
|
|||
nvkm-y += nvkm/subdev/gpio/g94.o
|
||||
nvkm-y += nvkm/subdev/gpio/gf119.o
|
||||
nvkm-y += nvkm/subdev/gpio/gk104.o
|
||||
nvkm-y += nvkm/subdev/gpio/ga102.o
|
||||
|
|
|
|||
118
drivers/gpu/drm/nouveau/nvkm/subdev/gpio/ga102.c
Normal file
118
drivers/gpu/drm/nouveau/nvkm/subdev/gpio/ga102.c
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "priv.h"
|
||||
|
||||
static void
|
||||
ga102_gpio_reset(struct nvkm_gpio *gpio, u8 match)
|
||||
{
|
||||
struct nvkm_device *device = gpio->subdev.device;
|
||||
struct nvkm_bios *bios = device->bios;
|
||||
u8 ver, len;
|
||||
u16 entry;
|
||||
int ent = -1;
|
||||
|
||||
while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
|
||||
u32 data = nvbios_rd32(bios, entry);
|
||||
u8 line = (data & 0x0000003f);
|
||||
u8 defs = !!(data & 0x00000080);
|
||||
u8 func = (data & 0x0000ff00) >> 8;
|
||||
u8 unk0 = (data & 0x00ff0000) >> 16;
|
||||
u8 unk1 = (data & 0x1f000000) >> 24;
|
||||
|
||||
if ( func == DCB_GPIO_UNUSED ||
|
||||
(match != DCB_GPIO_UNUSED && match != func))
|
||||
continue;
|
||||
|
||||
nvkm_gpio_set(gpio, 0, func, line, defs);
|
||||
|
||||
nvkm_mask(device, 0x021200 + (line * 4), 0xff, unk0);
|
||||
if (unk1--)
|
||||
nvkm_mask(device, 0x00d740 + (unk1 * 4), 0xff, line);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ga102_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
|
||||
{
|
||||
struct nvkm_device *device = gpio->subdev.device;
|
||||
u32 data = ((dir ^ 1) << 13) | (out << 12);
|
||||
nvkm_mask(device, 0x021200 + (line * 4), 0x00003000, data);
|
||||
nvkm_mask(device, 0x00d604, 0x00000001, 0x00000001); /* update? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ga102_gpio_sense(struct nvkm_gpio *gpio, int line)
|
||||
{
|
||||
struct nvkm_device *device = gpio->subdev.device;
|
||||
return !!(nvkm_rd32(device, 0x021200 + (line * 4)) & 0x00004000);
|
||||
}
|
||||
|
||||
static void
|
||||
ga102_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
|
||||
{
|
||||
struct nvkm_device *device = gpio->subdev.device;
|
||||
u32 intr0 = nvkm_rd32(device, 0x021640);
|
||||
u32 intr1 = nvkm_rd32(device, 0x02164c);
|
||||
u32 stat0 = nvkm_rd32(device, 0x021648) & intr0;
|
||||
u32 stat1 = nvkm_rd32(device, 0x021654) & intr1;
|
||||
*lo = (stat1 & 0xffff0000) | (stat0 >> 16);
|
||||
*hi = (stat1 << 16) | (stat0 & 0x0000ffff);
|
||||
nvkm_wr32(device, 0x021640, intr0);
|
||||
nvkm_wr32(device, 0x02164c, intr1);
|
||||
}
|
||||
|
||||
static void
|
||||
ga102_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
|
||||
{
|
||||
struct nvkm_device *device = gpio->subdev.device;
|
||||
u32 inte0 = nvkm_rd32(device, 0x021648);
|
||||
u32 inte1 = nvkm_rd32(device, 0x021654);
|
||||
if (type & NVKM_GPIO_LO)
|
||||
inte0 = (inte0 & ~(mask << 16)) | (data << 16);
|
||||
if (type & NVKM_GPIO_HI)
|
||||
inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
|
||||
mask >>= 16;
|
||||
data >>= 16;
|
||||
if (type & NVKM_GPIO_LO)
|
||||
inte1 = (inte1 & ~(mask << 16)) | (data << 16);
|
||||
if (type & NVKM_GPIO_HI)
|
||||
inte1 = (inte1 & ~mask) | data;
|
||||
nvkm_wr32(device, 0x021648, inte0);
|
||||
nvkm_wr32(device, 0x021654, inte1);
|
||||
}
|
||||
|
||||
static const struct nvkm_gpio_func
|
||||
ga102_gpio = {
|
||||
.lines = 32,
|
||||
.intr_stat = ga102_gpio_intr_stat,
|
||||
.intr_mask = ga102_gpio_intr_mask,
|
||||
.drive = ga102_gpio_drive,
|
||||
.sense = ga102_gpio_sense,
|
||||
.reset = ga102_gpio_reset,
|
||||
};
|
||||
|
||||
int
|
||||
ga102_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio)
|
||||
{
|
||||
return nvkm_gpio_new_(&ga102_gpio, device, index, pgpio);
|
||||
}
|
||||
|
|
@ -14,3 +14,4 @@ nvkm-y += nvkm/subdev/mc/gk20a.o
|
|||
nvkm-y += nvkm/subdev/mc/gp100.o
|
||||
nvkm-y += nvkm/subdev/mc/gp10b.o
|
||||
nvkm-y += nvkm/subdev/mc/tu102.o
|
||||
nvkm-y += nvkm/subdev/mc/ga100.o
|
||||
|
|
|
|||
74
drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c
Normal file
74
drivers/gpu/drm/nouveau/nvkm/subdev/mc/ga100.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "priv.h"
|
||||
|
||||
static void
|
||||
ga100_mc_intr_unarm(struct nvkm_mc *mc)
|
||||
{
|
||||
nvkm_wr32(mc->subdev.device, 0xb81610, 0x00000004);
|
||||
}
|
||||
|
||||
static void
|
||||
ga100_mc_intr_rearm(struct nvkm_mc *mc)
|
||||
{
|
||||
nvkm_wr32(mc->subdev.device, 0xb81608, 0x00000004);
|
||||
}
|
||||
|
||||
static void
|
||||
ga100_mc_intr_mask(struct nvkm_mc *mc, u32 mask, u32 intr)
|
||||
{
|
||||
nvkm_wr32(mc->subdev.device, 0xb81210, mask & intr );
|
||||
nvkm_wr32(mc->subdev.device, 0xb81410, mask & ~(mask & intr));
|
||||
}
|
||||
|
||||
static u32
|
||||
ga100_mc_intr_stat(struct nvkm_mc *mc)
|
||||
{
|
||||
u32 intr_top = nvkm_rd32(mc->subdev.device, 0xb81600), intr = 0x00000000;
|
||||
if (intr_top & 0x00000004)
|
||||
intr = nvkm_mask(mc->subdev.device, 0xb81010, 0x00000000, 0x00000000);
|
||||
return intr;
|
||||
}
|
||||
|
||||
static void
|
||||
ga100_mc_init(struct nvkm_mc *mc)
|
||||
{
|
||||
nv50_mc_init(mc);
|
||||
nvkm_wr32(mc->subdev.device, 0xb81210, 0xffffffff);
|
||||
}
|
||||
|
||||
static const struct nvkm_mc_func
|
||||
ga100_mc = {
|
||||
.init = ga100_mc_init,
|
||||
.intr = gp100_mc_intr,
|
||||
.intr_unarm = ga100_mc_intr_unarm,
|
||||
.intr_rearm = ga100_mc_intr_rearm,
|
||||
.intr_mask = ga100_mc_intr_mask,
|
||||
.intr_stat = ga100_mc_intr_stat,
|
||||
.reset = gk104_mc_reset,
|
||||
};
|
||||
|
||||
int
|
||||
ga100_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
|
||||
{
|
||||
return nvkm_mc_new_(&ga100_mc, device, index, pmc);
|
||||
}
|
||||
|
|
@ -131,8 +131,10 @@ static ssize_t default_roce_mode_store(struct config_item *item,
|
|||
return ret;
|
||||
|
||||
gid_type = ib_cache_gid_parse_type_str(buf);
|
||||
if (gid_type < 0)
|
||||
if (gid_type < 0) {
|
||||
cma_configfs_params_put(cma_dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = cma_set_default_gid_type(cma_dev, group->port_num, gid_type);
|
||||
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ void rdma_restrack_add(struct rdma_restrack_entry *res)
|
|||
} else {
|
||||
ret = xa_alloc_cyclic(&rt->xa, &res->id, res, xa_limit_32b,
|
||||
&rt->next_id, GFP_KERNEL);
|
||||
ret = (ret < 0) ? ret : 0;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -95,8 +95,6 @@ struct ucma_context {
|
|||
u64 uid;
|
||||
|
||||
struct list_head list;
|
||||
/* sync between removal event and id destroy, protected by file mut */
|
||||
int destroying;
|
||||
struct work_struct close_work;
|
||||
};
|
||||
|
||||
|
|
@ -122,7 +120,7 @@ static DEFINE_XARRAY_ALLOC(ctx_table);
|
|||
static DEFINE_XARRAY_ALLOC(multicast_table);
|
||||
|
||||
static const struct file_operations ucma_fops;
|
||||
static int __destroy_id(struct ucma_context *ctx);
|
||||
static int ucma_destroy_private_ctx(struct ucma_context *ctx);
|
||||
|
||||
static inline struct ucma_context *_ucma_find_context(int id,
|
||||
struct ucma_file *file)
|
||||
|
|
@ -179,19 +177,14 @@ static void ucma_close_id(struct work_struct *work)
|
|||
|
||||
/* once all inflight tasks are finished, we close all underlying
|
||||
* resources. The context is still alive till its explicit destryoing
|
||||
* by its creator.
|
||||
* by its creator. This puts back the xarray's reference.
|
||||
*/
|
||||
ucma_put_ctx(ctx);
|
||||
wait_for_completion(&ctx->comp);
|
||||
/* No new events will be generated after destroying the id. */
|
||||
rdma_destroy_id(ctx->cm_id);
|
||||
|
||||
/*
|
||||
* At this point ctx->ref is zero so the only place the ctx can be is in
|
||||
* a uevent or in __destroy_id(). Since the former doesn't touch
|
||||
* ctx->cm_id and the latter sync cancels this, there is no races with
|
||||
* this store.
|
||||
*/
|
||||
/* Reading the cm_id without holding a positive ref is not allowed */
|
||||
ctx->cm_id = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +197,6 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
|
|||
return NULL;
|
||||
|
||||
INIT_WORK(&ctx->close_work, ucma_close_id);
|
||||
refcount_set(&ctx->ref, 1);
|
||||
init_completion(&ctx->comp);
|
||||
/* So list_del() will work if we don't do ucma_finish_ctx() */
|
||||
INIT_LIST_HEAD(&ctx->list);
|
||||
|
|
@ -218,6 +210,13 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file)
|
|||
return ctx;
|
||||
}
|
||||
|
||||
static void ucma_set_ctx_cm_id(struct ucma_context *ctx,
|
||||
struct rdma_cm_id *cm_id)
|
||||
{
|
||||
refcount_set(&ctx->ref, 1);
|
||||
ctx->cm_id = cm_id;
|
||||
}
|
||||
|
||||
static void ucma_finish_ctx(struct ucma_context *ctx)
|
||||
{
|
||||
lockdep_assert_held(&ctx->file->mut);
|
||||
|
|
@ -303,7 +302,7 @@ static int ucma_connect_event_handler(struct rdma_cm_id *cm_id,
|
|||
ctx = ucma_alloc_ctx(listen_ctx->file);
|
||||
if (!ctx)
|
||||
goto err_backlog;
|
||||
ctx->cm_id = cm_id;
|
||||
ucma_set_ctx_cm_id(ctx, cm_id);
|
||||
|
||||
uevent = ucma_create_uevent(listen_ctx, event);
|
||||
if (!uevent)
|
||||
|
|
@ -321,8 +320,7 @@ static int ucma_connect_event_handler(struct rdma_cm_id *cm_id,
|
|||
return 0;
|
||||
|
||||
err_alloc:
|
||||
xa_erase(&ctx_table, ctx->id);
|
||||
kfree(ctx);
|
||||
ucma_destroy_private_ctx(ctx);
|
||||
err_backlog:
|
||||
atomic_inc(&listen_ctx->backlog);
|
||||
/* Returning error causes the new ID to be destroyed */
|
||||
|
|
@ -356,8 +354,12 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
|
|||
wake_up_interruptible(&ctx->file->poll_wait);
|
||||
}
|
||||
|
||||
if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL && !ctx->destroying)
|
||||
queue_work(system_unbound_wq, &ctx->close_work);
|
||||
if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) {
|
||||
xa_lock(&ctx_table);
|
||||
if (xa_load(&ctx_table, ctx->id) == ctx)
|
||||
queue_work(system_unbound_wq, &ctx->close_work);
|
||||
xa_unlock(&ctx_table);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -461,13 +463,12 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
|
|||
ret = PTR_ERR(cm_id);
|
||||
goto err1;
|
||||
}
|
||||
ctx->cm_id = cm_id;
|
||||
ucma_set_ctx_cm_id(ctx, cm_id);
|
||||
|
||||
resp.id = ctx->id;
|
||||
if (copy_to_user(u64_to_user_ptr(cmd.response),
|
||||
&resp, sizeof(resp))) {
|
||||
xa_erase(&ctx_table, ctx->id);
|
||||
__destroy_id(ctx);
|
||||
ucma_destroy_private_ctx(ctx);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
|
@ -477,8 +478,7 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
|
|||
return 0;
|
||||
|
||||
err1:
|
||||
xa_erase(&ctx_table, ctx->id);
|
||||
kfree(ctx);
|
||||
ucma_destroy_private_ctx(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -516,68 +516,73 @@ static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
|
|||
rdma_unlock_handler(mc->ctx->cm_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* ucma_free_ctx is called after the underlying rdma CM-ID is destroyed. At
|
||||
* this point, no new events will be reported from the hardware. However, we
|
||||
* still need to cleanup the UCMA context for this ID. Specifically, there
|
||||
* might be events that have not yet been consumed by the user space software.
|
||||
* mutex. After that we release them as needed.
|
||||
*/
|
||||
static int ucma_free_ctx(struct ucma_context *ctx)
|
||||
static int ucma_cleanup_ctx_events(struct ucma_context *ctx)
|
||||
{
|
||||
int events_reported;
|
||||
struct ucma_event *uevent, *tmp;
|
||||
LIST_HEAD(list);
|
||||
|
||||
ucma_cleanup_multicast(ctx);
|
||||
|
||||
/* Cleanup events not yet reported to the user. */
|
||||
/* Cleanup events not yet reported to the user.*/
|
||||
mutex_lock(&ctx->file->mut);
|
||||
list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) {
|
||||
if (uevent->ctx == ctx || uevent->conn_req_ctx == ctx)
|
||||
if (uevent->ctx != ctx)
|
||||
continue;
|
||||
|
||||
if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST &&
|
||||
xa_cmpxchg(&ctx_table, uevent->conn_req_ctx->id,
|
||||
uevent->conn_req_ctx, XA_ZERO_ENTRY,
|
||||
GFP_KERNEL) == uevent->conn_req_ctx) {
|
||||
list_move_tail(&uevent->list, &list);
|
||||
continue;
|
||||
}
|
||||
list_del(&uevent->list);
|
||||
kfree(uevent);
|
||||
}
|
||||
list_del(&ctx->list);
|
||||
events_reported = ctx->events_reported;
|
||||
mutex_unlock(&ctx->file->mut);
|
||||
|
||||
/*
|
||||
* If this was a listening ID then any connections spawned from it
|
||||
* that have not been delivered to userspace are cleaned up too.
|
||||
* Must be done outside any locks.
|
||||
* If this was a listening ID then any connections spawned from it that
|
||||
* have not been delivered to userspace are cleaned up too. Must be done
|
||||
* outside any locks.
|
||||
*/
|
||||
list_for_each_entry_safe(uevent, tmp, &list, list) {
|
||||
list_del(&uevent->list);
|
||||
if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST &&
|
||||
uevent->conn_req_ctx != ctx)
|
||||
__destroy_id(uevent->conn_req_ctx);
|
||||
ucma_destroy_private_ctx(uevent->conn_req_ctx);
|
||||
kfree(uevent);
|
||||
}
|
||||
|
||||
mutex_destroy(&ctx->mutex);
|
||||
kfree(ctx);
|
||||
return events_reported;
|
||||
}
|
||||
|
||||
static int __destroy_id(struct ucma_context *ctx)
|
||||
/*
|
||||
* When this is called the xarray must have a XA_ZERO_ENTRY in the ctx->id (ie
|
||||
* the ctx is not public to the user). This either because:
|
||||
* - ucma_finish_ctx() hasn't been called
|
||||
* - xa_cmpxchg() succeed to remove the entry (only one thread can succeed)
|
||||
*/
|
||||
static int ucma_destroy_private_ctx(struct ucma_context *ctx)
|
||||
{
|
||||
/*
|
||||
* If the refcount is already 0 then ucma_close_id() has already
|
||||
* destroyed the cm_id, otherwise holding the refcount keeps cm_id
|
||||
* valid. Prevent queue_work() from being called.
|
||||
*/
|
||||
if (refcount_inc_not_zero(&ctx->ref)) {
|
||||
rdma_lock_handler(ctx->cm_id);
|
||||
ctx->destroying = 1;
|
||||
rdma_unlock_handler(ctx->cm_id);
|
||||
ucma_put_ctx(ctx);
|
||||
}
|
||||
int events_reported;
|
||||
|
||||
/*
|
||||
* Destroy the underlying cm_id. New work queuing is prevented now by
|
||||
* the removal from the xarray. Once the work is cancled ref will either
|
||||
* be 0 because the work ran to completion and consumed the ref from the
|
||||
* xarray, or it will be positive because we still have the ref from the
|
||||
* xarray. This can also be 0 in cases where cm_id was never set
|
||||
*/
|
||||
cancel_work_sync(&ctx->close_work);
|
||||
/* At this point it's guaranteed that there is no inflight closing task */
|
||||
if (ctx->cm_id)
|
||||
if (refcount_read(&ctx->ref))
|
||||
ucma_close_id(&ctx->close_work);
|
||||
return ucma_free_ctx(ctx);
|
||||
|
||||
events_reported = ucma_cleanup_ctx_events(ctx);
|
||||
ucma_cleanup_multicast(ctx);
|
||||
|
||||
WARN_ON(xa_cmpxchg(&ctx_table, ctx->id, XA_ZERO_ENTRY, NULL,
|
||||
GFP_KERNEL) != NULL);
|
||||
mutex_destroy(&ctx->mutex);
|
||||
kfree(ctx);
|
||||
return events_reported;
|
||||
}
|
||||
|
||||
static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
|
||||
|
|
@ -596,14 +601,17 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf,
|
|||
|
||||
xa_lock(&ctx_table);
|
||||
ctx = _ucma_find_context(cmd.id, file);
|
||||
if (!IS_ERR(ctx))
|
||||
__xa_erase(&ctx_table, ctx->id);
|
||||
if (!IS_ERR(ctx)) {
|
||||
if (__xa_cmpxchg(&ctx_table, ctx->id, ctx, XA_ZERO_ENTRY,
|
||||
GFP_KERNEL) != ctx)
|
||||
ctx = ERR_PTR(-ENOENT);
|
||||
}
|
||||
xa_unlock(&ctx_table);
|
||||
|
||||
if (IS_ERR(ctx))
|
||||
return PTR_ERR(ctx);
|
||||
|
||||
resp.events_reported = __destroy_id(ctx);
|
||||
resp.events_reported = ucma_destroy_private_ctx(ctx);
|
||||
if (copy_to_user(u64_to_user_ptr(cmd.response),
|
||||
&resp, sizeof(resp)))
|
||||
ret = -EFAULT;
|
||||
|
|
@ -1777,15 +1785,16 @@ static int ucma_close(struct inode *inode, struct file *filp)
|
|||
* prevented by this being a FD release function. The list_add_tail() in
|
||||
* ucma_connect_event_handler() can run concurrently, however it only
|
||||
* adds to the list *after* a listening ID. By only reading the first of
|
||||
* the list, and relying on __destroy_id() to block
|
||||
* the list, and relying on ucma_destroy_private_ctx() to block
|
||||
* ucma_connect_event_handler(), no additional locking is needed.
|
||||
*/
|
||||
while (!list_empty(&file->ctx_list)) {
|
||||
struct ucma_context *ctx = list_first_entry(
|
||||
&file->ctx_list, struct ucma_context, list);
|
||||
|
||||
xa_erase(&ctx_table, ctx->id);
|
||||
__destroy_id(ctx);
|
||||
WARN_ON(xa_cmpxchg(&ctx_table, ctx->id, ctx, XA_ZERO_ENTRY,
|
||||
GFP_KERNEL) != ctx);
|
||||
ucma_destroy_private_ctx(ctx);
|
||||
}
|
||||
kfree(file);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
|
|||
*/
|
||||
if (mask)
|
||||
pgsz_bitmap &= GENMASK(count_trailing_zeros(mask), 0);
|
||||
return rounddown_pow_of_two(pgsz_bitmap);
|
||||
return pgsz_bitmap ? rounddown_pow_of_two(pgsz_bitmap) : 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ib_umem_find_best_pgsz);
|
||||
|
||||
|
|
|
|||
|
|
@ -3956,7 +3956,7 @@ static int mlx5_ib_stage_init_init(struct mlx5_ib_dev *dev)
|
|||
|
||||
err = set_has_smi_cap(dev);
|
||||
if (err)
|
||||
return err;
|
||||
goto err_mp;
|
||||
|
||||
if (!mlx5_core_mp_enabled(mdev)) {
|
||||
for (i = 1; i <= dev->num_ports; i++) {
|
||||
|
|
@ -4319,7 +4319,7 @@ static int mlx5_ib_stage_bfrag_init(struct mlx5_ib_dev *dev)
|
|||
|
||||
err = mlx5_alloc_bfreg(dev->mdev, &dev->fp_bfreg, false, true);
|
||||
if (err)
|
||||
mlx5_free_bfreg(dev->mdev, &dev->fp_bfreg);
|
||||
mlx5_free_bfreg(dev->mdev, &dev->bfreg);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -434,9 +434,9 @@ static void ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
|
|||
pr_err("%s(%d) Freeing in use pdid=0x%x.\n",
|
||||
__func__, dev->id, pd->id);
|
||||
}
|
||||
kfree(uctx->cntxt_pd);
|
||||
uctx->cntxt_pd = NULL;
|
||||
_ocrdma_dealloc_pd(dev, pd);
|
||||
kfree(pd);
|
||||
}
|
||||
|
||||
static struct ocrdma_pd *ocrdma_get_ucontext_pd(struct ocrdma_ucontext *uctx)
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ find_free_vf_and_create_qp_grp(struct usnic_ib_dev *us_ibdev,
|
|||
|
||||
}
|
||||
usnic_uiom_free_dev_list(dev_list);
|
||||
dev_list = NULL;
|
||||
}
|
||||
|
||||
/* Try to find resources on an unused vf */
|
||||
|
|
@ -239,6 +240,8 @@ find_free_vf_and_create_qp_grp(struct usnic_ib_dev *us_ibdev,
|
|||
qp_grp_check:
|
||||
if (IS_ERR_OR_NULL(qp_grp)) {
|
||||
usnic_err("Failed to allocate qp_grp\n");
|
||||
if (usnic_ib_share_vf)
|
||||
usnic_uiom_free_dev_list(dev_list);
|
||||
return ERR_PTR(qp_grp ? PTR_ERR(qp_grp) : -ENOMEM);
|
||||
}
|
||||
return qp_grp;
|
||||
|
|
|
|||
|
|
@ -364,7 +364,9 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
|
|||
}
|
||||
|
||||
static const struct of_device_id __maybe_unused qcom_smmu_impl_of_match[] = {
|
||||
{ .compatible = "qcom,msm8998-smmu-v2" },
|
||||
{ .compatible = "qcom,sc7180-smmu-500" },
|
||||
{ .compatible = "qcom,sdm630-smmu-v2" },
|
||||
{ .compatible = "qcom,sdm845-smmu-500" },
|
||||
{ .compatible = "qcom,sm8150-smmu-500" },
|
||||
{ .compatible = "qcom,sm8250-smmu-500" },
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@
|
|||
#include <linux/dmi.h>
|
||||
#include <linux/pci-ats.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/dma-direct.h>
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/numa.h>
|
||||
|
|
|
|||
|
|
@ -118,8 +118,10 @@ void intel_svm_check(struct intel_iommu *iommu)
|
|||
iommu->flags |= VTD_FLAG_SVM_CAPABLE;
|
||||
}
|
||||
|
||||
static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_dev *sdev,
|
||||
unsigned long address, unsigned long pages, int ih)
|
||||
static void __flush_svm_range_dev(struct intel_svm *svm,
|
||||
struct intel_svm_dev *sdev,
|
||||
unsigned long address,
|
||||
unsigned long pages, int ih)
|
||||
{
|
||||
struct qi_desc desc;
|
||||
|
||||
|
|
@ -170,6 +172,22 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
|
|||
}
|
||||
}
|
||||
|
||||
static void intel_flush_svm_range_dev(struct intel_svm *svm,
|
||||
struct intel_svm_dev *sdev,
|
||||
unsigned long address,
|
||||
unsigned long pages, int ih)
|
||||
{
|
||||
unsigned long shift = ilog2(__roundup_pow_of_two(pages));
|
||||
unsigned long align = (1ULL << (VTD_PAGE_SHIFT + shift));
|
||||
unsigned long start = ALIGN_DOWN(address, align);
|
||||
unsigned long end = ALIGN(address + (pages << VTD_PAGE_SHIFT), align);
|
||||
|
||||
while (start < end) {
|
||||
__flush_svm_range_dev(svm, sdev, start, align >> VTD_PAGE_SHIFT, ih);
|
||||
start += align;
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_flush_svm_range(struct intel_svm *svm, unsigned long address,
|
||||
unsigned long pages, int ih)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -637,6 +637,7 @@ config DM_INTEGRITY
|
|||
select BLK_DEV_INTEGRITY
|
||||
select DM_BUFIO
|
||||
select CRYPTO
|
||||
select CRYPTO_SKCIPHER
|
||||
select ASYNC_XOR
|
||||
help
|
||||
This device-mapper target emulates a block device that has
|
||||
|
|
@ -654,6 +655,7 @@ config DM_ZONED
|
|||
tristate "Drive-managed zoned block device target support"
|
||||
depends on BLK_DEV_DM
|
||||
depends on BLK_DEV_ZONED
|
||||
select CRC32
|
||||
help
|
||||
This device-mapper target takes a host-managed or host-aware zoned
|
||||
block device and exposes most of its capacity as a regular block
|
||||
|
|
|
|||
|
|
@ -1534,6 +1534,12 @@ sector_t dm_bufio_get_device_size(struct dm_bufio_client *c)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(dm_bufio_get_device_size);
|
||||
|
||||
struct dm_io_client *dm_bufio_get_dm_io_client(struct dm_bufio_client *c)
|
||||
{
|
||||
return c->dm_io;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dm_bufio_get_dm_io_client);
|
||||
|
||||
sector_t dm_bufio_get_block_number(struct dm_buffer *b)
|
||||
{
|
||||
return b->block;
|
||||
|
|
|
|||
|
|
@ -1454,13 +1454,16 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
|
|||
static void kcryptd_async_done(struct crypto_async_request *async_req,
|
||||
int error);
|
||||
|
||||
static void crypt_alloc_req_skcipher(struct crypt_config *cc,
|
||||
static int crypt_alloc_req_skcipher(struct crypt_config *cc,
|
||||
struct convert_context *ctx)
|
||||
{
|
||||
unsigned key_index = ctx->cc_sector & (cc->tfms_count - 1);
|
||||
|
||||
if (!ctx->r.req)
|
||||
ctx->r.req = mempool_alloc(&cc->req_pool, GFP_NOIO);
|
||||
if (!ctx->r.req) {
|
||||
ctx->r.req = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
|
||||
if (!ctx->r.req)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
skcipher_request_set_tfm(ctx->r.req, cc->cipher_tfm.tfms[key_index]);
|
||||
|
||||
|
|
@ -1471,13 +1474,18 @@ static void crypt_alloc_req_skcipher(struct crypt_config *cc,
|
|||
skcipher_request_set_callback(ctx->r.req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
kcryptd_async_done, dmreq_of_req(cc, ctx->r.req));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void crypt_alloc_req_aead(struct crypt_config *cc,
|
||||
static int crypt_alloc_req_aead(struct crypt_config *cc,
|
||||
struct convert_context *ctx)
|
||||
{
|
||||
if (!ctx->r.req_aead)
|
||||
ctx->r.req_aead = mempool_alloc(&cc->req_pool, GFP_NOIO);
|
||||
if (!ctx->r.req) {
|
||||
ctx->r.req = mempool_alloc(&cc->req_pool, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
|
||||
if (!ctx->r.req)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
aead_request_set_tfm(ctx->r.req_aead, cc->cipher_tfm.tfms_aead[0]);
|
||||
|
||||
|
|
@ -1488,15 +1496,17 @@ static void crypt_alloc_req_aead(struct crypt_config *cc,
|
|||
aead_request_set_callback(ctx->r.req_aead,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG,
|
||||
kcryptd_async_done, dmreq_of_req(cc, ctx->r.req_aead));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void crypt_alloc_req(struct crypt_config *cc,
|
||||
static int crypt_alloc_req(struct crypt_config *cc,
|
||||
struct convert_context *ctx)
|
||||
{
|
||||
if (crypt_integrity_aead(cc))
|
||||
crypt_alloc_req_aead(cc, ctx);
|
||||
return crypt_alloc_req_aead(cc, ctx);
|
||||
else
|
||||
crypt_alloc_req_skcipher(cc, ctx);
|
||||
return crypt_alloc_req_skcipher(cc, ctx);
|
||||
}
|
||||
|
||||
static void crypt_free_req_skcipher(struct crypt_config *cc,
|
||||
|
|
@ -1529,17 +1539,28 @@ static void crypt_free_req(struct crypt_config *cc, void *req, struct bio *base_
|
|||
* Encrypt / decrypt data from one bio to another one (can be the same one)
|
||||
*/
|
||||
static blk_status_t crypt_convert(struct crypt_config *cc,
|
||||
struct convert_context *ctx, bool atomic)
|
||||
struct convert_context *ctx, bool atomic, bool reset_pending)
|
||||
{
|
||||
unsigned int tag_offset = 0;
|
||||
unsigned int sector_step = cc->sector_size >> SECTOR_SHIFT;
|
||||
int r;
|
||||
|
||||
atomic_set(&ctx->cc_pending, 1);
|
||||
/*
|
||||
* if reset_pending is set we are dealing with the bio for the first time,
|
||||
* else we're continuing to work on the previous bio, so don't mess with
|
||||
* the cc_pending counter
|
||||
*/
|
||||
if (reset_pending)
|
||||
atomic_set(&ctx->cc_pending, 1);
|
||||
|
||||
while (ctx->iter_in.bi_size && ctx->iter_out.bi_size) {
|
||||
|
||||
crypt_alloc_req(cc, ctx);
|
||||
r = crypt_alloc_req(cc, ctx);
|
||||
if (r) {
|
||||
complete(&ctx->restart);
|
||||
return BLK_STS_DEV_RESOURCE;
|
||||
}
|
||||
|
||||
atomic_inc(&ctx->cc_pending);
|
||||
|
||||
if (crypt_integrity_aead(cc))
|
||||
|
|
@ -1553,7 +1574,25 @@ static blk_status_t crypt_convert(struct crypt_config *cc,
|
|||
* but the driver request queue is full, let's wait.
|
||||
*/
|
||||
case -EBUSY:
|
||||
wait_for_completion(&ctx->restart);
|
||||
if (in_interrupt()) {
|
||||
if (try_wait_for_completion(&ctx->restart)) {
|
||||
/*
|
||||
* we don't have to block to wait for completion,
|
||||
* so proceed
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* we can't wait for completion without blocking
|
||||
* exit and continue processing in a workqueue
|
||||
*/
|
||||
ctx->r.req = NULL;
|
||||
ctx->cc_sector += sector_step;
|
||||
tag_offset++;
|
||||
return BLK_STS_DEV_RESOURCE;
|
||||
}
|
||||
} else {
|
||||
wait_for_completion(&ctx->restart);
|
||||
}
|
||||
reinit_completion(&ctx->restart);
|
||||
fallthrough;
|
||||
/*
|
||||
|
|
@ -1691,6 +1730,12 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
|
|||
atomic_inc(&io->io_pending);
|
||||
}
|
||||
|
||||
static void kcryptd_io_bio_endio(struct work_struct *work)
|
||||
{
|
||||
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
|
||||
bio_endio(io->base_bio);
|
||||
}
|
||||
|
||||
/*
|
||||
* One of the bios was finished. Check for completion of
|
||||
* the whole request and correctly clean up the buffer.
|
||||
|
|
@ -1713,7 +1758,23 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
|
|||
kfree(io->integrity_metadata);
|
||||
|
||||
base_bio->bi_status = error;
|
||||
bio_endio(base_bio);
|
||||
|
||||
/*
|
||||
* If we are running this function from our tasklet,
|
||||
* we can't call bio_endio() here, because it will call
|
||||
* clone_endio() from dm.c, which in turn will
|
||||
* free the current struct dm_crypt_io structure with
|
||||
* our tasklet. In this case we need to delay bio_endio()
|
||||
* execution to after the tasklet is done and dequeued.
|
||||
*/
|
||||
if (tasklet_trylock(&io->tasklet)) {
|
||||
tasklet_unlock(&io->tasklet);
|
||||
bio_endio(base_bio);
|
||||
return;
|
||||
}
|
||||
|
||||
INIT_WORK(&io->work, kcryptd_io_bio_endio);
|
||||
queue_work(cc->io_queue, &io->work);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1945,6 +2006,37 @@ static bool kcryptd_crypt_write_inline(struct crypt_config *cc,
|
|||
}
|
||||
}
|
||||
|
||||
static void kcryptd_crypt_write_continue(struct work_struct *work)
|
||||
{
|
||||
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
|
||||
struct crypt_config *cc = io->cc;
|
||||
struct convert_context *ctx = &io->ctx;
|
||||
int crypt_finished;
|
||||
sector_t sector = io->sector;
|
||||
blk_status_t r;
|
||||
|
||||
wait_for_completion(&ctx->restart);
|
||||
reinit_completion(&ctx->restart);
|
||||
|
||||
r = crypt_convert(cc, &io->ctx, true, false);
|
||||
if (r)
|
||||
io->error = r;
|
||||
crypt_finished = atomic_dec_and_test(&ctx->cc_pending);
|
||||
if (!crypt_finished && kcryptd_crypt_write_inline(cc, ctx)) {
|
||||
/* Wait for completion signaled by kcryptd_async_done() */
|
||||
wait_for_completion(&ctx->restart);
|
||||
crypt_finished = 1;
|
||||
}
|
||||
|
||||
/* Encryption was already finished, submit io now */
|
||||
if (crypt_finished) {
|
||||
kcryptd_crypt_write_io_submit(io, 0);
|
||||
io->sector = sector;
|
||||
}
|
||||
|
||||
crypt_dec_pending(io);
|
||||
}
|
||||
|
||||
static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
|
||||
{
|
||||
struct crypt_config *cc = io->cc;
|
||||
|
|
@ -1973,7 +2065,17 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
|
|||
|
||||
crypt_inc_pending(io);
|
||||
r = crypt_convert(cc, ctx,
|
||||
test_bit(DM_CRYPT_NO_WRITE_WORKQUEUE, &cc->flags));
|
||||
test_bit(DM_CRYPT_NO_WRITE_WORKQUEUE, &cc->flags), true);
|
||||
/*
|
||||
* Crypto API backlogged the request, because its queue was full
|
||||
* and we're in softirq context, so continue from a workqueue
|
||||
* (TODO: is it actually possible to be in softirq in the write path?)
|
||||
*/
|
||||
if (r == BLK_STS_DEV_RESOURCE) {
|
||||
INIT_WORK(&io->work, kcryptd_crypt_write_continue);
|
||||
queue_work(cc->crypt_queue, &io->work);
|
||||
return;
|
||||
}
|
||||
if (r)
|
||||
io->error = r;
|
||||
crypt_finished = atomic_dec_and_test(&ctx->cc_pending);
|
||||
|
|
@ -1998,6 +2100,25 @@ static void kcryptd_crypt_read_done(struct dm_crypt_io *io)
|
|||
crypt_dec_pending(io);
|
||||
}
|
||||
|
||||
static void kcryptd_crypt_read_continue(struct work_struct *work)
|
||||
{
|
||||
struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
|
||||
struct crypt_config *cc = io->cc;
|
||||
blk_status_t r;
|
||||
|
||||
wait_for_completion(&io->ctx.restart);
|
||||
reinit_completion(&io->ctx.restart);
|
||||
|
||||
r = crypt_convert(cc, &io->ctx, true, false);
|
||||
if (r)
|
||||
io->error = r;
|
||||
|
||||
if (atomic_dec_and_test(&io->ctx.cc_pending))
|
||||
kcryptd_crypt_read_done(io);
|
||||
|
||||
crypt_dec_pending(io);
|
||||
}
|
||||
|
||||
static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
|
||||
{
|
||||
struct crypt_config *cc = io->cc;
|
||||
|
|
@ -2009,7 +2130,16 @@ static void kcryptd_crypt_read_convert(struct dm_crypt_io *io)
|
|||
io->sector);
|
||||
|
||||
r = crypt_convert(cc, &io->ctx,
|
||||
test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags));
|
||||
test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true);
|
||||
/*
|
||||
* Crypto API backlogged the request, because its queue was full
|
||||
* and we're in softirq context, so continue from a workqueue
|
||||
*/
|
||||
if (r == BLK_STS_DEV_RESOURCE) {
|
||||
INIT_WORK(&io->work, kcryptd_crypt_read_continue);
|
||||
queue_work(cc->crypt_queue, &io->work);
|
||||
return;
|
||||
}
|
||||
if (r)
|
||||
io->error = r;
|
||||
|
||||
|
|
@ -2091,8 +2221,12 @@ static void kcryptd_queue_crypt(struct dm_crypt_io *io)
|
|||
|
||||
if ((bio_data_dir(io->base_bio) == READ && test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags)) ||
|
||||
(bio_data_dir(io->base_bio) == WRITE && test_bit(DM_CRYPT_NO_WRITE_WORKQUEUE, &cc->flags))) {
|
||||
if (in_irq()) {
|
||||
/* Crypto API's "skcipher_walk_first() refuses to work in hard IRQ context */
|
||||
/*
|
||||
* in_irq(): Crypto API's skcipher_walk_first() refuses to work in hard IRQ context.
|
||||
* irqs_disabled(): the kernel may run some IO completion from the idle thread, but
|
||||
* it is being executed with irqs disabled.
|
||||
*/
|
||||
if (in_irq() || irqs_disabled()) {
|
||||
tasklet_init(&io->tasklet, kcryptd_crypt_tasklet, (unsigned long)&io->work);
|
||||
tasklet_schedule(&io->tasklet);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1379,12 +1379,52 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
|
|||
#undef MAY_BE_HASH
|
||||
}
|
||||
|
||||
static void dm_integrity_flush_buffers(struct dm_integrity_c *ic)
|
||||
struct flush_request {
|
||||
struct dm_io_request io_req;
|
||||
struct dm_io_region io_reg;
|
||||
struct dm_integrity_c *ic;
|
||||
struct completion comp;
|
||||
};
|
||||
|
||||
static void flush_notify(unsigned long error, void *fr_)
|
||||
{
|
||||
struct flush_request *fr = fr_;
|
||||
if (unlikely(error != 0))
|
||||
dm_integrity_io_error(fr->ic, "flusing disk cache", -EIO);
|
||||
complete(&fr->comp);
|
||||
}
|
||||
|
||||
static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_data)
|
||||
{
|
||||
int r;
|
||||
|
||||
struct flush_request fr;
|
||||
|
||||
if (!ic->meta_dev)
|
||||
flush_data = false;
|
||||
if (flush_data) {
|
||||
fr.io_req.bi_op = REQ_OP_WRITE,
|
||||
fr.io_req.bi_op_flags = REQ_PREFLUSH | REQ_SYNC,
|
||||
fr.io_req.mem.type = DM_IO_KMEM,
|
||||
fr.io_req.mem.ptr.addr = NULL,
|
||||
fr.io_req.notify.fn = flush_notify,
|
||||
fr.io_req.notify.context = &fr;
|
||||
fr.io_req.client = dm_bufio_get_dm_io_client(ic->bufio),
|
||||
fr.io_reg.bdev = ic->dev->bdev,
|
||||
fr.io_reg.sector = 0,
|
||||
fr.io_reg.count = 0,
|
||||
fr.ic = ic;
|
||||
init_completion(&fr.comp);
|
||||
r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL);
|
||||
BUG_ON(r);
|
||||
}
|
||||
|
||||
r = dm_bufio_write_dirty_buffers(ic->bufio);
|
||||
if (unlikely(r))
|
||||
dm_integrity_io_error(ic, "writing tags", r);
|
||||
|
||||
if (flush_data)
|
||||
wait_for_completion(&fr.comp);
|
||||
}
|
||||
|
||||
static void sleep_on_endio_wait(struct dm_integrity_c *ic)
|
||||
|
|
@ -2110,7 +2150,7 @@ static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map
|
|||
|
||||
if (unlikely(dio->op == REQ_OP_DISCARD) && likely(ic->mode != 'D')) {
|
||||
integrity_metadata(&dio->work);
|
||||
dm_integrity_flush_buffers(ic);
|
||||
dm_integrity_flush_buffers(ic, false);
|
||||
|
||||
dio->in_flight = (atomic_t)ATOMIC_INIT(1);
|
||||
dio->completion = NULL;
|
||||
|
|
@ -2195,7 +2235,7 @@ static void integrity_commit(struct work_struct *w)
|
|||
flushes = bio_list_get(&ic->flush_bio_list);
|
||||
if (unlikely(ic->mode != 'J')) {
|
||||
spin_unlock_irq(&ic->endio_wait.lock);
|
||||
dm_integrity_flush_buffers(ic);
|
||||
dm_integrity_flush_buffers(ic, true);
|
||||
goto release_flush_bios;
|
||||
}
|
||||
|
||||
|
|
@ -2409,7 +2449,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
|
|||
complete_journal_op(&comp);
|
||||
wait_for_completion_io(&comp.comp);
|
||||
|
||||
dm_integrity_flush_buffers(ic);
|
||||
dm_integrity_flush_buffers(ic, true);
|
||||
}
|
||||
|
||||
static void integrity_writer(struct work_struct *w)
|
||||
|
|
@ -2451,7 +2491,7 @@ static void recalc_write_super(struct dm_integrity_c *ic)
|
|||
{
|
||||
int r;
|
||||
|
||||
dm_integrity_flush_buffers(ic);
|
||||
dm_integrity_flush_buffers(ic, false);
|
||||
if (dm_integrity_failed(ic))
|
||||
return;
|
||||
|
||||
|
|
@ -2654,7 +2694,7 @@ static void bitmap_flush_work(struct work_struct *work)
|
|||
unsigned long limit;
|
||||
struct bio *bio;
|
||||
|
||||
dm_integrity_flush_buffers(ic);
|
||||
dm_integrity_flush_buffers(ic, false);
|
||||
|
||||
range.logical_sector = 0;
|
||||
range.n_sectors = ic->provided_data_sectors;
|
||||
|
|
@ -2663,9 +2703,7 @@ static void bitmap_flush_work(struct work_struct *work)
|
|||
add_new_range_and_wait(ic, &range);
|
||||
spin_unlock_irq(&ic->endio_wait.lock);
|
||||
|
||||
dm_integrity_flush_buffers(ic);
|
||||
if (ic->meta_dev)
|
||||
blkdev_issue_flush(ic->dev->bdev, GFP_NOIO);
|
||||
dm_integrity_flush_buffers(ic, true);
|
||||
|
||||
limit = ic->provided_data_sectors;
|
||||
if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING)) {
|
||||
|
|
@ -2934,11 +2972,11 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
|
|||
if (ic->meta_dev)
|
||||
queue_work(ic->writer_wq, &ic->writer_work);
|
||||
drain_workqueue(ic->writer_wq);
|
||||
dm_integrity_flush_buffers(ic);
|
||||
dm_integrity_flush_buffers(ic, true);
|
||||
}
|
||||
|
||||
if (ic->mode == 'B') {
|
||||
dm_integrity_flush_buffers(ic);
|
||||
dm_integrity_flush_buffers(ic, true);
|
||||
#if 1
|
||||
/* set to 0 to test bitmap replay code */
|
||||
init_journal(ic, 0, ic->journal_sections, 0);
|
||||
|
|
@ -3754,7 +3792,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||
unsigned extra_args;
|
||||
struct dm_arg_set as;
|
||||
static const struct dm_arg _args[] = {
|
||||
{0, 9, "Invalid number of feature args"},
|
||||
{0, 15, "Invalid number of feature args"},
|
||||
};
|
||||
unsigned journal_sectors, interleave_sectors, buffer_sectors, journal_watermark, sync_msec;
|
||||
bool should_write_sb;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user