mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-25 10:59:05 +00:00
Merge branch 'aarch64/for-next/ras-apei' into aarch64/for-next/core
Merge in arm64 ACPI RAS support (APEI/GHES) from Tyler Baicar.
This commit is contained in:
commit
3edb1dd13c
@ -247,7 +247,6 @@ bias-bus-hold - latch weakly
|
||||
bias-pull-up - pull up the pin
|
||||
bias-pull-down - pull down the pin
|
||||
bias-pull-pin-default - use pin-default pull state
|
||||
bi-directional - pin supports simultaneous input/output operations
|
||||
drive-push-pull - drive actively high and low
|
||||
drive-open-drain - drive with open drain
|
||||
drive-open-source - drive with open source
|
||||
@ -260,7 +259,6 @@ input-debounce - debounce mode with debound time X
|
||||
power-source - select between different power supplies
|
||||
low-power-enable - enable low power mode
|
||||
low-power-disable - disable low power mode
|
||||
output-enable - enable output on pin regardless of output value
|
||||
output-low - set the pin to output mode with low level
|
||||
output-high - set the pin to output mode with high level
|
||||
slew-rate - set the slew rate
|
||||
|
15
MAINTAINERS
15
MAINTAINERS
@ -10450,7 +10450,7 @@ S: Orphan
|
||||
|
||||
PXA RTC DRIVER
|
||||
M: Robert Jarzmik <robert.jarzmik@free.fr>
|
||||
L: rtc-linux@googlegroups.com
|
||||
L: linux-rtc@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
QAT DRIVER
|
||||
@ -10757,7 +10757,7 @@ X: kernel/torture.c
|
||||
REAL TIME CLOCK (RTC) SUBSYSTEM
|
||||
M: Alessandro Zummo <a.zummo@towertech.it>
|
||||
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
L: rtc-linux@googlegroups.com
|
||||
L: linux-rtc@vger.kernel.org
|
||||
Q: http://patchwork.ozlabs.org/project/rtc-linux/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
|
||||
S: Maintained
|
||||
@ -13463,6 +13463,17 @@ W: http://en.wikipedia.org/wiki/Util-linux
|
||||
T: git git://git.kernel.org/pub/scm/utils/util-linux/util-linux.git
|
||||
S: Maintained
|
||||
|
||||
UUID HELPERS
|
||||
M: Christoph Hellwig <hch@lst.de>
|
||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
T: git git://git.infradead.org/users/hch/uuid.git
|
||||
F: lib/uuid.c
|
||||
F: lib/test_uuid.c
|
||||
F: include/linux/uuid.h
|
||||
F: include/uapi/linux/uuid.h
|
||||
S: Maintained
|
||||
|
||||
UVESAFB DRIVER
|
||||
M: Michal Januszewski <spock@gentoo.org>
|
||||
L: linux-fbdev@vger.kernel.org
|
||||
|
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
VERSION = 4
|
||||
PATCHLEVEL = 12
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION = -rc3
|
||||
EXTRAVERSION = -rc4
|
||||
NAME = Fearless Coyote
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -187,6 +187,16 @@
|
||||
#define FSC_FAULT (0x04)
|
||||
#define FSC_ACCESS (0x08)
|
||||
#define FSC_PERM (0x0c)
|
||||
#define FSC_SEA (0x10)
|
||||
#define FSC_SEA_TTW0 (0x14)
|
||||
#define FSC_SEA_TTW1 (0x15)
|
||||
#define FSC_SEA_TTW2 (0x16)
|
||||
#define FSC_SEA_TTW3 (0x17)
|
||||
#define FSC_SECC (0x18)
|
||||
#define FSC_SECC_TTW0 (0x1c)
|
||||
#define FSC_SECC_TTW1 (0x1d)
|
||||
#define FSC_SECC_TTW2 (0x1e)
|
||||
#define FSC_SECC_TTW3 (0x1f)
|
||||
|
||||
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
||||
#define HPFAR_MASK (~0xf)
|
||||
|
@ -22,6 +22,11 @@ extern void (*arm_pm_idle)(void);
|
||||
|
||||
extern unsigned int user_debug;
|
||||
|
||||
static inline int handle_guest_sea(phys_addr_t addr, unsigned int esr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_ARM_SYSTEM_MISC_H */
|
||||
|
@ -20,6 +20,7 @@ config ARM64
|
||||
select ARCH_HAS_STRICT_KERNEL_RWX
|
||||
select ARCH_HAS_STRICT_MODULE_RWX
|
||||
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG if ACPI_APEI_SEA
|
||||
select ARCH_USE_CMPXCHG_LOCKREF
|
||||
select ARCH_SUPPORTS_MEMORY_FAILURE
|
||||
select ARCH_SUPPORTS_ATOMIC_RMW
|
||||
@ -94,6 +95,7 @@ config ARM64
|
||||
select HAVE_IRQ_TIME_ACCOUNTING
|
||||
select HAVE_MEMBLOCK
|
||||
select HAVE_MEMBLOCK_NODE_MAP if NUMA
|
||||
select HAVE_NMI if ACPI_APEI_SEA
|
||||
select HAVE_PATA_PLATFORM
|
||||
select HAVE_PERF_EVENTS
|
||||
select HAVE_PERF_REGS
|
||||
|
@ -23,9 +23,9 @@
|
||||
#define ACPI_MADT_GICC_LENGTH \
|
||||
(acpi_gbl_FADT.header.revision < 6 ? 76 : 80)
|
||||
|
||||
#define BAD_MADT_GICC_ENTRY(entry, end) \
|
||||
(!(entry) || (unsigned long)(entry) + sizeof(*(entry)) > (end) || \
|
||||
(entry)->header.length != ACPI_MADT_GICC_LENGTH)
|
||||
#define BAD_MADT_GICC_ENTRY(entry, end) \
|
||||
(!(entry) || (entry)->header.length != ACPI_MADT_GICC_LENGTH || \
|
||||
(unsigned long)(entry) + ACPI_MADT_GICC_LENGTH > (end))
|
||||
|
||||
/* Basic configuration for ACPI */
|
||||
#ifdef CONFIG_ACPI
|
||||
|
@ -83,6 +83,7 @@
|
||||
#define ESR_ELx_WNR (UL(1) << 6)
|
||||
|
||||
/* Shared ISS field definitions for Data/Instruction aborts */
|
||||
#define ESR_ELx_FnV (UL(1) << 10)
|
||||
#define ESR_ELx_EA (UL(1) << 9)
|
||||
#define ESR_ELx_S1PTW (UL(1) << 7)
|
||||
|
||||
|
@ -204,6 +204,16 @@
|
||||
#define FSC_FAULT ESR_ELx_FSC_FAULT
|
||||
#define FSC_ACCESS ESR_ELx_FSC_ACCESS
|
||||
#define FSC_PERM ESR_ELx_FSC_PERM
|
||||
#define FSC_SEA ESR_ELx_FSC_EXTABT
|
||||
#define FSC_SEA_TTW0 (0x14)
|
||||
#define FSC_SEA_TTW1 (0x15)
|
||||
#define FSC_SEA_TTW2 (0x16)
|
||||
#define FSC_SEA_TTW3 (0x17)
|
||||
#define FSC_SECC (0x18)
|
||||
#define FSC_SECC_TTW0 (0x1c)
|
||||
#define FSC_SECC_TTW1 (0x1d)
|
||||
#define FSC_SECC_TTW2 (0x1e)
|
||||
#define FSC_SECC_TTW3 (0x1f)
|
||||
|
||||
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
|
||||
#define HPFAR_MASK (~UL(0xf))
|
||||
|
@ -56,6 +56,8 @@ extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
|
||||
__show_ratelimited; \
|
||||
})
|
||||
|
||||
int handle_guest_sea(phys_addr_t addr, unsigned int esr);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_SYSTEM_MISC_H */
|
||||
|
@ -194,8 +194,10 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
|
||||
return NULL;
|
||||
|
||||
root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node);
|
||||
if (!root_ops)
|
||||
if (!root_ops) {
|
||||
kfree(ri);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ri->cfg = pci_acpi_setup_ecam_mapping(root);
|
||||
if (!ri->cfg) {
|
||||
|
@ -43,6 +43,8 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#include <acpi/ghes.h>
|
||||
|
||||
struct fault_info {
|
||||
int (*fn)(unsigned long addr, unsigned int esr,
|
||||
struct pt_regs *regs);
|
||||
@ -559,6 +561,47 @@ static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This abort handler deals with Synchronous External Abort.
|
||||
* It calls notifiers, and then returns "fault".
|
||||
*/
|
||||
static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
|
||||
{
|
||||
struct siginfo info;
|
||||
const struct fault_info *inf;
|
||||
int ret = 0;
|
||||
|
||||
inf = esr_to_fault_info(esr);
|
||||
pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n",
|
||||
inf->name, esr, addr);
|
||||
|
||||
/*
|
||||
* Synchronous aborts may interrupt code which had interrupts masked.
|
||||
* Before calling out into the wider kernel tell the interested
|
||||
* subsystems.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
|
||||
if (interrupts_enabled(regs))
|
||||
nmi_enter();
|
||||
|
||||
ret = ghes_notify_sea();
|
||||
|
||||
if (interrupts_enabled(regs))
|
||||
nmi_exit();
|
||||
}
|
||||
|
||||
info.si_signo = SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
if (esr & ESR_ELx_FnV)
|
||||
info.si_addr = NULL;
|
||||
else
|
||||
info.si_addr = (void __user *)addr;
|
||||
arm64_notify_die("", regs, &info, esr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct fault_info fault_info[] = {
|
||||
{ do_bad, SIGBUS, 0, "ttbr address size fault" },
|
||||
{ do_bad, SIGBUS, 0, "level 1 address size fault" },
|
||||
@ -576,22 +619,22 @@ static const struct fault_info fault_info[] = {
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
|
||||
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous external abort" },
|
||||
{ do_sea, SIGBUS, 0, "synchronous external abort" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 17" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 18" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 19" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous external abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous external abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous external abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous external abort (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error" },
|
||||
{ do_sea, SIGBUS, 0, "level 0 (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "level 1 (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "level 2 (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "level 3 (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "synchronous parity or ECC error" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 25" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 26" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 27" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "level 0 synchronous parity error (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "level 1 synchronous parity error (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "level 2 synchronous parity error (translation table walk)" },
|
||||
{ do_sea, SIGBUS, 0, "level 3 synchronous parity error (translation table walk)" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 32" },
|
||||
{ do_alignment_fault, SIGBUS, BUS_ADRALN, "alignment fault" },
|
||||
{ do_bad, SIGBUS, 0, "unknown 34" },
|
||||
@ -626,6 +669,23 @@ static const struct fault_info fault_info[] = {
|
||||
{ do_bad, SIGBUS, 0, "unknown 63" },
|
||||
};
|
||||
|
||||
/*
|
||||
* Handle Synchronous External Aborts that occur in a guest kernel.
|
||||
*
|
||||
* The return value will be zero if the SEA was successfully handled
|
||||
* and non-zero if there was an error processing the error or there was
|
||||
* no error to process.
|
||||
*/
|
||||
int handle_guest_sea(phys_addr_t addr, unsigned int esr)
|
||||
{
|
||||
int ret = -ENOENT;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ACPI_APEI_SEA))
|
||||
ret = ghes_notify_sea();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch a data abort to the relevant handler.
|
||||
*/
|
||||
|
@ -16,5 +16,11 @@ static inline cycles_t get_cycles(void)
|
||||
#define vxtime_lock() do {} while (0)
|
||||
#define vxtime_unlock() do {} while (0)
|
||||
|
||||
/* This attribute is used in include/linux/jiffies.h alongside with
|
||||
* __cacheline_aligned_in_smp. It is assumed that __cacheline_aligned_in_smp
|
||||
* for frv does not contain another section specification.
|
||||
*/
|
||||
#define __jiffy_arch_data __attribute__((__section__(".data")))
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -120,7 +120,6 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
|
||||
struct thread_info *ti = task_thread_info(p);
|
||||
struct pt_regs *childregs, *regs = current_pt_regs();
|
||||
unsigned long childksp;
|
||||
p->set_child_tid = p->clear_child_tid = NULL;
|
||||
|
||||
childksp = (unsigned long)task_stack_page(p) + THREAD_SIZE - 32;
|
||||
|
||||
|
@ -167,8 +167,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
|
||||
|
||||
top_of_kernel_stack = sp;
|
||||
|
||||
p->set_child_tid = p->clear_child_tid = NULL;
|
||||
|
||||
/* Locate userspace context on stack... */
|
||||
sp -= STACK_FRAME_OVERHEAD; /* redzone */
|
||||
sp -= sizeof(struct pt_regs);
|
||||
|
@ -109,7 +109,7 @@ struct sysinfo_2_2_2 {
|
||||
unsigned short cpus_shared;
|
||||
char reserved_4[3];
|
||||
unsigned char vsne;
|
||||
uuid_be uuid;
|
||||
uuid_t uuid;
|
||||
char reserved_5[160];
|
||||
char ext_name[256];
|
||||
};
|
||||
@ -134,7 +134,7 @@ struct sysinfo_3_2_2 {
|
||||
char reserved_1[3];
|
||||
unsigned char evmne;
|
||||
unsigned int reserved_2;
|
||||
uuid_be uuid;
|
||||
uuid_t uuid;
|
||||
} vm[8];
|
||||
char reserved_3[1504];
|
||||
char ext_names[8][256];
|
||||
|
@ -242,7 +242,7 @@ static void print_ext_name(struct seq_file *m, int lvl,
|
||||
|
||||
static void print_uuid(struct seq_file *m, int i, struct sysinfo_3_2_2 *info)
|
||||
{
|
||||
if (!memcmp(&info->vm[i].uuid, &NULL_UUID_BE, sizeof(uuid_be)))
|
||||
if (uuid_is_null(&info->vm[i].uuid))
|
||||
return;
|
||||
seq_printf(m, "VM%02d UUID: %pUb\n", i, &info->vm[i].uuid);
|
||||
}
|
||||
|
@ -320,7 +320,7 @@ void load_ucode_amd_ap(unsigned int cpuid_1_eax)
|
||||
}
|
||||
|
||||
static enum ucode_state
|
||||
load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size);
|
||||
load_microcode_amd(bool save, u8 family, const u8 *data, size_t size);
|
||||
|
||||
int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
|
||||
{
|
||||
@ -338,8 +338,7 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
|
||||
if (!desc.mc)
|
||||
return -EINVAL;
|
||||
|
||||
ret = load_microcode_amd(smp_processor_id(), x86_family(cpuid_1_eax),
|
||||
desc.data, desc.size);
|
||||
ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size);
|
||||
if (ret != UCODE_OK)
|
||||
return -EINVAL;
|
||||
|
||||
@ -675,7 +674,7 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
|
||||
}
|
||||
|
||||
static enum ucode_state
|
||||
load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
|
||||
load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
|
||||
{
|
||||
enum ucode_state ret;
|
||||
|
||||
@ -689,8 +688,8 @@ load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/* save BSP's matching patch for early load */
|
||||
if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
|
||||
struct ucode_patch *p = find_patch(cpu);
|
||||
if (save) {
|
||||
struct ucode_patch *p = find_patch(0);
|
||||
if (p) {
|
||||
memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
|
||||
memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data),
|
||||
@ -722,11 +721,12 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
|
||||
{
|
||||
char fw_name[36] = "amd-ucode/microcode_amd.bin";
|
||||
struct cpuinfo_x86 *c = &cpu_data(cpu);
|
||||
bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
|
||||
enum ucode_state ret = UCODE_NFOUND;
|
||||
const struct firmware *fw;
|
||||
|
||||
/* reload ucode container only on the boot cpu */
|
||||
if (!refresh_fw || c->cpu_index != boot_cpu_data.cpu_index)
|
||||
if (!refresh_fw || !bsp)
|
||||
return UCODE_OK;
|
||||
|
||||
if (c->x86 >= 0x15)
|
||||
@ -743,7 +743,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
|
||||
goto fw_release;
|
||||
}
|
||||
|
||||
ret = load_microcode_amd(cpu, c->x86, fw->data, fw->size);
|
||||
ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size);
|
||||
|
||||
fw_release:
|
||||
release_firmware(fw);
|
||||
|
@ -78,7 +78,7 @@ void __show_regs(struct pt_regs *regs, int all)
|
||||
|
||||
printk(KERN_DEFAULT "EIP: %pS\n", (void *)regs->ip);
|
||||
printk(KERN_DEFAULT "EFLAGS: %08lx CPU: %d\n", regs->flags,
|
||||
smp_processor_id());
|
||||
raw_smp_processor_id());
|
||||
|
||||
printk(KERN_DEFAULT "EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
|
||||
regs->ax, regs->bx, regs->cx, regs->dx);
|
||||
|
@ -1495,8 +1495,10 @@ EXPORT_SYMBOL_GPL(kvm_lapic_hv_timer_in_use);
|
||||
|
||||
static void cancel_hv_timer(struct kvm_lapic *apic)
|
||||
{
|
||||
preempt_disable();
|
||||
kvm_x86_ops->cancel_hv_timer(apic->vcpu);
|
||||
apic->lapic_timer.hv_timer_in_use = false;
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
static bool start_hv_timer(struct kvm_lapic *apic)
|
||||
@ -1934,7 +1936,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
for (i = 0; i < KVM_APIC_LVT_NUM; i++)
|
||||
kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
|
||||
apic_update_lvtt(apic);
|
||||
if (kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED))
|
||||
if (kvm_vcpu_is_reset_bsp(vcpu) &&
|
||||
kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED))
|
||||
kvm_lapic_set_reg(apic, APIC_LVT0,
|
||||
SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
|
||||
apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0));
|
||||
|
@ -1807,7 +1807,7 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
|
||||
* AMD's VMCB does not have an explicit unusable field, so emulate it
|
||||
* for cross vendor migration purposes by "not present"
|
||||
*/
|
||||
var->unusable = !var->present || (var->type == 0);
|
||||
var->unusable = !var->present;
|
||||
|
||||
switch (seg) {
|
||||
case VCPU_SREG_TR:
|
||||
@ -1840,6 +1840,7 @@ static void svm_get_segment(struct kvm_vcpu *vcpu,
|
||||
*/
|
||||
if (var->unusable)
|
||||
var->db = 0;
|
||||
/* This is symmetric with svm_set_segment() */
|
||||
var->dpl = to_svm(vcpu)->vmcb->save.cpl;
|
||||
break;
|
||||
}
|
||||
@ -1980,18 +1981,14 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
|
||||
s->base = var->base;
|
||||
s->limit = var->limit;
|
||||
s->selector = var->selector;
|
||||
if (var->unusable)
|
||||
s->attrib = 0;
|
||||
else {
|
||||
s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
|
||||
s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
|
||||
s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
|
||||
s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
|
||||
s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
|
||||
s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
|
||||
s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
|
||||
s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
|
||||
}
|
||||
s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
|
||||
s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
|
||||
s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
|
||||
s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT;
|
||||
s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
|
||||
s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
|
||||
s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
|
||||
s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
|
||||
|
||||
/*
|
||||
* This is always accurate, except if SYSRET returned to a segment
|
||||
@ -2000,7 +1997,8 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
|
||||
* would entail passing the CPL to userspace and back.
|
||||
*/
|
||||
if (seg == VCPU_SREG_SS)
|
||||
svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
|
||||
/* This is symmetric with svm_get_segment() */
|
||||
svm->vmcb->save.cpl = (var->dpl & 3);
|
||||
|
||||
mark_dirty(svm->vmcb, VMCB_SEG);
|
||||
}
|
||||
|
@ -6914,97 +6914,21 @@ static int get_vmx_mem_address(struct kvm_vcpu *vcpu,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function performs the various checks including
|
||||
* - if it's 4KB aligned
|
||||
* - No bits beyond the physical address width are set
|
||||
* - Returns 0 on success or else 1
|
||||
* (Intel SDM Section 30.3)
|
||||
*/
|
||||
static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason,
|
||||
gpa_t *vmpointer)
|
||||
static int nested_vmx_get_vmptr(struct kvm_vcpu *vcpu, gpa_t *vmpointer)
|
||||
{
|
||||
gva_t gva;
|
||||
gpa_t vmptr;
|
||||
struct x86_exception e;
|
||||
struct page *page;
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
int maxphyaddr = cpuid_maxphyaddr(vcpu);
|
||||
|
||||
if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION),
|
||||
vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva))
|
||||
return 1;
|
||||
|
||||
if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr,
|
||||
sizeof(vmptr), &e)) {
|
||||
if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, vmpointer,
|
||||
sizeof(*vmpointer), &e)) {
|
||||
kvm_inject_page_fault(vcpu, &e);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (exit_reason) {
|
||||
case EXIT_REASON_VMON:
|
||||
/*
|
||||
* SDM 3: 24.11.5
|
||||
* The first 4 bytes of VMXON region contain the supported
|
||||
* VMCS revision identifier
|
||||
*
|
||||
* Note - IA32_VMX_BASIC[48] will never be 1
|
||||
* for the nested case;
|
||||
* which replaces physical address width with 32
|
||||
*
|
||||
*/
|
||||
if (!PAGE_ALIGNED(vmptr) || (vmptr >> maxphyaddr)) {
|
||||
nested_vmx_failInvalid(vcpu);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
page = nested_get_page(vcpu, vmptr);
|
||||
if (page == NULL) {
|
||||
nested_vmx_failInvalid(vcpu);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
if (*(u32 *)kmap(page) != VMCS12_REVISION) {
|
||||
kunmap(page);
|
||||
nested_release_page_clean(page);
|
||||
nested_vmx_failInvalid(vcpu);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
kunmap(page);
|
||||
nested_release_page_clean(page);
|
||||
vmx->nested.vmxon_ptr = vmptr;
|
||||
break;
|
||||
case EXIT_REASON_VMCLEAR:
|
||||
if (!PAGE_ALIGNED(vmptr) || (vmptr >> maxphyaddr)) {
|
||||
nested_vmx_failValid(vcpu,
|
||||
VMXERR_VMCLEAR_INVALID_ADDRESS);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
if (vmptr == vmx->nested.vmxon_ptr) {
|
||||
nested_vmx_failValid(vcpu,
|
||||
VMXERR_VMCLEAR_VMXON_POINTER);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
break;
|
||||
case EXIT_REASON_VMPTRLD:
|
||||
if (!PAGE_ALIGNED(vmptr) || (vmptr >> maxphyaddr)) {
|
||||
nested_vmx_failValid(vcpu,
|
||||
VMXERR_VMPTRLD_INVALID_ADDRESS);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
if (vmptr == vmx->nested.vmxon_ptr) {
|
||||
nested_vmx_failValid(vcpu,
|
||||
VMXERR_VMPTRLD_VMXON_POINTER);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 1; /* shouldn't happen */
|
||||
}
|
||||
|
||||
if (vmpointer)
|
||||
*vmpointer = vmptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -7066,6 +6990,8 @@ out_msr_bitmap:
|
||||
static int handle_vmon(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int ret;
|
||||
gpa_t vmptr;
|
||||
struct page *page;
|
||||
struct vcpu_vmx *vmx = to_vmx(vcpu);
|
||||
const u64 VMXON_NEEDED_FEATURES = FEATURE_CONTROL_LOCKED
|
||||
| FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX;
|
||||
@ -7095,9 +7021,37 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (nested_vmx_check_vmptr(vcpu, EXIT_REASON_VMON, NULL))
|
||||
if (nested_vmx_get_vmptr(vcpu, &vmptr))
|
||||
return 1;
|
||||
|
||||
|
||||
/*
|
||||
* SDM 3: 24.11.5
|
||||
* The first 4 bytes of VMXON region contain the supported
|
||||
* VMCS revision identifier
|
||||
*
|
||||
* Note - IA32_VMX_BASIC[48] will never be 1 for the nested case;
|
||||
* which replaces physical address width with 32
|
||||
*/
|
||||
if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) {
|
||||
nested_vmx_failInvalid(vcpu);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
page = nested_get_page(vcpu, vmptr);
|
||||
if (page == NULL) {
|
||||
nested_vmx_failInvalid(vcpu);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
if (*(u32 *)kmap(page) != VMCS12_REVISION) {
|
||||
kunmap(page);
|
||||
nested_release_page_clean(page);
|
||||
nested_vmx_failInvalid(vcpu);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
kunmap(page);
|
||||
nested_release_page_clean(page);
|
||||
|
||||
vmx->nested.vmxon_ptr = vmptr;
|
||||
ret = enter_vmx_operation(vcpu);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -7213,9 +7167,19 @@ static int handle_vmclear(struct kvm_vcpu *vcpu)
|
||||
if (!nested_vmx_check_permission(vcpu))
|
||||
return 1;
|
||||
|
||||
if (nested_vmx_check_vmptr(vcpu, EXIT_REASON_VMCLEAR, &vmptr))
|
||||
if (nested_vmx_get_vmptr(vcpu, &vmptr))
|
||||
return 1;
|
||||
|
||||
if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) {
|
||||
nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_INVALID_ADDRESS);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
if (vmptr == vmx->nested.vmxon_ptr) {
|
||||
nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_VMXON_POINTER);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
if (vmptr == vmx->nested.current_vmptr)
|
||||
nested_release_vmcs12(vmx);
|
||||
|
||||
@ -7545,9 +7509,19 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
|
||||
if (!nested_vmx_check_permission(vcpu))
|
||||
return 1;
|
||||
|
||||
if (nested_vmx_check_vmptr(vcpu, EXIT_REASON_VMPTRLD, &vmptr))
|
||||
if (nested_vmx_get_vmptr(vcpu, &vmptr))
|
||||
return 1;
|
||||
|
||||
if (!PAGE_ALIGNED(vmptr) || (vmptr >> cpuid_maxphyaddr(vcpu))) {
|
||||
nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_INVALID_ADDRESS);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
if (vmptr == vmx->nested.vmxon_ptr) {
|
||||
nested_vmx_failValid(vcpu, VMXERR_VMPTRLD_VMXON_POINTER);
|
||||
return kvm_skip_emulated_instruction(vcpu);
|
||||
}
|
||||
|
||||
if (vmx->nested.current_vmptr != vmptr) {
|
||||
struct vmcs12 *new_vmcs12;
|
||||
struct page *page;
|
||||
@ -7913,11 +7887,13 @@ static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu,
|
||||
{
|
||||
unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
|
||||
int cr = exit_qualification & 15;
|
||||
int reg = (exit_qualification >> 8) & 15;
|
||||
unsigned long val = kvm_register_readl(vcpu, reg);
|
||||
int reg;
|
||||
unsigned long val;
|
||||
|
||||
switch ((exit_qualification >> 4) & 3) {
|
||||
case 0: /* mov to cr */
|
||||
reg = (exit_qualification >> 8) & 15;
|
||||
val = kvm_register_readl(vcpu, reg);
|
||||
switch (cr) {
|
||||
case 0:
|
||||
if (vmcs12->cr0_guest_host_mask &
|
||||
@ -7972,6 +7948,7 @@ static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu,
|
||||
* lmsw can change bits 1..3 of cr0, and only set bit 0 of
|
||||
* cr0. Other attempted changes are ignored, with no exit.
|
||||
*/
|
||||
val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f;
|
||||
if (vmcs12->cr0_guest_host_mask & 0xe &
|
||||
(val ^ vmcs12->cr0_read_shadow))
|
||||
return true;
|
||||
|
@ -8394,10 +8394,13 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
|
||||
if (vcpu->arch.pv.pv_unhalted)
|
||||
return true;
|
||||
|
||||
if (atomic_read(&vcpu->arch.nmi_queued))
|
||||
if (kvm_test_request(KVM_REQ_NMI, vcpu) ||
|
||||
(vcpu->arch.nmi_pending &&
|
||||
kvm_x86_ops->nmi_allowed(vcpu)))
|
||||
return true;
|
||||
|
||||
if (kvm_test_request(KVM_REQ_SMI, vcpu))
|
||||
if (kvm_test_request(KVM_REQ_SMI, vcpu) ||
|
||||
(vcpu->arch.smi_pending && !is_smm(vcpu)))
|
||||
return true;
|
||||
|
||||
if (kvm_arch_interrupt_allowed(vcpu) &&
|
||||
|
@ -65,11 +65,9 @@ static int __init nopat(char *str)
|
||||
}
|
||||
early_param("nopat", nopat);
|
||||
|
||||
static bool __read_mostly __pat_initialized = false;
|
||||
|
||||
bool pat_enabled(void)
|
||||
{
|
||||
return __pat_initialized;
|
||||
return !!__pat_enabled;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pat_enabled);
|
||||
|
||||
@ -227,14 +225,13 @@ static void pat_bsp_init(u64 pat)
|
||||
}
|
||||
|
||||
wrmsrl(MSR_IA32_CR_PAT, pat);
|
||||
__pat_initialized = true;
|
||||
|
||||
__init_cache_modes(pat);
|
||||
}
|
||||
|
||||
static void pat_ap_init(u64 pat)
|
||||
{
|
||||
if (!this_cpu_has(X86_FEATURE_PAT)) {
|
||||
if (!boot_cpu_has(X86_FEATURE_PAT)) {
|
||||
/*
|
||||
* If this happens we are on a secondary CPU, but switched to
|
||||
* PAT on the boot CPU. We have no way to undo PAT.
|
||||
@ -309,7 +306,7 @@ void pat_init(void)
|
||||
u64 pat;
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
if (!__pat_enabled) {
|
||||
if (!pat_enabled()) {
|
||||
init_cache_modes();
|
||||
return;
|
||||
}
|
||||
|
@ -828,9 +828,11 @@ static void __init kexec_enter_virtual_mode(void)
|
||||
|
||||
/*
|
||||
* We don't do virtual mode, since we don't do runtime services, on
|
||||
* non-native EFI
|
||||
* non-native EFI. With efi=old_map, we don't do runtime services in
|
||||
* kexec kernel because in the initial boot something else might
|
||||
* have been mapped at these virtual addresses.
|
||||
*/
|
||||
if (!efi_is_native()) {
|
||||
if (!efi_is_native() || efi_enabled(EFI_OLD_MEMMAP)) {
|
||||
efi_memmap_unmap();
|
||||
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
|
||||
return;
|
||||
|
@ -71,11 +71,13 @@ static void __init early_code_mapping_set_exec(int executable)
|
||||
|
||||
pgd_t * __init efi_call_phys_prolog(void)
|
||||
{
|
||||
unsigned long vaddress;
|
||||
pgd_t *save_pgd;
|
||||
unsigned long vaddr, addr_pgd, addr_p4d, addr_pud;
|
||||
pgd_t *save_pgd, *pgd_k, *pgd_efi;
|
||||
p4d_t *p4d, *p4d_k, *p4d_efi;
|
||||
pud_t *pud;
|
||||
|
||||
int pgd;
|
||||
int n_pgds;
|
||||
int n_pgds, i, j;
|
||||
|
||||
if (!efi_enabled(EFI_OLD_MEMMAP)) {
|
||||
save_pgd = (pgd_t *)read_cr3();
|
||||
@ -88,10 +90,49 @@ pgd_t * __init efi_call_phys_prolog(void)
|
||||
n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
|
||||
save_pgd = kmalloc_array(n_pgds, sizeof(*save_pgd), GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* Build 1:1 identity mapping for efi=old_map usage. Note that
|
||||
* PAGE_OFFSET is PGDIR_SIZE aligned when KASLR is disabled, while
|
||||
* it is PUD_SIZE ALIGNED with KASLR enabled. So for a given physical
|
||||
* address X, the pud_index(X) != pud_index(__va(X)), we can only copy
|
||||
* PUD entry of __va(X) to fill in pud entry of X to build 1:1 mapping.
|
||||
* This means here we can only reuse the PMD tables of the direct mapping.
|
||||
*/
|
||||
for (pgd = 0; pgd < n_pgds; pgd++) {
|
||||
save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);
|
||||
vaddress = (unsigned long)__va(pgd * PGDIR_SIZE);
|
||||
set_pgd(pgd_offset_k(pgd * PGDIR_SIZE), *pgd_offset_k(vaddress));
|
||||
addr_pgd = (unsigned long)(pgd * PGDIR_SIZE);
|
||||
vaddr = (unsigned long)__va(pgd * PGDIR_SIZE);
|
||||
pgd_efi = pgd_offset_k(addr_pgd);
|
||||
save_pgd[pgd] = *pgd_efi;
|
||||
|
||||
p4d = p4d_alloc(&init_mm, pgd_efi, addr_pgd);
|
||||
if (!p4d) {
|
||||
pr_err("Failed to allocate p4d table!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < PTRS_PER_P4D; i++) {
|
||||
addr_p4d = addr_pgd + i * P4D_SIZE;
|
||||
p4d_efi = p4d + p4d_index(addr_p4d);
|
||||
|
||||
pud = pud_alloc(&init_mm, p4d_efi, addr_p4d);
|
||||
if (!pud) {
|
||||
pr_err("Failed to allocate pud table!\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (j = 0; j < PTRS_PER_PUD; j++) {
|
||||
addr_pud = addr_p4d + j * PUD_SIZE;
|
||||
|
||||
if (addr_pud > (max_pfn << PAGE_SHIFT))
|
||||
break;
|
||||
|
||||
vaddr = (unsigned long)__va(addr_pud);
|
||||
|
||||
pgd_k = pgd_offset_k(vaddr);
|
||||
p4d_k = p4d_offset(pgd_k, vaddr);
|
||||
pud[j] = *pud_offset(p4d_k, vaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
__flush_tlb_all();
|
||||
@ -104,8 +145,11 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd)
|
||||
/*
|
||||
* After the lock is released, the original page table is restored.
|
||||
*/
|
||||
int pgd_idx;
|
||||
int pgd_idx, i;
|
||||
int nr_pgds;
|
||||
pgd_t *pgd;
|
||||
p4d_t *p4d;
|
||||
pud_t *pud;
|
||||
|
||||
if (!efi_enabled(EFI_OLD_MEMMAP)) {
|
||||
write_cr3((unsigned long)save_pgd);
|
||||
@ -115,9 +159,28 @@ void __init efi_call_phys_epilog(pgd_t *save_pgd)
|
||||
|
||||
nr_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT) , PGDIR_SIZE);
|
||||
|
||||
for (pgd_idx = 0; pgd_idx < nr_pgds; pgd_idx++)
|
||||
for (pgd_idx = 0; pgd_idx < nr_pgds; pgd_idx++) {
|
||||
pgd = pgd_offset_k(pgd_idx * PGDIR_SIZE);
|
||||
set_pgd(pgd_offset_k(pgd_idx * PGDIR_SIZE), save_pgd[pgd_idx]);
|
||||
|
||||
if (!(pgd_val(*pgd) & _PAGE_PRESENT))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < PTRS_PER_P4D; i++) {
|
||||
p4d = p4d_offset(pgd,
|
||||
pgd_idx * PGDIR_SIZE + i * P4D_SIZE);
|
||||
|
||||
if (!(p4d_val(*p4d) & _PAGE_PRESENT))
|
||||
continue;
|
||||
|
||||
pud = (pud_t *)p4d_page_vaddr(*p4d);
|
||||
pud_free(&init_mm, pud);
|
||||
}
|
||||
|
||||
p4d = (p4d_t *)pgd_page_vaddr(*pgd);
|
||||
p4d_free(&init_mm, p4d);
|
||||
}
|
||||
|
||||
kfree(save_pgd);
|
||||
|
||||
__flush_tlb_all();
|
||||
|
@ -360,6 +360,9 @@ void __init efi_free_boot_services(void)
|
||||
free_bootmem_late(start, size);
|
||||
}
|
||||
|
||||
if (!num_entries)
|
||||
return;
|
||||
|
||||
new_size = efi.memmap.desc_size * num_entries;
|
||||
new_phys = efi_memmap_alloc(num_entries);
|
||||
if (!new_phys) {
|
||||
|
@ -74,7 +74,7 @@ static void blkg_free(struct blkcg_gq *blkg)
|
||||
blkcg_policy[i]->pd_free_fn(blkg->pd[i]);
|
||||
|
||||
if (blkg->blkcg != &blkcg_root)
|
||||
blk_exit_rl(&blkg->rl);
|
||||
blk_exit_rl(blkg->q, &blkg->rl);
|
||||
|
||||
blkg_rwstat_exit(&blkg->stat_ios);
|
||||
blkg_rwstat_exit(&blkg->stat_bytes);
|
||||
|
@ -648,13 +648,19 @@ int blk_init_rl(struct request_list *rl, struct request_queue *q,
|
||||
if (!rl->rq_pool)
|
||||
return -ENOMEM;
|
||||
|
||||
if (rl != &q->root_rl)
|
||||
WARN_ON_ONCE(!blk_get_queue(q));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void blk_exit_rl(struct request_list *rl)
|
||||
void blk_exit_rl(struct request_queue *q, struct request_list *rl)
|
||||
{
|
||||
if (rl->rq_pool)
|
||||
if (rl->rq_pool) {
|
||||
mempool_destroy(rl->rq_pool);
|
||||
if (rl != &q->root_rl)
|
||||
blk_put_queue(q);
|
||||
}
|
||||
}
|
||||
|
||||
struct request_queue *blk_alloc_queue(gfp_t gfp_mask)
|
||||
|
@ -2641,7 +2641,8 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues)
|
||||
static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
|
||||
int nr_hw_queues)
|
||||
{
|
||||
struct request_queue *q;
|
||||
|
||||
@ -2665,6 +2666,13 @@ void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues)
|
||||
list_for_each_entry(q, &set->tag_list, tag_set_list)
|
||||
blk_mq_unfreeze_queue(q);
|
||||
}
|
||||
|
||||
void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues)
|
||||
{
|
||||
mutex_lock(&set->tag_list_lock);
|
||||
__blk_mq_update_nr_hw_queues(set, nr_hw_queues);
|
||||
mutex_unlock(&set->tag_list_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blk_mq_update_nr_hw_queues);
|
||||
|
||||
/* Enable polling stats and return whether they were already enabled. */
|
||||
|
@ -809,7 +809,7 @@ static void blk_release_queue(struct kobject *kobj)
|
||||
|
||||
blk_free_queue_stats(q->stats);
|
||||
|
||||
blk_exit_rl(&q->root_rl);
|
||||
blk_exit_rl(q, &q->root_rl);
|
||||
|
||||
if (q->queue_tags)
|
||||
__blk_queue_free_tags(q);
|
||||
|
@ -59,7 +59,7 @@ void blk_free_flush_queue(struct blk_flush_queue *q);
|
||||
|
||||
int blk_init_rl(struct request_list *rl, struct request_queue *q,
|
||||
gfp_t gfp_mask);
|
||||
void blk_exit_rl(struct request_list *rl);
|
||||
void blk_exit_rl(struct request_queue *q, struct request_list *rl);
|
||||
void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
|
||||
struct bio *bio);
|
||||
void blk_queue_bypass_start(struct request_queue *q);
|
||||
|
@ -38,9 +38,13 @@ static const u64 cfq_target_latency = (u64)NSEC_PER_SEC * 3/10; /* 300 ms */
|
||||
static const int cfq_hist_divisor = 4;
|
||||
|
||||
/*
|
||||
* offset from end of service tree
|
||||
* offset from end of queue service tree for idle class
|
||||
*/
|
||||
#define CFQ_IDLE_DELAY (NSEC_PER_SEC / 5)
|
||||
/* offset from end of group service tree under time slice mode */
|
||||
#define CFQ_SLICE_MODE_GROUP_DELAY (NSEC_PER_SEC / 5)
|
||||
/* offset from end of group service under IOPS mode */
|
||||
#define CFQ_IOPS_MODE_GROUP_DELAY (HZ / 5)
|
||||
|
||||
/*
|
||||
* below this threshold, we consider thinktime immediate
|
||||
@ -1362,6 +1366,14 @@ cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg)
|
||||
cfqg->vfraction = max_t(unsigned, vfr, 1);
|
||||
}
|
||||
|
||||
static inline u64 cfq_get_cfqg_vdisktime_delay(struct cfq_data *cfqd)
|
||||
{
|
||||
if (!iops_mode(cfqd))
|
||||
return CFQ_SLICE_MODE_GROUP_DELAY;
|
||||
else
|
||||
return CFQ_IOPS_MODE_GROUP_DELAY;
|
||||
}
|
||||
|
||||
static void
|
||||
cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
||||
{
|
||||
@ -1381,7 +1393,8 @@ cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
||||
n = rb_last(&st->rb);
|
||||
if (n) {
|
||||
__cfqg = rb_entry_cfqg(n);
|
||||
cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY;
|
||||
cfqg->vdisktime = __cfqg->vdisktime +
|
||||
cfq_get_cfqg_vdisktime_delay(cfqd);
|
||||
} else
|
||||
cfqg->vdisktime = st->min_vdisktime;
|
||||
cfq_group_service_tree_add(st, cfqg);
|
||||
|
@ -115,7 +115,7 @@ static bool ldm_parse_privhead(const u8 *data, struct privhead *ph)
|
||||
ldm_error("PRIVHEAD disk size doesn't match real disk size");
|
||||
return false;
|
||||
}
|
||||
if (uuid_be_to_bin(data + 0x0030, (uuid_be *)ph->disk_id)) {
|
||||
if (uuid_parse(data + 0x0030, &ph->disk_id)) {
|
||||
ldm_error("PRIVHEAD contains an invalid GUID.");
|
||||
return false;
|
||||
}
|
||||
@ -234,7 +234,7 @@ static bool ldm_compare_privheads (const struct privhead *ph1,
|
||||
(ph1->logical_disk_size == ph2->logical_disk_size) &&
|
||||
(ph1->config_start == ph2->config_start) &&
|
||||
(ph1->config_size == ph2->config_size) &&
|
||||
!memcmp (ph1->disk_id, ph2->disk_id, GUID_SIZE));
|
||||
uuid_equal(&ph1->disk_id, &ph2->disk_id));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -557,7 +557,7 @@ static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
|
||||
|
||||
list_for_each (item, &ldb->v_disk) {
|
||||
struct vblk *v = list_entry (item, struct vblk, list);
|
||||
if (!memcmp (v->vblk.disk.disk_id, ldb->ph.disk_id, GUID_SIZE))
|
||||
if (uuid_equal(&v->vblk.disk.disk_id, &ldb->ph.disk_id))
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -892,7 +892,7 @@ static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
|
||||
disk = &vb->vblk.disk;
|
||||
ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
|
||||
sizeof (disk->alt_name));
|
||||
if (uuid_be_to_bin(buffer + 0x19 + r_name, (uuid_be *)disk->disk_id))
|
||||
if (uuid_parse(buffer + 0x19 + r_name, &disk->disk_id))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -927,7 +927,7 @@ static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
|
||||
return false;
|
||||
|
||||
disk = &vb->vblk.disk;
|
||||
memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
|
||||
uuid_copy(&disk->disk_id, (uuid_t *)(buffer + 0x18 + r_name));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -112,8 +112,6 @@ struct frag { /* VBLK Fragment handling */
|
||||
|
||||
/* In memory LDM database structures. */
|
||||
|
||||
#define GUID_SIZE 16
|
||||
|
||||
struct privhead { /* Offsets and sizes are in sectors. */
|
||||
u16 ver_major;
|
||||
u16 ver_minor;
|
||||
@ -121,7 +119,7 @@ struct privhead { /* Offsets and sizes are in sectors. */
|
||||
u64 logical_disk_size;
|
||||
u64 config_start;
|
||||
u64 config_size;
|
||||
u8 disk_id[GUID_SIZE];
|
||||
uuid_t disk_id;
|
||||
};
|
||||
|
||||
struct tocblock { /* We have exactly two bitmaps. */
|
||||
@ -154,7 +152,7 @@ struct vblk_dgrp { /* VBLK Disk Group */
|
||||
};
|
||||
|
||||
struct vblk_disk { /* VBLK Disk */
|
||||
u8 disk_id[GUID_SIZE];
|
||||
uuid_t disk_id;
|
||||
u8 alt_name[128];
|
||||
};
|
||||
|
||||
|
@ -141,9 +141,9 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
|
||||
int cpu = mce->extcpu;
|
||||
struct acpi_hest_generic_status *estatus, *tmp;
|
||||
struct acpi_hest_generic_data *gdata;
|
||||
const uuid_le *fru_id = &NULL_UUID_LE;
|
||||
const guid_t *fru_id = &guid_null;
|
||||
char *fru_text = "";
|
||||
uuid_le *sec_type;
|
||||
guid_t *sec_type;
|
||||
static u32 err_seq;
|
||||
|
||||
estatus = extlog_elog_entry_check(cpu, bank);
|
||||
@ -165,11 +165,11 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
|
||||
err_seq++;
|
||||
gdata = (struct acpi_hest_generic_data *)(tmp + 1);
|
||||
if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
|
||||
fru_id = (uuid_le *)gdata->fru_id;
|
||||
fru_id = (guid_t *)gdata->fru_id;
|
||||
if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
|
||||
fru_text = gdata->fru_text;
|
||||
sec_type = (uuid_le *)gdata->section_type;
|
||||
if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
|
||||
sec_type = (guid_t *)gdata->section_type;
|
||||
if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
|
||||
struct cper_sec_mem_err *mem = (void *)(gdata + 1);
|
||||
if (gdata->error_data_length >= sizeof(*mem))
|
||||
trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
|
||||
@ -182,17 +182,17 @@ out:
|
||||
|
||||
static bool __init extlog_get_l1addr(void)
|
||||
{
|
||||
u8 uuid[16];
|
||||
guid_t guid;
|
||||
acpi_handle handle;
|
||||
union acpi_object *obj;
|
||||
|
||||
acpi_str_to_uuid(extlog_dsm_uuid, uuid);
|
||||
|
||||
if (guid_parse(extlog_dsm_uuid, &guid))
|
||||
return false;
|
||||
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
|
||||
return false;
|
||||
if (!acpi_check_dsm(handle, uuid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR))
|
||||
if (!acpi_check_dsm(handle, &guid, EXTLOG_DSM_REV, 1 << EXTLOG_FN_ADDR))
|
||||
return false;
|
||||
obj = acpi_evaluate_dsm_typed(handle, uuid, EXTLOG_DSM_REV,
|
||||
obj = acpi_evaluate_dsm_typed(handle, &guid, EXTLOG_DSM_REV,
|
||||
EXTLOG_FN_ADDR, NULL, ACPI_TYPE_INTEGER);
|
||||
if (!obj) {
|
||||
return false;
|
||||
|
@ -418,11 +418,7 @@ acpi_tb_get_table(struct acpi_table_desc *table_desc,
|
||||
|
||||
table_desc->validation_count++;
|
||||
if (table_desc->validation_count == 0) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Table %p, Validation count is zero after increment\n",
|
||||
table_desc));
|
||||
table_desc->validation_count--;
|
||||
return_ACPI_STATUS(AE_LIMIT);
|
||||
}
|
||||
|
||||
*out_table = table_desc->pointer;
|
||||
|
@ -39,6 +39,21 @@ config ACPI_APEI_PCIEAER
|
||||
PCIe AER errors may be reported via APEI firmware first mode.
|
||||
Turn on this option to enable the corresponding support.
|
||||
|
||||
config ACPI_APEI_SEA
|
||||
bool "APEI Synchronous External Abort logging/recovering support"
|
||||
depends on ARM64 && ACPI_APEI_GHES
|
||||
default y
|
||||
help
|
||||
This option should be enabled if the system supports
|
||||
firmware first handling of SEA (Synchronous External Abort).
|
||||
SEA happens with certain faults of data abort or instruction
|
||||
abort synchronous exceptions on ARMv8 systems. If a system
|
||||
supports firmware first handling of SEA, the platform analyzes
|
||||
and handles hardware error notifications from SEA, and it may then
|
||||
form a HW error record for the OS to parse and handle. This
|
||||
option allows the OS to look for such hardware error record, and
|
||||
take appropriate action.
|
||||
|
||||
config ACPI_APEI_MEMORY_FAILURE
|
||||
bool "APEI memory error recovering support"
|
||||
depends on ACPI_APEI && MEMORY_FAILURE
|
||||
|
@ -45,10 +45,14 @@
|
||||
#include <linux/aer.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/sched/clock.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/ras.h>
|
||||
|
||||
#include <acpi/actbl1.h>
|
||||
#include <acpi/ghes.h>
|
||||
#include <acpi/apei.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <ras/ras_event.h>
|
||||
|
||||
#include "apei-internal.h"
|
||||
|
||||
@ -80,6 +84,11 @@
|
||||
((struct acpi_hest_generic_status *) \
|
||||
((struct ghes_estatus_node *)(estatus_node) + 1))
|
||||
|
||||
static inline bool is_hest_type_generic_v2(struct ghes *ghes)
|
||||
{
|
||||
return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
|
||||
}
|
||||
|
||||
/*
|
||||
* This driver isn't really modular, however for the time being,
|
||||
* continuing to use module_param is the easiest way to remain
|
||||
@ -110,11 +119,7 @@ static DEFINE_MUTEX(ghes_list_mutex);
|
||||
* Two virtual pages are used, one for IRQ/PROCESS context, the other for
|
||||
* NMI context (optionally).
|
||||
*/
|
||||
#ifdef CONFIG_HAVE_ACPI_APEI_NMI
|
||||
#define GHES_IOREMAP_PAGES 2
|
||||
#else
|
||||
#define GHES_IOREMAP_PAGES 1
|
||||
#endif
|
||||
#define GHES_IOREMAP_IRQ_PAGE(base) (base)
|
||||
#define GHES_IOREMAP_NMI_PAGE(base) ((base) + PAGE_SIZE)
|
||||
|
||||
@ -133,6 +138,8 @@ static unsigned long ghes_estatus_pool_size_request;
|
||||
static struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
|
||||
static atomic_t ghes_estatus_cache_alloced;
|
||||
|
||||
static int ghes_panic_timeout __read_mostly = 30;
|
||||
|
||||
static int ghes_ioremap_init(void)
|
||||
{
|
||||
ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
|
||||
@ -153,10 +160,14 @@ static void ghes_ioremap_exit(void)
|
||||
static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
|
||||
{
|
||||
unsigned long vaddr;
|
||||
phys_addr_t paddr;
|
||||
pgprot_t prot;
|
||||
|
||||
vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
|
||||
ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
|
||||
pfn << PAGE_SHIFT, PAGE_KERNEL);
|
||||
|
||||
paddr = pfn << PAGE_SHIFT;
|
||||
prot = arch_apei_get_mem_attribute(paddr);
|
||||
ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot);
|
||||
|
||||
return (void __iomem *)vaddr;
|
||||
}
|
||||
@ -240,6 +251,16 @@ static int ghes_estatus_pool_expand(unsigned long len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int map_gen_v2(struct ghes *ghes)
|
||||
{
|
||||
return apei_map_generic_address(&ghes->generic_v2->read_ack_register);
|
||||
}
|
||||
|
||||
static void unmap_gen_v2(struct ghes *ghes)
|
||||
{
|
||||
apei_unmap_generic_address(&ghes->generic_v2->read_ack_register);
|
||||
}
|
||||
|
||||
static struct ghes *ghes_new(struct acpi_hest_generic *generic)
|
||||
{
|
||||
struct ghes *ghes;
|
||||
@ -249,10 +270,17 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
|
||||
ghes = kzalloc(sizeof(*ghes), GFP_KERNEL);
|
||||
if (!ghes)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ghes->generic = generic;
|
||||
if (is_hest_type_generic_v2(ghes)) {
|
||||
rc = map_gen_v2(ghes);
|
||||
if (rc)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
rc = apei_map_generic_address(&generic->error_status_address);
|
||||
if (rc)
|
||||
goto err_free;
|
||||
goto err_unmap_read_ack_addr;
|
||||
error_block_length = generic->error_block_length;
|
||||
if (error_block_length > GHES_ESTATUS_MAX_SIZE) {
|
||||
pr_warning(FW_WARN GHES_PFX
|
||||
@ -264,13 +292,16 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
|
||||
ghes->estatus = kmalloc(error_block_length, GFP_KERNEL);
|
||||
if (!ghes->estatus) {
|
||||
rc = -ENOMEM;
|
||||
goto err_unmap;
|
||||
goto err_unmap_status_addr;
|
||||
}
|
||||
|
||||
return ghes;
|
||||
|
||||
err_unmap:
|
||||
err_unmap_status_addr:
|
||||
apei_unmap_generic_address(&generic->error_status_address);
|
||||
err_unmap_read_ack_addr:
|
||||
if (is_hest_type_generic_v2(ghes))
|
||||
unmap_gen_v2(ghes);
|
||||
err_free:
|
||||
kfree(ghes);
|
||||
return ERR_PTR(rc);
|
||||
@ -280,6 +311,8 @@ static void ghes_fini(struct ghes *ghes)
|
||||
{
|
||||
kfree(ghes->estatus);
|
||||
apei_unmap_generic_address(&ghes->generic->error_status_address);
|
||||
if (is_hest_type_generic_v2(ghes))
|
||||
unmap_gen_v2(ghes);
|
||||
}
|
||||
|
||||
static inline int ghes_severity(int severity)
|
||||
@ -400,8 +433,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
|
||||
unsigned long pfn;
|
||||
int flags = -1;
|
||||
int sec_sev = ghes_severity(gdata->error_severity);
|
||||
struct cper_sec_mem_err *mem_err;
|
||||
mem_err = (struct cper_sec_mem_err *)(gdata + 1);
|
||||
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
|
||||
return;
|
||||
@ -431,24 +463,32 @@ static void ghes_do_proc(struct ghes *ghes,
|
||||
{
|
||||
int sev, sec_sev;
|
||||
struct acpi_hest_generic_data *gdata;
|
||||
guid_t *sec_type;
|
||||
guid_t *fru_id = &NULL_UUID_LE;
|
||||
char *fru_text = "";
|
||||
|
||||
sev = ghes_severity(estatus->error_severity);
|
||||
apei_estatus_for_each_section(estatus, gdata) {
|
||||
sec_type = (guid_t *)gdata->section_type;
|
||||
sec_sev = ghes_severity(gdata->error_severity);
|
||||
if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
|
||||
CPER_SEC_PLATFORM_MEM)) {
|
||||
struct cper_sec_mem_err *mem_err;
|
||||
mem_err = (struct cper_sec_mem_err *)(gdata+1);
|
||||
if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
|
||||
fru_id = (guid_t *)gdata->fru_id;
|
||||
|
||||
if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
|
||||
fru_text = gdata->fru_text;
|
||||
|
||||
if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
|
||||
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
ghes_edac_report_mem_error(ghes, sev, mem_err);
|
||||
|
||||
arch_apei_report_mem_error(sev, mem_err);
|
||||
ghes_handle_memory_failure(gdata, sev);
|
||||
}
|
||||
#ifdef CONFIG_ACPI_APEI_PCIEAER
|
||||
else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
|
||||
CPER_SEC_PCIE)) {
|
||||
struct cper_sec_pcie *pcie_err;
|
||||
pcie_err = (struct cper_sec_pcie *)(gdata+1);
|
||||
else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
|
||||
struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
if (sev == GHES_SEV_RECOVERABLE &&
|
||||
sec_sev == GHES_SEV_RECOVERABLE &&
|
||||
pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
|
||||
@ -477,6 +517,17 @@ static void ghes_do_proc(struct ghes *ghes,
|
||||
|
||||
}
|
||||
#endif
|
||||
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
|
||||
struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
|
||||
|
||||
log_arm_hw_error(err);
|
||||
} else {
|
||||
void *err = acpi_hest_get_payload(gdata);
|
||||
|
||||
log_non_standard_event(sec_type, fru_id, fru_text,
|
||||
sec_sev, err,
|
||||
gdata->error_data_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -649,6 +700,31 @@ static void ghes_estatus_cache_add(
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int ghes_ack_error(struct acpi_hest_generic_v2 *gv2)
|
||||
{
|
||||
int rc;
|
||||
u64 val = 0;
|
||||
|
||||
rc = apei_read(&val, &gv2->read_ack_register);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
val &= gv2->read_ack_preserve << gv2->read_ack_register.bit_offset;
|
||||
val |= gv2->read_ack_write << gv2->read_ack_register.bit_offset;
|
||||
|
||||
return apei_write(val, &gv2->read_ack_register);
|
||||
}
|
||||
|
||||
static void __ghes_panic(struct ghes *ghes)
|
||||
{
|
||||
__ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
|
||||
|
||||
/* reboot to log the error! */
|
||||
if (!panic_timeout)
|
||||
panic_timeout = ghes_panic_timeout;
|
||||
panic("Fatal hardware error!");
|
||||
}
|
||||
|
||||
static int ghes_proc(struct ghes *ghes)
|
||||
{
|
||||
int rc;
|
||||
@ -656,11 +732,26 @@ static int ghes_proc(struct ghes *ghes)
|
||||
rc = ghes_read_estatus(ghes, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
if (ghes_severity(ghes->estatus->error_severity) >= GHES_SEV_PANIC) {
|
||||
__ghes_panic(ghes);
|
||||
}
|
||||
|
||||
if (!ghes_estatus_cached(ghes->estatus)) {
|
||||
if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus))
|
||||
ghes_estatus_cache_add(ghes->generic, ghes->estatus);
|
||||
}
|
||||
ghes_do_proc(ghes, ghes->estatus);
|
||||
|
||||
/*
|
||||
* GHESv2 type HEST entries introduce support for error acknowledgment,
|
||||
* so only acknowledge the error if this support is present.
|
||||
*/
|
||||
if (is_hest_type_generic_v2(ghes)) {
|
||||
rc = ghes_ack_error(ghes->generic_v2);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
out:
|
||||
ghes_clear_estatus(ghes);
|
||||
return rc;
|
||||
@ -722,6 +813,55 @@ static struct notifier_block ghes_notifier_sci = {
|
||||
.notifier_call = ghes_notify_sci,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI_APEI_SEA
|
||||
static LIST_HEAD(ghes_sea);
|
||||
|
||||
/*
|
||||
* Return 0 only if one of the SEA error sources successfully reported an error
|
||||
* record sent from the firmware.
|
||||
*/
|
||||
int ghes_notify_sea(void)
|
||||
{
|
||||
struct ghes *ghes;
|
||||
int ret = -ENOENT;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ghes, &ghes_sea, list) {
|
||||
if (!ghes_proc(ghes))
|
||||
ret = 0;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ghes_sea_add(struct ghes *ghes)
|
||||
{
|
||||
mutex_lock(&ghes_list_mutex);
|
||||
list_add_rcu(&ghes->list, &ghes_sea);
|
||||
mutex_unlock(&ghes_list_mutex);
|
||||
}
|
||||
|
||||
static void ghes_sea_remove(struct ghes *ghes)
|
||||
{
|
||||
mutex_lock(&ghes_list_mutex);
|
||||
list_del_rcu(&ghes->list);
|
||||
mutex_unlock(&ghes_list_mutex);
|
||||
synchronize_rcu();
|
||||
}
|
||||
#else /* CONFIG_ACPI_APEI_SEA */
|
||||
static inline void ghes_sea_add(struct ghes *ghes)
|
||||
{
|
||||
pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n",
|
||||
ghes->generic->header.source_id);
|
||||
}
|
||||
|
||||
static inline void ghes_sea_remove(struct ghes *ghes)
|
||||
{
|
||||
pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n",
|
||||
ghes->generic->header.source_id);
|
||||
}
|
||||
#endif /* CONFIG_ACPI_APEI_SEA */
|
||||
|
||||
#ifdef CONFIG_HAVE_ACPI_APEI_NMI
|
||||
/*
|
||||
* printk is not safe in NMI context. So in NMI handler, we allocate
|
||||
@ -742,8 +882,6 @@ static atomic_t ghes_in_nmi = ATOMIC_INIT(0);
|
||||
|
||||
static LIST_HEAD(ghes_nmi);
|
||||
|
||||
static int ghes_panic_timeout __read_mostly = 30;
|
||||
|
||||
static void ghes_proc_in_irq(struct irq_work *irq_work)
|
||||
{
|
||||
struct llist_node *llnode, *next;
|
||||
@ -829,18 +967,6 @@ static void __process_error(struct ghes *ghes)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __ghes_panic(struct ghes *ghes)
|
||||
{
|
||||
oops_begin();
|
||||
ghes_print_queued_estatus();
|
||||
__ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
|
||||
|
||||
/* reboot to log the error! */
|
||||
if (panic_timeout == 0)
|
||||
panic_timeout = ghes_panic_timeout;
|
||||
panic("Fatal hardware error!");
|
||||
}
|
||||
|
||||
static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
|
||||
{
|
||||
struct ghes *ghes;
|
||||
@ -858,8 +984,11 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
|
||||
}
|
||||
|
||||
sev = ghes_severity(ghes->estatus->error_severity);
|
||||
if (sev >= GHES_SEV_PANIC)
|
||||
if (sev >= GHES_SEV_PANIC) {
|
||||
oops_begin();
|
||||
ghes_print_queued_estatus();
|
||||
__ghes_panic(ghes);
|
||||
}
|
||||
|
||||
if (!(ghes->flags & GHES_TO_CLEAR))
|
||||
continue;
|
||||
@ -967,6 +1096,14 @@ static int ghes_probe(struct platform_device *ghes_dev)
|
||||
case ACPI_HEST_NOTIFY_EXTERNAL:
|
||||
case ACPI_HEST_NOTIFY_SCI:
|
||||
break;
|
||||
case ACPI_HEST_NOTIFY_SEA:
|
||||
if (!IS_ENABLED(CONFIG_ACPI_APEI_SEA)) {
|
||||
pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n",
|
||||
generic->header.source_id);
|
||||
rc = -ENOTSUPP;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
case ACPI_HEST_NOTIFY_NMI:
|
||||
if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
|
||||
pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
|
||||
@ -1031,6 +1168,9 @@ static int ghes_probe(struct platform_device *ghes_dev)
|
||||
list_add_rcu(&ghes->list, &ghes_sci);
|
||||
mutex_unlock(&ghes_list_mutex);
|
||||
break;
|
||||
case ACPI_HEST_NOTIFY_SEA:
|
||||
ghes_sea_add(ghes);
|
||||
break;
|
||||
case ACPI_HEST_NOTIFY_NMI:
|
||||
ghes_nmi_add(ghes);
|
||||
break;
|
||||
@ -1039,6 +1179,9 @@ static int ghes_probe(struct platform_device *ghes_dev)
|
||||
}
|
||||
platform_set_drvdata(ghes_dev, ghes);
|
||||
|
||||
/* Handle any pending errors right away */
|
||||
ghes_proc(ghes);
|
||||
|
||||
return 0;
|
||||
err_edac_unreg:
|
||||
ghes_edac_unregister(ghes);
|
||||
@ -1074,6 +1217,9 @@ static int ghes_remove(struct platform_device *ghes_dev)
|
||||
mutex_unlock(&ghes_list_mutex);
|
||||
synchronize_rcu();
|
||||
break;
|
||||
case ACPI_HEST_NOTIFY_SEA:
|
||||
ghes_sea_remove(ghes);
|
||||
break;
|
||||
case ACPI_HEST_NOTIFY_NMI:
|
||||
ghes_nmi_remove(ghes);
|
||||
break;
|
||||
|
@ -52,6 +52,7 @@ static const int hest_esrc_len_tab[ACPI_HEST_TYPE_RESERVED] = {
|
||||
[ACPI_HEST_TYPE_AER_ENDPOINT] = sizeof(struct acpi_hest_aer),
|
||||
[ACPI_HEST_TYPE_AER_BRIDGE] = sizeof(struct acpi_hest_aer_bridge),
|
||||
[ACPI_HEST_TYPE_GENERIC_ERROR] = sizeof(struct acpi_hest_generic),
|
||||
[ACPI_HEST_TYPE_GENERIC_ERROR_V2] = sizeof(struct acpi_hest_generic_v2),
|
||||
};
|
||||
|
||||
static int hest_esrc_len(struct acpi_hest_header *hest_hdr)
|
||||
@ -141,7 +142,8 @@ static int __init hest_parse_ghes_count(struct acpi_hest_header *hest_hdr, void
|
||||
{
|
||||
int *count = data;
|
||||
|
||||
if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR)
|
||||
if (hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR ||
|
||||
hest_hdr->type == ACPI_HEST_TYPE_GENERIC_ERROR_V2)
|
||||
(*count)++;
|
||||
return 0;
|
||||
}
|
||||
@ -152,7 +154,8 @@ static int __init hest_parse_ghes(struct acpi_hest_header *hest_hdr, void *data)
|
||||
struct ghes_arr *ghes_arr = data;
|
||||
int rc, i;
|
||||
|
||||
if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR)
|
||||
if (hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR &&
|
||||
hest_hdr->type != ACPI_HEST_TYPE_GENERIC_ERROR_V2)
|
||||
return 0;
|
||||
|
||||
if (!((struct acpi_hest_generic *)hest_hdr)->enabled)
|
||||
|
@ -196,42 +196,19 @@ static void acpi_print_osc_error(acpi_handle handle,
|
||||
pr_debug("\n");
|
||||
}
|
||||
|
||||
acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
|
||||
{
|
||||
int i;
|
||||
static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21,
|
||||
24, 26, 28, 30, 32, 34};
|
||||
|
||||
if (strlen(str) != 36)
|
||||
return AE_BAD_PARAMETER;
|
||||
for (i = 0; i < 36; i++) {
|
||||
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
||||
if (str[i] != '-')
|
||||
return AE_BAD_PARAMETER;
|
||||
} else if (!isxdigit(str[i]))
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
uuid[i] = hex_to_bin(str[opc_map_to_uuid[i]]) << 4;
|
||||
uuid[i] |= hex_to_bin(str[opc_map_to_uuid[i] + 1]);
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_str_to_uuid);
|
||||
|
||||
acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object in_params[4];
|
||||
union acpi_object *out_obj;
|
||||
u8 uuid[16];
|
||||
guid_t guid;
|
||||
u32 errors;
|
||||
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
|
||||
if (!context)
|
||||
return AE_ERROR;
|
||||
if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid)))
|
||||
if (guid_parse(context->uuid_str, &guid))
|
||||
return AE_ERROR;
|
||||
context->ret.length = ACPI_ALLOCATE_BUFFER;
|
||||
context->ret.pointer = NULL;
|
||||
@ -241,7 +218,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
|
||||
input.pointer = in_params;
|
||||
in_params[0].type = ACPI_TYPE_BUFFER;
|
||||
in_params[0].buffer.length = 16;
|
||||
in_params[0].buffer.pointer = uuid;
|
||||
in_params[0].buffer.pointer = (u8 *)&guid;
|
||||
in_params[1].type = ACPI_TYPE_INTEGER;
|
||||
in_params[1].integer.value = context->rev;
|
||||
in_params[2].type = ACPI_TYPE_INTEGER;
|
||||
|
@ -113,7 +113,7 @@ struct acpi_button {
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
|
||||
static struct acpi_device *lid_device;
|
||||
static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
|
||||
static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
|
||||
|
||||
static unsigned long lid_report_interval __read_mostly = 500;
|
||||
module_param(lid_report_interval, ulong, 0644);
|
||||
|
@ -74,11 +74,11 @@ struct nfit_table_prev {
|
||||
struct list_head flushes;
|
||||
};
|
||||
|
||||
static u8 nfit_uuid[NFIT_UUID_MAX][16];
|
||||
static guid_t nfit_uuid[NFIT_UUID_MAX];
|
||||
|
||||
const u8 *to_nfit_uuid(enum nfit_uuids id)
|
||||
const guid_t *to_nfit_uuid(enum nfit_uuids id)
|
||||
{
|
||||
return nfit_uuid[id];
|
||||
return &nfit_uuid[id];
|
||||
}
|
||||
EXPORT_SYMBOL(to_nfit_uuid);
|
||||
|
||||
@ -222,7 +222,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
||||
u32 offset, fw_status = 0;
|
||||
acpi_handle handle;
|
||||
unsigned int func;
|
||||
const u8 *uuid;
|
||||
const guid_t *guid;
|
||||
int rc, i;
|
||||
|
||||
func = cmd;
|
||||
@ -245,7 +245,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
||||
cmd_mask = nvdimm_cmd_mask(nvdimm);
|
||||
dsm_mask = nfit_mem->dsm_mask;
|
||||
desc = nd_cmd_dimm_desc(cmd);
|
||||
uuid = to_nfit_uuid(nfit_mem->family);
|
||||
guid = to_nfit_uuid(nfit_mem->family);
|
||||
handle = adev->handle;
|
||||
} else {
|
||||
struct acpi_device *adev = to_acpi_dev(acpi_desc);
|
||||
@ -254,7 +254,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
||||
cmd_mask = nd_desc->cmd_mask;
|
||||
dsm_mask = cmd_mask;
|
||||
desc = nd_cmd_bus_desc(cmd);
|
||||
uuid = to_nfit_uuid(NFIT_DEV_BUS);
|
||||
guid = to_nfit_uuid(NFIT_DEV_BUS);
|
||||
handle = adev->handle;
|
||||
dimm_name = "bus";
|
||||
}
|
||||
@ -289,7 +289,7 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
|
||||
in_buf.buffer.pointer,
|
||||
min_t(u32, 256, in_buf.buffer.length), true);
|
||||
|
||||
out_obj = acpi_evaluate_dsm(handle, uuid, 1, func, &in_obj);
|
||||
out_obj = acpi_evaluate_dsm(handle, guid, 1, func, &in_obj);
|
||||
if (!out_obj) {
|
||||
dev_dbg(dev, "%s:%s _DSM failed cmd: %s\n", __func__, dimm_name,
|
||||
cmd_name);
|
||||
@ -409,7 +409,7 @@ int nfit_spa_type(struct acpi_nfit_system_address *spa)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NFIT_UUID_MAX; i++)
|
||||
if (memcmp(to_nfit_uuid(i), spa->range_guid, 16) == 0)
|
||||
if (guid_equal(to_nfit_uuid(i), (guid_t *)&spa->range_guid))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
@ -1415,7 +1415,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
|
||||
struct acpi_device *adev, *adev_dimm;
|
||||
struct device *dev = acpi_desc->dev;
|
||||
unsigned long dsm_mask;
|
||||
const u8 *uuid;
|
||||
const guid_t *guid;
|
||||
int i;
|
||||
int family = -1;
|
||||
|
||||
@ -1444,7 +1444,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
|
||||
/*
|
||||
* Until standardization materializes we need to consider 4
|
||||
* different command sets. Note, that checking for function0 (bit0)
|
||||
* tells us if any commands are reachable through this uuid.
|
||||
* tells us if any commands are reachable through this GUID.
|
||||
*/
|
||||
for (i = NVDIMM_FAMILY_INTEL; i <= NVDIMM_FAMILY_MSFT; i++)
|
||||
if (acpi_check_dsm(adev_dimm->handle, to_nfit_uuid(i), 1, 1))
|
||||
@ -1474,9 +1474,9 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
uuid = to_nfit_uuid(nfit_mem->family);
|
||||
guid = to_nfit_uuid(nfit_mem->family);
|
||||
for_each_set_bit(i, &dsm_mask, BITS_PER_LONG)
|
||||
if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i))
|
||||
if (acpi_check_dsm(adev_dimm->handle, guid, 1, 1ULL << i))
|
||||
set_bit(i, &nfit_mem->dsm_mask);
|
||||
|
||||
return 0;
|
||||
@ -1611,7 +1611,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
|
||||
static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
|
||||
{
|
||||
struct nvdimm_bus_descriptor *nd_desc = &acpi_desc->nd_desc;
|
||||
const u8 *uuid = to_nfit_uuid(NFIT_DEV_BUS);
|
||||
const guid_t *guid = to_nfit_uuid(NFIT_DEV_BUS);
|
||||
struct acpi_device *adev;
|
||||
int i;
|
||||
|
||||
@ -1621,7 +1621,7 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
|
||||
return;
|
||||
|
||||
for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++)
|
||||
if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i))
|
||||
if (acpi_check_dsm(adev->handle, guid, 1, 1ULL << i))
|
||||
set_bit(i, &nd_desc->cmd_mask);
|
||||
}
|
||||
|
||||
@ -3051,19 +3051,19 @@ static __init int nfit_init(void)
|
||||
BUILD_BUG_ON(sizeof(struct acpi_nfit_control_region) != 80);
|
||||
BUILD_BUG_ON(sizeof(struct acpi_nfit_data_region) != 40);
|
||||
|
||||
acpi_str_to_uuid(UUID_VOLATILE_MEMORY, nfit_uuid[NFIT_SPA_VOLATILE]);
|
||||
acpi_str_to_uuid(UUID_PERSISTENT_MEMORY, nfit_uuid[NFIT_SPA_PM]);
|
||||
acpi_str_to_uuid(UUID_CONTROL_REGION, nfit_uuid[NFIT_SPA_DCR]);
|
||||
acpi_str_to_uuid(UUID_DATA_REGION, nfit_uuid[NFIT_SPA_BDW]);
|
||||
acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_VDISK]);
|
||||
acpi_str_to_uuid(UUID_VOLATILE_VIRTUAL_CD, nfit_uuid[NFIT_SPA_VCD]);
|
||||
acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_DISK, nfit_uuid[NFIT_SPA_PDISK]);
|
||||
acpi_str_to_uuid(UUID_PERSISTENT_VIRTUAL_CD, nfit_uuid[NFIT_SPA_PCD]);
|
||||
acpi_str_to_uuid(UUID_NFIT_BUS, nfit_uuid[NFIT_DEV_BUS]);
|
||||
acpi_str_to_uuid(UUID_NFIT_DIMM, nfit_uuid[NFIT_DEV_DIMM]);
|
||||
acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE1, nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
|
||||
acpi_str_to_uuid(UUID_NFIT_DIMM_N_HPE2, nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
|
||||
acpi_str_to_uuid(UUID_NFIT_DIMM_N_MSFT, nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
|
||||
guid_parse(UUID_VOLATILE_MEMORY, &nfit_uuid[NFIT_SPA_VOLATILE]);
|
||||
guid_parse(UUID_PERSISTENT_MEMORY, &nfit_uuid[NFIT_SPA_PM]);
|
||||
guid_parse(UUID_CONTROL_REGION, &nfit_uuid[NFIT_SPA_DCR]);
|
||||
guid_parse(UUID_DATA_REGION, &nfit_uuid[NFIT_SPA_BDW]);
|
||||
guid_parse(UUID_VOLATILE_VIRTUAL_DISK, &nfit_uuid[NFIT_SPA_VDISK]);
|
||||
guid_parse(UUID_VOLATILE_VIRTUAL_CD, &nfit_uuid[NFIT_SPA_VCD]);
|
||||
guid_parse(UUID_PERSISTENT_VIRTUAL_DISK, &nfit_uuid[NFIT_SPA_PDISK]);
|
||||
guid_parse(UUID_PERSISTENT_VIRTUAL_CD, &nfit_uuid[NFIT_SPA_PCD]);
|
||||
guid_parse(UUID_NFIT_BUS, &nfit_uuid[NFIT_DEV_BUS]);
|
||||
guid_parse(UUID_NFIT_DIMM, &nfit_uuid[NFIT_DEV_DIMM]);
|
||||
guid_parse(UUID_NFIT_DIMM_N_HPE1, &nfit_uuid[NFIT_DEV_DIMM_N_HPE1]);
|
||||
guid_parse(UUID_NFIT_DIMM_N_HPE2, &nfit_uuid[NFIT_DEV_DIMM_N_HPE2]);
|
||||
guid_parse(UUID_NFIT_DIMM_N_MSFT, &nfit_uuid[NFIT_DEV_DIMM_N_MSFT]);
|
||||
|
||||
nfit_wq = create_singlethread_workqueue("nfit");
|
||||
if (!nfit_wq)
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/libnvdimm.h>
|
||||
#include <linux/ndctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acuuid.h>
|
||||
|
||||
@ -237,7 +236,7 @@ static inline struct acpi_nfit_desc *to_acpi_desc(
|
||||
return container_of(nd_desc, struct acpi_nfit_desc, nd_desc);
|
||||
}
|
||||
|
||||
const u8 *to_nfit_uuid(enum nfit_uuids id);
|
||||
const guid_t *to_nfit_uuid(enum nfit_uuids id);
|
||||
int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz);
|
||||
void acpi_nfit_shutdown(void *data);
|
||||
void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event);
|
||||
|
@ -333,14 +333,17 @@ static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj,
|
||||
container_of(bin_attr, struct acpi_table_attr, attr);
|
||||
struct acpi_table_header *table_header = NULL;
|
||||
acpi_status status;
|
||||
ssize_t rc;
|
||||
|
||||
status = acpi_get_table(table_attr->name, table_attr->instance,
|
||||
&table_header);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
return memory_read_from_buffer(buf, count, &offset,
|
||||
table_header, table_header->length);
|
||||
rc = memory_read_from_buffer(buf, count, &offset, table_header,
|
||||
table_header->length);
|
||||
acpi_put_table(table_header);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int acpi_table_attr_init(struct kobject *tables_obj,
|
||||
|
@ -613,19 +613,19 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
|
||||
/**
|
||||
* acpi_evaluate_dsm - evaluate device's _DSM method
|
||||
* @handle: ACPI device handle
|
||||
* @uuid: UUID of requested functions, should be 16 bytes
|
||||
* @guid: GUID of requested functions, should be 16 bytes
|
||||
* @rev: revision number of requested function
|
||||
* @func: requested function number
|
||||
* @argv4: the function specific parameter
|
||||
*
|
||||
* Evaluate device's _DSM method with specified UUID, revision id and
|
||||
* Evaluate device's _DSM method with specified GUID, revision id and
|
||||
* function number. Caller needs to free the returned object.
|
||||
*
|
||||
* Though ACPI defines the fourth parameter for _DSM should be a package,
|
||||
* some old BIOSes do expect a buffer or an integer etc.
|
||||
*/
|
||||
union acpi_object *
|
||||
acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 func,
|
||||
acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func,
|
||||
union acpi_object *argv4)
|
||||
{
|
||||
acpi_status ret;
|
||||
@ -638,7 +638,7 @@ acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 func,
|
||||
|
||||
params[0].type = ACPI_TYPE_BUFFER;
|
||||
params[0].buffer.length = 16;
|
||||
params[0].buffer.pointer = (char *)uuid;
|
||||
params[0].buffer.pointer = (u8 *)guid;
|
||||
params[1].type = ACPI_TYPE_INTEGER;
|
||||
params[1].integer.value = rev;
|
||||
params[2].type = ACPI_TYPE_INTEGER;
|
||||
@ -666,7 +666,7 @@ EXPORT_SYMBOL(acpi_evaluate_dsm);
|
||||
/**
|
||||
* acpi_check_dsm - check if _DSM method supports requested functions.
|
||||
* @handle: ACPI device handle
|
||||
* @uuid: UUID of requested functions, should be 16 bytes at least
|
||||
* @guid: GUID of requested functions, should be 16 bytes at least
|
||||
* @rev: revision number of requested functions
|
||||
* @funcs: bitmap of requested functions
|
||||
*
|
||||
@ -674,7 +674,7 @@ EXPORT_SYMBOL(acpi_evaluate_dsm);
|
||||
* functions. Currently only support 64 functions at maximum, should be
|
||||
* enough for now.
|
||||
*/
|
||||
bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs)
|
||||
bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs)
|
||||
{
|
||||
int i;
|
||||
u64 mask = 0;
|
||||
@ -683,7 +683,7 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs)
|
||||
if (funcs == 0)
|
||||
return false;
|
||||
|
||||
obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL);
|
||||
obj = acpi_evaluate_dsm(handle, guid, rev, 0, NULL);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
@ -697,7 +697,7 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, u64 rev, u64 funcs)
|
||||
|
||||
/*
|
||||
* Bit 0 indicates whether there's support for any functions other than
|
||||
* function 0 for the specified UUID and revision.
|
||||
* function 0 for the specified GUID and revision.
|
||||
*/
|
||||
if ((mask & 0x1) && (mask & funcs) == funcs)
|
||||
return true;
|
||||
|
@ -937,14 +937,6 @@ static int nbd_reconnect_socket(struct nbd_device *nbd, unsigned long arg)
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
/* Reset all properties of an NBD device */
|
||||
static void nbd_reset(struct nbd_device *nbd)
|
||||
{
|
||||
nbd->config = NULL;
|
||||
nbd->tag_set.timeout = 0;
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue);
|
||||
}
|
||||
|
||||
static void nbd_bdev_reset(struct block_device *bdev)
|
||||
{
|
||||
if (bdev->bd_openers > 1)
|
||||
@ -1029,7 +1021,11 @@ static void nbd_config_put(struct nbd_device *nbd)
|
||||
}
|
||||
kfree(config->socks);
|
||||
}
|
||||
nbd_reset(nbd);
|
||||
kfree(nbd->config);
|
||||
nbd->config = NULL;
|
||||
|
||||
nbd->tag_set.timeout = 0;
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, nbd->disk->queue);
|
||||
|
||||
mutex_unlock(&nbd->config_lock);
|
||||
nbd_put(nbd);
|
||||
@ -1483,7 +1479,6 @@ static int nbd_dev_add(int index)
|
||||
disk->fops = &nbd_fops;
|
||||
disk->private_data = nbd;
|
||||
sprintf(disk->disk_name, "nbd%d", index);
|
||||
nbd_reset(nbd);
|
||||
add_disk(disk);
|
||||
nbd_total_devices++;
|
||||
return index;
|
||||
|
@ -4023,6 +4023,7 @@ static void rbd_queue_workfn(struct work_struct *work)
|
||||
|
||||
switch (req_op(rq)) {
|
||||
case REQ_OP_DISCARD:
|
||||
case REQ_OP_WRITE_ZEROES:
|
||||
op_type = OBJ_OP_DISCARD;
|
||||
break;
|
||||
case REQ_OP_WRITE:
|
||||
@ -4420,6 +4421,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
|
||||
q->limits.discard_granularity = segment_size;
|
||||
q->limits.discard_alignment = segment_size;
|
||||
blk_queue_max_discard_sectors(q, segment_size / SECTOR_SIZE);
|
||||
blk_queue_max_write_zeroes_sectors(q, segment_size / SECTOR_SIZE);
|
||||
|
||||
if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC))
|
||||
q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES;
|
||||
|
@ -374,7 +374,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
|
||||
|
||||
rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);
|
||||
if (rc <= 0) {
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
|
||||
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
|
||||
if (rc == -ERESTARTSYS)
|
||||
return rc;
|
||||
@ -387,7 +387,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
|
||||
for (i = 0; i < bytes_to_write; i++) {
|
||||
rc = wait_for_bulk_out_ready(dev);
|
||||
if (rc <= 0) {
|
||||
DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n",
|
||||
DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2zx\n",
|
||||
rc);
|
||||
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
|
||||
if (rc == -ERESTARTSYS)
|
||||
@ -403,7 +403,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf,
|
||||
rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);
|
||||
|
||||
if (rc <= 0) {
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
|
||||
DEBUGP(5, dev, "write_sync_reg c=%.2zx\n", rc);
|
||||
DEBUGP(2, dev, "<- cm4040_write (failed)\n");
|
||||
if (rc == -ERESTARTSYS)
|
||||
return rc;
|
||||
|
@ -1097,12 +1097,16 @@ static void add_interrupt_bench(cycles_t start)
|
||||
static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
|
||||
{
|
||||
__u32 *ptr = (__u32 *) regs;
|
||||
unsigned long flags;
|
||||
|
||||
if (regs == NULL)
|
||||
return 0;
|
||||
local_irq_save(flags);
|
||||
if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32))
|
||||
f->reg_idx = 0;
|
||||
return *(ptr + f->reg_idx++);
|
||||
ptr += f->reg_idx++;
|
||||
local_irq_restore(flags);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
void add_interrupt_randomness(int irq, int irq_flags)
|
||||
|
@ -27,10 +27,9 @@
|
||||
|
||||
#define ACPI_SIG_TPM2 "TPM2"
|
||||
|
||||
static const u8 CRB_ACPI_START_UUID[] = {
|
||||
/* 0000 */ 0xAB, 0x6C, 0xBF, 0x6B, 0x63, 0x54, 0x14, 0x47,
|
||||
/* 0008 */ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4
|
||||
};
|
||||
static const guid_t crb_acpi_start_guid =
|
||||
GUID_INIT(0x6BBF6CAB, 0x5463, 0x4714,
|
||||
0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4);
|
||||
|
||||
enum crb_defaults {
|
||||
CRB_ACPI_START_REVISION_ID = 1,
|
||||
@ -266,7 +265,7 @@ static int crb_do_acpi_start(struct tpm_chip *chip)
|
||||
int rc;
|
||||
|
||||
obj = acpi_evaluate_dsm(chip->acpi_dev_handle,
|
||||
CRB_ACPI_START_UUID,
|
||||
&crb_acpi_start_guid,
|
||||
CRB_ACPI_START_REVISION_ID,
|
||||
CRB_ACPI_START_INDEX,
|
||||
NULL);
|
||||
|
@ -32,20 +32,16 @@
|
||||
#define PPI_VS_REQ_START 128
|
||||
#define PPI_VS_REQ_END 255
|
||||
|
||||
static const u8 tpm_ppi_uuid[] = {
|
||||
0xA6, 0xFA, 0xDD, 0x3D,
|
||||
0x1B, 0x36,
|
||||
0xB4, 0x4E,
|
||||
0xA4, 0x24,
|
||||
0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
|
||||
};
|
||||
static const guid_t tpm_ppi_guid =
|
||||
GUID_INIT(0x3DDDFAA6, 0x361B, 0x4EB4,
|
||||
0xA4, 0x24, 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53);
|
||||
|
||||
static inline union acpi_object *
|
||||
tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
|
||||
union acpi_object *argv4)
|
||||
{
|
||||
BUG_ON(!ppi_handle);
|
||||
return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid,
|
||||
return acpi_evaluate_dsm_typed(ppi_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID,
|
||||
func, argv4, type);
|
||||
}
|
||||
@ -107,7 +103,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
|
||||
* is updated with function index from SUBREQ to SUBREQ2 since PPI
|
||||
* version 1.1
|
||||
*/
|
||||
if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
|
||||
if (acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
|
||||
func = TPM_PPI_FN_SUBREQ2;
|
||||
|
||||
@ -268,7 +264,7 @@ static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
|
||||
"User not required",
|
||||
};
|
||||
|
||||
if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
|
||||
if (!acpi_check_dsm(dev_handle, &tpm_ppi_guid, TPM_PPI_REVISION_ID,
|
||||
1 << TPM_PPI_FN_GETOPR))
|
||||
return -EPERM;
|
||||
|
||||
@ -341,12 +337,12 @@ void tpm_add_ppi(struct tpm_chip *chip)
|
||||
if (!chip->acpi_dev_handle)
|
||||
return;
|
||||
|
||||
if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
|
||||
if (!acpi_check_dsm(chip->acpi_dev_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
|
||||
return;
|
||||
|
||||
/* Cache PPI version string. */
|
||||
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
|
||||
obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, &tpm_ppi_guid,
|
||||
TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
|
||||
NULL, ACPI_TYPE_STRING);
|
||||
if (obj) {
|
||||
|
@ -2468,6 +2468,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||
if (!(cpufreq_driver->flags & CPUFREQ_STICKY) &&
|
||||
list_empty(&cpufreq_policy_list)) {
|
||||
/* if all ->init() calls failed, unregister */
|
||||
ret = -ENODEV;
|
||||
pr_debug("%s: No CPU initialized for driver %s\n", __func__,
|
||||
driver_data->name);
|
||||
goto err_if_unreg;
|
||||
|
@ -127,7 +127,12 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(priv.cpu_clk);
|
||||
}
|
||||
|
||||
clk_prepare_enable(priv.cpu_clk);
|
||||
err = clk_prepare_enable(priv.cpu_clk);
|
||||
if (err) {
|
||||
dev_err(priv.dev, "Unable to prepare cpuclk\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
kirkwood_freq_table[0].frequency = clk_get_rate(priv.cpu_clk) / 1000;
|
||||
|
||||
priv.ddr_clk = of_clk_get_by_name(np, "ddrclk");
|
||||
@ -137,7 +142,11 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
|
||||
goto out_cpu;
|
||||
}
|
||||
|
||||
clk_prepare_enable(priv.ddr_clk);
|
||||
err = clk_prepare_enable(priv.ddr_clk);
|
||||
if (err) {
|
||||
dev_err(priv.dev, "Unable to prepare ddrclk\n");
|
||||
goto out_cpu;
|
||||
}
|
||||
kirkwood_freq_table[1].frequency = clk_get_rate(priv.ddr_clk) / 1000;
|
||||
|
||||
priv.powersave_clk = of_clk_get_by_name(np, "powersave");
|
||||
@ -146,7 +155,11 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
|
||||
err = PTR_ERR(priv.powersave_clk);
|
||||
goto out_ddr;
|
||||
}
|
||||
clk_prepare_enable(priv.powersave_clk);
|
||||
err = clk_prepare_enable(priv.powersave_clk);
|
||||
if (err) {
|
||||
dev_err(priv.dev, "Unable to prepare powersave clk\n");
|
||||
goto out_ddr;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
np = NULL;
|
||||
|
@ -201,6 +201,7 @@ struct ep93xx_dma_engine {
|
||||
struct dma_device dma_dev;
|
||||
bool m2m;
|
||||
int (*hw_setup)(struct ep93xx_dma_chan *);
|
||||
void (*hw_synchronize)(struct ep93xx_dma_chan *);
|
||||
void (*hw_shutdown)(struct ep93xx_dma_chan *);
|
||||
void (*hw_submit)(struct ep93xx_dma_chan *);
|
||||
int (*hw_interrupt)(struct ep93xx_dma_chan *);
|
||||
@ -323,6 +324,8 @@ static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
|
||||
| M2P_CONTROL_ENABLE;
|
||||
m2p_set_control(edmac, control);
|
||||
|
||||
edmac->buffer = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -331,21 +334,27 @@ static inline u32 m2p_channel_state(struct ep93xx_dma_chan *edmac)
|
||||
return (readl(edmac->regs + M2P_STATUS) >> 4) & 0x3;
|
||||
}
|
||||
|
||||
static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
|
||||
static void m2p_hw_synchronize(struct ep93xx_dma_chan *edmac)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 control;
|
||||
|
||||
spin_lock_irqsave(&edmac->lock, flags);
|
||||
control = readl(edmac->regs + M2P_CONTROL);
|
||||
control &= ~(M2P_CONTROL_STALLINT | M2P_CONTROL_NFBINT);
|
||||
m2p_set_control(edmac, control);
|
||||
spin_unlock_irqrestore(&edmac->lock, flags);
|
||||
|
||||
while (m2p_channel_state(edmac) >= M2P_STATE_ON)
|
||||
cpu_relax();
|
||||
schedule();
|
||||
}
|
||||
|
||||
static void m2p_hw_shutdown(struct ep93xx_dma_chan *edmac)
|
||||
{
|
||||
m2p_set_control(edmac, 0);
|
||||
|
||||
while (m2p_channel_state(edmac) == M2P_STATE_STALL)
|
||||
cpu_relax();
|
||||
while (m2p_channel_state(edmac) != M2P_STATE_IDLE)
|
||||
dev_warn(chan2dev(edmac), "M2P: Not yet IDLE\n");
|
||||
}
|
||||
|
||||
static void m2p_fill_desc(struct ep93xx_dma_chan *edmac)
|
||||
@ -1160,6 +1169,26 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ep93xx_dma_synchronize - Synchronizes the termination of transfers to the
|
||||
* current context.
|
||||
* @chan: channel
|
||||
*
|
||||
* Synchronizes the DMA channel termination to the current context. When this
|
||||
* function returns it is guaranteed that all transfers for previously issued
|
||||
* descriptors have stopped and and it is safe to free the memory associated
|
||||
* with them. Furthermore it is guaranteed that all complete callback functions
|
||||
* for a previously submitted descriptor have finished running and it is safe to
|
||||
* free resources accessed from within the complete callbacks.
|
||||
*/
|
||||
static void ep93xx_dma_synchronize(struct dma_chan *chan)
|
||||
{
|
||||
struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
|
||||
|
||||
if (edmac->edma->hw_synchronize)
|
||||
edmac->edma->hw_synchronize(edmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* ep93xx_dma_terminate_all - terminate all transactions
|
||||
* @chan: channel
|
||||
@ -1323,6 +1352,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
|
||||
dma_dev->device_prep_slave_sg = ep93xx_dma_prep_slave_sg;
|
||||
dma_dev->device_prep_dma_cyclic = ep93xx_dma_prep_dma_cyclic;
|
||||
dma_dev->device_config = ep93xx_dma_slave_config;
|
||||
dma_dev->device_synchronize = ep93xx_dma_synchronize;
|
||||
dma_dev->device_terminate_all = ep93xx_dma_terminate_all;
|
||||
dma_dev->device_issue_pending = ep93xx_dma_issue_pending;
|
||||
dma_dev->device_tx_status = ep93xx_dma_tx_status;
|
||||
@ -1340,6 +1370,7 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
|
||||
} else {
|
||||
dma_cap_set(DMA_PRIVATE, dma_dev->cap_mask);
|
||||
|
||||
edma->hw_synchronize = m2p_hw_synchronize;
|
||||
edma->hw_setup = m2p_hw_setup;
|
||||
edma->hw_shutdown = m2p_hw_shutdown;
|
||||
edma->hw_submit = m2p_hw_submit;
|
||||
|
@ -161,6 +161,7 @@ struct mv_xor_v2_device {
|
||||
struct mv_xor_v2_sw_desc *sw_desq;
|
||||
int desc_size;
|
||||
unsigned int npendings;
|
||||
unsigned int hw_queue_idx;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -213,18 +214,6 @@ static void mv_xor_v2_set_data_buffers(struct mv_xor_v2_device *xor_dev,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next available index in the DESQ.
|
||||
*/
|
||||
static int mv_xor_v2_get_desq_write_ptr(struct mv_xor_v2_device *xor_dev)
|
||||
{
|
||||
/* read the index for the next available descriptor in the DESQ */
|
||||
u32 reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_ALLOC_OFF);
|
||||
|
||||
return ((reg >> MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_SHIFT)
|
||||
& MV_XOR_V2_DMA_DESQ_ALLOC_WRPTR_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* notify the engine of new descriptors, and update the available index.
|
||||
*/
|
||||
@ -257,22 +246,6 @@ static int mv_xor_v2_set_desc_size(struct mv_xor_v2_device *xor_dev)
|
||||
return MV_XOR_V2_EXT_DESC_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the IMSG threshold
|
||||
*/
|
||||
static inline
|
||||
void mv_xor_v2_set_imsg_thrd(struct mv_xor_v2_device *xor_dev, int thrd_val)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl(xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
|
||||
|
||||
reg &= (~MV_XOR_V2_DMA_IMSG_THRD_MASK << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
|
||||
reg |= (thrd_val << MV_XOR_V2_DMA_IMSG_THRD_SHIFT);
|
||||
|
||||
writel(reg, xor_dev->dma_base + MV_XOR_V2_DMA_IMSG_THRD_OFF);
|
||||
}
|
||||
|
||||
static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data)
|
||||
{
|
||||
struct mv_xor_v2_device *xor_dev = data;
|
||||
@ -288,12 +261,6 @@ static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data)
|
||||
if (!ndescs)
|
||||
return IRQ_NONE;
|
||||
|
||||
/*
|
||||
* Update IMSG threshold, to disable new IMSG interrupts until
|
||||
* end of the tasklet
|
||||
*/
|
||||
mv_xor_v2_set_imsg_thrd(xor_dev, MV_XOR_V2_DESC_NUM);
|
||||
|
||||
/* schedule a tasklet to handle descriptors callbacks */
|
||||
tasklet_schedule(&xor_dev->irq_tasklet);
|
||||
|
||||
@ -306,7 +273,6 @@ static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data)
|
||||
static dma_cookie_t
|
||||
mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx)
|
||||
{
|
||||
int desq_ptr;
|
||||
void *dest_hw_desc;
|
||||
dma_cookie_t cookie;
|
||||
struct mv_xor_v2_sw_desc *sw_desc =
|
||||
@ -322,15 +288,15 @@ mv_xor_v2_tx_submit(struct dma_async_tx_descriptor *tx)
|
||||
spin_lock_bh(&xor_dev->lock);
|
||||
cookie = dma_cookie_assign(tx);
|
||||
|
||||
/* get the next available slot in the DESQ */
|
||||
desq_ptr = mv_xor_v2_get_desq_write_ptr(xor_dev);
|
||||
|
||||
/* copy the HW descriptor from the SW descriptor to the DESQ */
|
||||
dest_hw_desc = xor_dev->hw_desq_virt + desq_ptr;
|
||||
dest_hw_desc = xor_dev->hw_desq_virt + xor_dev->hw_queue_idx;
|
||||
|
||||
memcpy(dest_hw_desc, &sw_desc->hw_desc, xor_dev->desc_size);
|
||||
|
||||
xor_dev->npendings++;
|
||||
xor_dev->hw_queue_idx++;
|
||||
if (xor_dev->hw_queue_idx >= MV_XOR_V2_DESC_NUM)
|
||||
xor_dev->hw_queue_idx = 0;
|
||||
|
||||
spin_unlock_bh(&xor_dev->lock);
|
||||
|
||||
@ -344,6 +310,7 @@ static struct mv_xor_v2_sw_desc *
|
||||
mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev)
|
||||
{
|
||||
struct mv_xor_v2_sw_desc *sw_desc;
|
||||
bool found = false;
|
||||
|
||||
/* Lock the channel */
|
||||
spin_lock_bh(&xor_dev->lock);
|
||||
@ -355,19 +322,23 @@ mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get a free SW descriptor from the SW DESQ */
|
||||
sw_desc = list_first_entry(&xor_dev->free_sw_desc,
|
||||
struct mv_xor_v2_sw_desc, free_list);
|
||||
list_for_each_entry(sw_desc, &xor_dev->free_sw_desc, free_list) {
|
||||
if (async_tx_test_ack(&sw_desc->async_tx)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
spin_unlock_bh(&xor_dev->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_del(&sw_desc->free_list);
|
||||
|
||||
/* Release the channel */
|
||||
spin_unlock_bh(&xor_dev->lock);
|
||||
|
||||
/* set the async tx descriptor */
|
||||
dma_async_tx_descriptor_init(&sw_desc->async_tx, &xor_dev->dmachan);
|
||||
sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
|
||||
async_tx_ack(&sw_desc->async_tx);
|
||||
|
||||
return sw_desc;
|
||||
}
|
||||
|
||||
@ -389,6 +360,8 @@ mv_xor_v2_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
|
||||
__func__, len, &src, &dest, flags);
|
||||
|
||||
sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
|
||||
if (!sw_desc)
|
||||
return NULL;
|
||||
|
||||
sw_desc->async_tx.flags = flags;
|
||||
|
||||
@ -443,6 +416,8 @@ mv_xor_v2_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
|
||||
__func__, src_cnt, len, &dest, flags);
|
||||
|
||||
sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
|
||||
if (!sw_desc)
|
||||
return NULL;
|
||||
|
||||
sw_desc->async_tx.flags = flags;
|
||||
|
||||
@ -491,6 +466,8 @@ mv_xor_v2_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags)
|
||||
container_of(chan, struct mv_xor_v2_device, dmachan);
|
||||
|
||||
sw_desc = mv_xor_v2_prep_sw_desc(xor_dev);
|
||||
if (!sw_desc)
|
||||
return NULL;
|
||||
|
||||
/* set the HW descriptor */
|
||||
hw_descriptor = &sw_desc->hw_desc;
|
||||
@ -554,7 +531,6 @@ static void mv_xor_v2_tasklet(unsigned long data)
|
||||
{
|
||||
struct mv_xor_v2_device *xor_dev = (struct mv_xor_v2_device *) data;
|
||||
int pending_ptr, num_of_pending, i;
|
||||
struct mv_xor_v2_descriptor *next_pending_hw_desc = NULL;
|
||||
struct mv_xor_v2_sw_desc *next_pending_sw_desc = NULL;
|
||||
|
||||
dev_dbg(xor_dev->dmadev.dev, "%s %d\n", __func__, __LINE__);
|
||||
@ -562,17 +538,10 @@ static void mv_xor_v2_tasklet(unsigned long data)
|
||||
/* get the pending descriptors parameters */
|
||||
num_of_pending = mv_xor_v2_get_pending_params(xor_dev, &pending_ptr);
|
||||
|
||||
/* next HW descriptor */
|
||||
next_pending_hw_desc = xor_dev->hw_desq_virt + pending_ptr;
|
||||
|
||||
/* loop over free descriptors */
|
||||
for (i = 0; i < num_of_pending; i++) {
|
||||
|
||||
if (pending_ptr > MV_XOR_V2_DESC_NUM)
|
||||
pending_ptr = 0;
|
||||
|
||||
if (next_pending_sw_desc != NULL)
|
||||
next_pending_hw_desc++;
|
||||
struct mv_xor_v2_descriptor *next_pending_hw_desc =
|
||||
xor_dev->hw_desq_virt + pending_ptr;
|
||||
|
||||
/* get the SW descriptor related to the HW descriptor */
|
||||
next_pending_sw_desc =
|
||||
@ -608,15 +577,14 @@ static void mv_xor_v2_tasklet(unsigned long data)
|
||||
|
||||
/* increment the next descriptor */
|
||||
pending_ptr++;
|
||||
if (pending_ptr >= MV_XOR_V2_DESC_NUM)
|
||||
pending_ptr = 0;
|
||||
}
|
||||
|
||||
if (num_of_pending != 0) {
|
||||
/* free the descriptores */
|
||||
mv_xor_v2_free_desc_from_desq(xor_dev, num_of_pending);
|
||||
}
|
||||
|
||||
/* Update IMSG threshold, to enable new IMSG interrupts */
|
||||
mv_xor_v2_set_imsg_thrd(xor_dev, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -648,9 +616,6 @@ static int mv_xor_v2_descq_init(struct mv_xor_v2_device *xor_dev)
|
||||
writel((xor_dev->hw_desq & 0xFFFF00000000) >> 32,
|
||||
xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_BAHR_OFF);
|
||||
|
||||
/* enable the DMA engine */
|
||||
writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
|
||||
|
||||
/*
|
||||
* This is a temporary solution, until we activate the
|
||||
* SMMU. Set the attributes for reading & writing data buffers
|
||||
@ -694,6 +659,9 @@ static int mv_xor_v2_descq_init(struct mv_xor_v2_device *xor_dev)
|
||||
reg |= MV_XOR_V2_GLOB_PAUSE_AXI_TIME_DIS_VAL;
|
||||
writel(reg, xor_dev->glob_base + MV_XOR_V2_GLOB_PAUSE);
|
||||
|
||||
/* enable the DMA engine */
|
||||
writel(0, xor_dev->dma_base + MV_XOR_V2_DMA_DESQ_STOP_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -725,6 +693,10 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, xor_dev);
|
||||
|
||||
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
@ -785,8 +757,15 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
|
||||
|
||||
/* add all SW descriptors to the free list */
|
||||
for (i = 0; i < MV_XOR_V2_DESC_NUM; i++) {
|
||||
xor_dev->sw_desq[i].idx = i;
|
||||
list_add(&xor_dev->sw_desq[i].free_list,
|
||||
struct mv_xor_v2_sw_desc *sw_desc =
|
||||
xor_dev->sw_desq + i;
|
||||
sw_desc->idx = i;
|
||||
dma_async_tx_descriptor_init(&sw_desc->async_tx,
|
||||
&xor_dev->dmachan);
|
||||
sw_desc->async_tx.tx_submit = mv_xor_v2_tx_submit;
|
||||
async_tx_ack(&sw_desc->async_tx);
|
||||
|
||||
list_add(&sw_desc->free_list,
|
||||
&xor_dev->free_sw_desc);
|
||||
}
|
||||
|
||||
|
@ -3008,7 +3008,8 @@ static int pl330_remove(struct amba_device *adev)
|
||||
|
||||
for (i = 0; i < AMBA_NR_IRQS; i++) {
|
||||
irq = adev->irq[i];
|
||||
devm_free_irq(&adev->dev, irq, pl330);
|
||||
if (irq)
|
||||
devm_free_irq(&adev->dev, irq, pl330);
|
||||
}
|
||||
|
||||
dma_async_device_unregister(&pl330->ddma);
|
||||
|
@ -1287,6 +1287,9 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
|
||||
if (desc->hwdescs.use) {
|
||||
dptr = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
|
||||
RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT;
|
||||
if (dptr == 0)
|
||||
dptr = desc->nchunks;
|
||||
dptr--;
|
||||
WARN_ON(dptr >= desc->nchunks);
|
||||
} else {
|
||||
running = desc->running;
|
||||
|
@ -117,7 +117,7 @@ struct usb_dmac {
|
||||
#define USB_DMASWR 0x0008
|
||||
#define USB_DMASWR_SWR (1 << 0)
|
||||
#define USB_DMAOR 0x0060
|
||||
#define USB_DMAOR_AE (1 << 2)
|
||||
#define USB_DMAOR_AE (1 << 1)
|
||||
#define USB_DMAOR_DME (1 << 0)
|
||||
|
||||
#define USB_DMASAR 0x0000
|
||||
|
@ -47,6 +47,7 @@ DEFINE_DMI_ATTR_WITH_SHOW(product_name, 0444, DMI_PRODUCT_NAME);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_version, 0444, DMI_PRODUCT_VERSION);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_serial, 0400, DMI_PRODUCT_SERIAL);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_uuid, 0400, DMI_PRODUCT_UUID);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(product_family, 0400, DMI_PRODUCT_FAMILY);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_vendor, 0444, DMI_BOARD_VENDOR);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_name, 0444, DMI_BOARD_NAME);
|
||||
DEFINE_DMI_ATTR_WITH_SHOW(board_version, 0444, DMI_BOARD_VERSION);
|
||||
@ -191,6 +192,7 @@ static void __init dmi_id_init_attr_table(void)
|
||||
ADD_DMI_ATTR(product_version, DMI_PRODUCT_VERSION);
|
||||
ADD_DMI_ATTR(product_serial, DMI_PRODUCT_SERIAL);
|
||||
ADD_DMI_ATTR(product_uuid, DMI_PRODUCT_UUID);
|
||||
ADD_DMI_ATTR(product_family, DMI_PRODUCT_FAMILY);
|
||||
ADD_DMI_ATTR(board_vendor, DMI_BOARD_VENDOR);
|
||||
ADD_DMI_ATTR(board_name, DMI_BOARD_NAME);
|
||||
ADD_DMI_ATTR(board_version, DMI_BOARD_VERSION);
|
||||
|
@ -430,6 +430,7 @@ static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
|
||||
dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
|
||||
dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
|
||||
dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
|
||||
dmi_save_ident(dm, DMI_PRODUCT_FAMILY, 26);
|
||||
break;
|
||||
case 2: /* Base Board Information */
|
||||
dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
|
||||
|
@ -32,6 +32,10 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/aer.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <acpi/ghes.h>
|
||||
#include <ras/ras_event.h>
|
||||
|
||||
#define INDENT_SP " "
|
||||
|
||||
@ -107,12 +111,15 @@ void cper_print_bits(const char *pfx, unsigned int bits,
|
||||
static const char * const proc_type_strs[] = {
|
||||
"IA32/X64",
|
||||
"IA64",
|
||||
"ARM",
|
||||
};
|
||||
|
||||
static const char * const proc_isa_strs[] = {
|
||||
"IA32",
|
||||
"IA64",
|
||||
"X64",
|
||||
"ARM A32/T32",
|
||||
"ARM A64",
|
||||
};
|
||||
|
||||
static const char * const proc_error_type_strs[] = {
|
||||
@ -181,6 +188,122 @@ static void cper_print_proc_generic(const char *pfx,
|
||||
printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
|
||||
static const char * const arm_reg_ctx_strs[] = {
|
||||
"AArch32 general purpose registers",
|
||||
"AArch32 EL1 context registers",
|
||||
"AArch32 EL2 context registers",
|
||||
"AArch32 secure context registers",
|
||||
"AArch64 general purpose registers",
|
||||
"AArch64 EL1 context registers",
|
||||
"AArch64 EL2 context registers",
|
||||
"AArch64 EL3 context registers",
|
||||
"Misc. system register structure",
|
||||
};
|
||||
|
||||
static void cper_print_proc_arm(const char *pfx,
|
||||
const struct cper_sec_proc_arm *proc)
|
||||
{
|
||||
int i, len, max_ctx_type;
|
||||
struct cper_arm_err_info *err_info;
|
||||
struct cper_arm_ctx_info *ctx_info;
|
||||
char newpfx[64];
|
||||
|
||||
printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
|
||||
|
||||
len = proc->section_length - (sizeof(*proc) +
|
||||
proc->err_info_num * (sizeof(*err_info)));
|
||||
if (len < 0) {
|
||||
printk("%ssection length: %d\n", pfx, proc->section_length);
|
||||
printk("%ssection length is too small\n", pfx);
|
||||
printk("%sfirmware-generated error record is incorrect\n", pfx);
|
||||
printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
|
||||
return;
|
||||
}
|
||||
|
||||
if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
|
||||
printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
|
||||
pfx, proc->mpidr);
|
||||
|
||||
if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
|
||||
printk("%serror affinity level: %d\n", pfx,
|
||||
proc->affinity_level);
|
||||
|
||||
if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
|
||||
printk("%srunning state: 0x%x\n", pfx, proc->running_state);
|
||||
printk("%sPower State Coordination Interface state: %d\n",
|
||||
pfx, proc->psci_state);
|
||||
}
|
||||
|
||||
snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
|
||||
|
||||
err_info = (struct cper_arm_err_info *)(proc + 1);
|
||||
for (i = 0; i < proc->err_info_num; i++) {
|
||||
printk("%sError info structure %d:\n", pfx, i);
|
||||
|
||||
printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
|
||||
|
||||
if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
|
||||
if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
|
||||
printk("%sfirst error captured\n", newpfx);
|
||||
if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
|
||||
printk("%slast error captured\n", newpfx);
|
||||
if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
|
||||
printk("%spropagated error captured\n",
|
||||
newpfx);
|
||||
if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
|
||||
printk("%soverflow occurred, error info is incomplete\n",
|
||||
newpfx);
|
||||
}
|
||||
|
||||
printk("%serror_type: %d, %s\n", newpfx, err_info->type,
|
||||
err_info->type < ARRAY_SIZE(proc_error_type_strs) ?
|
||||
proc_error_type_strs[err_info->type] : "unknown");
|
||||
if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO)
|
||||
printk("%serror_info: 0x%016llx\n", newpfx,
|
||||
err_info->error_info);
|
||||
if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
|
||||
printk("%svirtual fault address: 0x%016llx\n",
|
||||
newpfx, err_info->virt_fault_addr);
|
||||
if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
|
||||
printk("%sphysical fault address: 0x%016llx\n",
|
||||
newpfx, err_info->physical_fault_addr);
|
||||
err_info += 1;
|
||||
}
|
||||
|
||||
ctx_info = (struct cper_arm_ctx_info *)err_info;
|
||||
max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
|
||||
for (i = 0; i < proc->context_info_num; i++) {
|
||||
int size = sizeof(*ctx_info) + ctx_info->size;
|
||||
|
||||
printk("%sContext info structure %d:\n", pfx, i);
|
||||
if (len < size) {
|
||||
printk("%ssection length is too small\n", newpfx);
|
||||
printk("%sfirmware-generated error record is incorrect\n", pfx);
|
||||
return;
|
||||
}
|
||||
if (ctx_info->type > max_ctx_type) {
|
||||
printk("%sInvalid context type: %d (max: %d)\n",
|
||||
newpfx, ctx_info->type, max_ctx_type);
|
||||
return;
|
||||
}
|
||||
printk("%sregister context type: %s\n", newpfx,
|
||||
arm_reg_ctx_strs[ctx_info->type]);
|
||||
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
|
||||
(ctx_info + 1), ctx_info->size, 0);
|
||||
len -= size;
|
||||
ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
printk("%sVendor specific error info has %u bytes:\n", pfx,
|
||||
len);
|
||||
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
|
||||
len, true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char * const mem_err_type_strs[] = {
|
||||
"unknown",
|
||||
"no error",
|
||||
@ -386,13 +509,38 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
|
||||
pfx, pcie->bridge.secondary_status, pcie->bridge.control);
|
||||
}
|
||||
|
||||
static void cper_estatus_print_section(
|
||||
const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no)
|
||||
static void cper_print_tstamp(const char *pfx,
|
||||
struct acpi_hest_generic_data_v300 *gdata)
|
||||
{
|
||||
__u8 hour, min, sec, day, mon, year, century, *timestamp;
|
||||
|
||||
if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
|
||||
timestamp = (__u8 *)&(gdata->time_stamp);
|
||||
sec = bcd2bin(timestamp[0]);
|
||||
min = bcd2bin(timestamp[1]);
|
||||
hour = bcd2bin(timestamp[2]);
|
||||
day = bcd2bin(timestamp[4]);
|
||||
mon = bcd2bin(timestamp[5]);
|
||||
year = bcd2bin(timestamp[6]);
|
||||
century = bcd2bin(timestamp[7]);
|
||||
|
||||
printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
|
||||
(timestamp[3] & 0x1 ? "precise " : "imprecise "),
|
||||
century, year, mon, day, hour, min, sec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
|
||||
int sec_no)
|
||||
{
|
||||
uuid_le *sec_type = (uuid_le *)gdata->section_type;
|
||||
__u16 severity;
|
||||
char newpfx[64];
|
||||
|
||||
if (acpi_hest_get_version(gdata) >= 3)
|
||||
cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
|
||||
|
||||
severity = gdata->error_severity;
|
||||
printk("%s""Error %d, type: %s\n", pfx, sec_no,
|
||||
cper_severity_str(severity));
|
||||
@ -403,14 +551,16 @@ static void cper_estatus_print_section(
|
||||
|
||||
snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
|
||||
if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
|
||||
struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
|
||||
struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
printk("%s""section_type: general processor error\n", newpfx);
|
||||
if (gdata->error_data_length >= sizeof(*proc_err))
|
||||
cper_print_proc_generic(newpfx, proc_err);
|
||||
else
|
||||
goto err_section_too_small;
|
||||
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
|
||||
struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
|
||||
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
printk("%s""section_type: memory error\n", newpfx);
|
||||
if (gdata->error_data_length >=
|
||||
sizeof(struct cper_sec_mem_err_old))
|
||||
@ -419,14 +569,32 @@ static void cper_estatus_print_section(
|
||||
else
|
||||
goto err_section_too_small;
|
||||
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
|
||||
struct cper_sec_pcie *pcie = (void *)(gdata + 1);
|
||||
struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
|
||||
|
||||
printk("%s""section_type: PCIe error\n", newpfx);
|
||||
if (gdata->error_data_length >= sizeof(*pcie))
|
||||
cper_print_pcie(newpfx, pcie, gdata);
|
||||
else
|
||||
goto err_section_too_small;
|
||||
} else
|
||||
printk("%s""section type: unknown, %pUl\n", newpfx, sec_type);
|
||||
#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
|
||||
} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
|
||||
struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
|
||||
|
||||
printk("%ssection_type: ARM processor error\n", newpfx);
|
||||
if (gdata->error_data_length >= sizeof(*arm_err))
|
||||
cper_print_proc_arm(newpfx, arm_err);
|
||||
else
|
||||
goto err_section_too_small;
|
||||
#endif
|
||||
} else {
|
||||
const void *err = acpi_hest_get_payload(gdata);
|
||||
|
||||
printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
|
||||
printk("%ssection length: %#x\n", newpfx,
|
||||
gdata->error_data_length);
|
||||
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
|
||||
gdata->error_data_length, true);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@ -438,7 +606,7 @@ void cper_estatus_print(const char *pfx,
|
||||
const struct acpi_hest_generic_status *estatus)
|
||||
{
|
||||
struct acpi_hest_generic_data *gdata;
|
||||
unsigned int data_len, gedata_len;
|
||||
unsigned int data_len;
|
||||
int sec_no = 0;
|
||||
char newpfx[64];
|
||||
__u16 severity;
|
||||
@ -452,11 +620,11 @@ void cper_estatus_print(const char *pfx,
|
||||
data_len = estatus->data_length;
|
||||
gdata = (struct acpi_hest_generic_data *)(estatus + 1);
|
||||
snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
|
||||
while (data_len >= sizeof(*gdata)) {
|
||||
gedata_len = gdata->error_data_length;
|
||||
|
||||
while (data_len >= acpi_hest_get_size(gdata)) {
|
||||
cper_estatus_print_section(newpfx, gdata, sec_no);
|
||||
data_len -= gedata_len + sizeof(*gdata);
|
||||
gdata = (void *)(gdata + 1) + gedata_len;
|
||||
data_len -= acpi_hest_get_record_size(gdata);
|
||||
gdata = acpi_hest_get_next(gdata);
|
||||
sec_no++;
|
||||
}
|
||||
}
|
||||
@ -486,12 +654,14 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
|
||||
return rc;
|
||||
data_len = estatus->data_length;
|
||||
gdata = (struct acpi_hest_generic_data *)(estatus + 1);
|
||||
while (data_len >= sizeof(*gdata)) {
|
||||
gedata_len = gdata->error_data_length;
|
||||
if (gedata_len > data_len - sizeof(*gdata))
|
||||
|
||||
while (data_len >= acpi_hest_get_size(gdata)) {
|
||||
gedata_len = acpi_hest_get_error_length(gdata);
|
||||
if (gedata_len > data_len - acpi_hest_get_size(gdata))
|
||||
return -EINVAL;
|
||||
data_len -= gedata_len + sizeof(*gdata);
|
||||
gdata = (void *)(gdata + 1) + gedata_len;
|
||||
|
||||
data_len -= acpi_hest_get_record_size(gdata);
|
||||
gdata = acpi_hest_get_next(gdata);
|
||||
}
|
||||
if (data_len)
|
||||
return -EINVAL;
|
||||
|
@ -36,6 +36,9 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
if (!efi_enabled(EFI_BOOT))
|
||||
return;
|
||||
|
||||
if (table->length < sizeof(bgrt_tab)) {
|
||||
pr_notice("Ignoring BGRT: invalid length %u (expected %zu)\n",
|
||||
table->length, sizeof(bgrt_tab));
|
||||
|
@ -16,10 +16,10 @@
|
||||
|
||||
/* BIOS variables */
|
||||
static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
|
||||
static const efi_char16_t const efi_SecureBoot_name[] = {
|
||||
static const efi_char16_t efi_SecureBoot_name[] = {
|
||||
'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0
|
||||
};
|
||||
static const efi_char16_t const efi_SetupMode_name[] = {
|
||||
static const efi_char16_t efi_SetupMode_name[] = {
|
||||
'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0
|
||||
};
|
||||
|
||||
|
@ -220,9 +220,9 @@ static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
|
||||
}
|
||||
|
||||
const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = {
|
||||
amdgpu_vram_mgr_init,
|
||||
amdgpu_vram_mgr_fini,
|
||||
amdgpu_vram_mgr_new,
|
||||
amdgpu_vram_mgr_del,
|
||||
amdgpu_vram_mgr_debug
|
||||
.init = amdgpu_vram_mgr_init,
|
||||
.takedown = amdgpu_vram_mgr_fini,
|
||||
.get_node = amdgpu_vram_mgr_new,
|
||||
.put_node = amdgpu_vram_mgr_del,
|
||||
.debug = amdgpu_vram_mgr_debug
|
||||
};
|
||||
|
@ -77,13 +77,26 @@ static int vce_v3_0_set_clockgating_state(void *handle,
|
||||
static uint64_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 v;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
if (adev->vce.harvest_config == 0 ||
|
||||
adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE1)
|
||||
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
|
||||
else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0)
|
||||
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1));
|
||||
|
||||
if (ring == &adev->vce.ring[0])
|
||||
return RREG32(mmVCE_RB_RPTR);
|
||||
v = RREG32(mmVCE_RB_RPTR);
|
||||
else if (ring == &adev->vce.ring[1])
|
||||
return RREG32(mmVCE_RB_RPTR2);
|
||||
v = RREG32(mmVCE_RB_RPTR2);
|
||||
else
|
||||
return RREG32(mmVCE_RB_RPTR3);
|
||||
v = RREG32(mmVCE_RB_RPTR3);
|
||||
|
||||
WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,13 +109,26 @@ static uint64_t vce_v3_0_ring_get_rptr(struct amdgpu_ring *ring)
|
||||
static uint64_t vce_v3_0_ring_get_wptr(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
u32 v;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
if (adev->vce.harvest_config == 0 ||
|
||||
adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE1)
|
||||
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
|
||||
else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0)
|
||||
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1));
|
||||
|
||||
if (ring == &adev->vce.ring[0])
|
||||
return RREG32(mmVCE_RB_WPTR);
|
||||
v = RREG32(mmVCE_RB_WPTR);
|
||||
else if (ring == &adev->vce.ring[1])
|
||||
return RREG32(mmVCE_RB_WPTR2);
|
||||
v = RREG32(mmVCE_RB_WPTR2);
|
||||
else
|
||||
return RREG32(mmVCE_RB_WPTR3);
|
||||
v = RREG32(mmVCE_RB_WPTR3);
|
||||
|
||||
WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,12 +142,22 @@ static void vce_v3_0_ring_set_wptr(struct amdgpu_ring *ring)
|
||||
{
|
||||
struct amdgpu_device *adev = ring->adev;
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
if (adev->vce.harvest_config == 0 ||
|
||||
adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE1)
|
||||
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
|
||||
else if (adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0)
|
||||
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1));
|
||||
|
||||
if (ring == &adev->vce.ring[0])
|
||||
WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
|
||||
else if (ring == &adev->vce.ring[1])
|
||||
WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr));
|
||||
else
|
||||
WREG32(mmVCE_RB_WPTR3, lower_32_bits(ring->wptr));
|
||||
|
||||
WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
|
||||
mutex_unlock(&adev->grbm_idx_mutex);
|
||||
}
|
||||
|
||||
static void vce_v3_0_override_vce_clock_gating(struct amdgpu_device *adev, bool override)
|
||||
@ -231,33 +267,38 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
|
||||
struct amdgpu_ring *ring;
|
||||
int idx, r;
|
||||
|
||||
ring = &adev->vce.ring[0];
|
||||
WREG32(mmVCE_RB_RPTR, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
|
||||
WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
|
||||
WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
|
||||
|
||||
ring = &adev->vce.ring[1];
|
||||
WREG32(mmVCE_RB_RPTR2, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
|
||||
WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
|
||||
WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
|
||||
|
||||
ring = &adev->vce.ring[2];
|
||||
WREG32(mmVCE_RB_RPTR3, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_WPTR3, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr);
|
||||
WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr));
|
||||
WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4);
|
||||
|
||||
mutex_lock(&adev->grbm_idx_mutex);
|
||||
for (idx = 0; idx < 2; ++idx) {
|
||||
if (adev->vce.harvest_config & (1 << idx))
|
||||
continue;
|
||||
|
||||
WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx));
|
||||
|
||||
/* Program instance 0 reg space for two instances or instance 0 case
|
||||
program instance 1 reg space for only instance 1 available case */
|
||||
if (idx != 1 || adev->vce.harvest_config == AMDGPU_VCE_HARVEST_VCE0) {
|
||||
ring = &adev->vce.ring[0];
|
||||
WREG32(mmVCE_RB_RPTR, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_WPTR, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_BASE_LO, ring->gpu_addr);
|
||||
WREG32(mmVCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
|
||||
WREG32(mmVCE_RB_SIZE, ring->ring_size / 4);
|
||||
|
||||
ring = &adev->vce.ring[1];
|
||||
WREG32(mmVCE_RB_RPTR2, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_WPTR2, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_BASE_LO2, ring->gpu_addr);
|
||||
WREG32(mmVCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
|
||||
WREG32(mmVCE_RB_SIZE2, ring->ring_size / 4);
|
||||
|
||||
ring = &adev->vce.ring[2];
|
||||
WREG32(mmVCE_RB_RPTR3, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_WPTR3, lower_32_bits(ring->wptr));
|
||||
WREG32(mmVCE_RB_BASE_LO3, ring->gpu_addr);
|
||||
WREG32(mmVCE_RB_BASE_HI3, upper_32_bits(ring->gpu_addr));
|
||||
WREG32(mmVCE_RB_SIZE3, ring->ring_size / 4);
|
||||
}
|
||||
|
||||
vce_v3_0_mc_resume(adev, idx);
|
||||
WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1);
|
||||
|
||||
|
@ -709,17 +709,17 @@ static int tf_vega10_thermal_disable_alert(struct pp_hwmgr *hwmgr,
|
||||
|
||||
static struct phm_master_table_item
|
||||
vega10_thermal_start_thermal_controller_master_list[] = {
|
||||
{NULL, tf_vega10_thermal_initialize},
|
||||
{NULL, tf_vega10_thermal_set_temperature_range},
|
||||
{NULL, tf_vega10_thermal_enable_alert},
|
||||
{ .tableFunction = tf_vega10_thermal_initialize },
|
||||
{ .tableFunction = tf_vega10_thermal_set_temperature_range },
|
||||
{ .tableFunction = tf_vega10_thermal_enable_alert },
|
||||
/* We should restrict performance levels to low before we halt the SMC.
|
||||
* On the other hand we are still in boot state when we do this
|
||||
* so it would be pointless.
|
||||
* If this assumption changes we have to revisit this table.
|
||||
*/
|
||||
{NULL, tf_vega10_thermal_setup_fan_table},
|
||||
{NULL, tf_vega10_thermal_start_smc_fan_control},
|
||||
{NULL, NULL}
|
||||
{ .tableFunction = tf_vega10_thermal_setup_fan_table },
|
||||
{ .tableFunction = tf_vega10_thermal_start_smc_fan_control },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct phm_master_table_header
|
||||
@ -731,10 +731,10 @@ vega10_thermal_start_thermal_controller_master = {
|
||||
|
||||
static struct phm_master_table_item
|
||||
vega10_thermal_set_temperature_range_master_list[] = {
|
||||
{NULL, tf_vega10_thermal_disable_alert},
|
||||
{NULL, tf_vega10_thermal_set_temperature_range},
|
||||
{NULL, tf_vega10_thermal_enable_alert},
|
||||
{NULL, NULL}
|
||||
{ .tableFunction = tf_vega10_thermal_disable_alert },
|
||||
{ .tableFunction = tf_vega10_thermal_set_temperature_range },
|
||||
{ .tableFunction = tf_vega10_thermal_enable_alert },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct phm_master_table_header
|
||||
|
@ -1208,3 +1208,86 @@ int drm_dp_stop_crc(struct drm_dp_aux *aux)
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_stop_crc);
|
||||
|
||||
struct dpcd_quirk {
|
||||
u8 oui[3];
|
||||
bool is_branch;
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
#define OUI(first, second, third) { (first), (second), (third) }
|
||||
|
||||
static const struct dpcd_quirk dpcd_quirk_list[] = {
|
||||
/* Analogix 7737 needs reduced M and N at HBR2 link rates */
|
||||
{ OUI(0x00, 0x22, 0xb9), true, BIT(DP_DPCD_QUIRK_LIMITED_M_N) },
|
||||
};
|
||||
|
||||
#undef OUI
|
||||
|
||||
/*
|
||||
* Get a bit mask of DPCD quirks for the sink/branch device identified by
|
||||
* ident. The quirk data is shared but it's up to the drivers to act on the
|
||||
* data.
|
||||
*
|
||||
* For now, only the OUI (first three bytes) is used, but this may be extended
|
||||
* to device identification string and hardware/firmware revisions later.
|
||||
*/
|
||||
static u32
|
||||
drm_dp_get_quirks(const struct drm_dp_dpcd_ident *ident, bool is_branch)
|
||||
{
|
||||
const struct dpcd_quirk *quirk;
|
||||
u32 quirks = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dpcd_quirk_list); i++) {
|
||||
quirk = &dpcd_quirk_list[i];
|
||||
|
||||
if (quirk->is_branch != is_branch)
|
||||
continue;
|
||||
|
||||
if (memcmp(quirk->oui, ident->oui, sizeof(ident->oui)) != 0)
|
||||
continue;
|
||||
|
||||
quirks |= quirk->quirks;
|
||||
}
|
||||
|
||||
return quirks;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_dp_read_desc - read sink/branch descriptor from DPCD
|
||||
* @aux: DisplayPort AUX channel
|
||||
* @desc: Device decriptor to fill from DPCD
|
||||
* @is_branch: true for branch devices, false for sink devices
|
||||
*
|
||||
* Read DPCD 0x400 (sink) or 0x500 (branch) into @desc. Also debug log the
|
||||
* identification.
|
||||
*
|
||||
* Returns 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc,
|
||||
bool is_branch)
|
||||
{
|
||||
struct drm_dp_dpcd_ident *ident = &desc->ident;
|
||||
unsigned int offset = is_branch ? DP_BRANCH_OUI : DP_SINK_OUI;
|
||||
int ret, dev_id_len;
|
||||
|
||||
ret = drm_dp_dpcd_read(aux, offset, ident, sizeof(*ident));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
desc->quirks = drm_dp_get_quirks(ident, is_branch);
|
||||
|
||||
dev_id_len = strnlen(ident->device_id, sizeof(ident->device_id));
|
||||
|
||||
DRM_DEBUG_KMS("DP %s: OUI %*phD dev-ID %*pE HW-rev %d.%d SW-rev %d.%d quirks 0x%04x\n",
|
||||
is_branch ? "branch" : "sink",
|
||||
(int)sizeof(ident->oui), ident->oui,
|
||||
dev_id_len, ident->device_id,
|
||||
ident->hw_rev >> 4, ident->hw_rev & 0xf,
|
||||
ident->sw_major_rev, ident->sw_minor_rev,
|
||||
desc->quirks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_read_desc);
|
||||
|
@ -82,14 +82,9 @@ err_file_priv_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exynos_drm_preclose(struct drm_device *dev,
|
||||
struct drm_file *file)
|
||||
{
|
||||
exynos_drm_subdrv_close(dev, file);
|
||||
}
|
||||
|
||||
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
exynos_drm_subdrv_close(dev, file);
|
||||
kfree(file->driver_priv);
|
||||
file->driver_priv = NULL;
|
||||
}
|
||||
@ -145,7 +140,6 @@ static struct drm_driver exynos_drm_driver = {
|
||||
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
|
||||
| DRIVER_ATOMIC | DRIVER_RENDER,
|
||||
.open = exynos_drm_open,
|
||||
.preclose = exynos_drm_preclose,
|
||||
.lastclose = exynos_drm_lastclose,
|
||||
.postclose = exynos_drm_postclose,
|
||||
.gem_free_object_unlocked = exynos_drm_gem_free_object,
|
||||
|
@ -160,12 +160,9 @@ struct exynos_drm_clk {
|
||||
* drm framework doesn't support multiple irq yet.
|
||||
* we can refer to the crtc to current hardware interrupt occurred through
|
||||
* this pipe value.
|
||||
* @enabled: if the crtc is enabled or not
|
||||
* @event: vblank event that is currently queued for flip
|
||||
* @wait_update: wait all pending planes updates to finish
|
||||
* @pending_update: number of pending plane updates in this crtc
|
||||
* @ops: pointer to callbacks for exynos drm specific functionality
|
||||
* @ctx: A pointer to the crtc's implementation specific context
|
||||
* @pipe_clk: A pointer to the crtc's pipeline clock.
|
||||
*/
|
||||
struct exynos_drm_crtc {
|
||||
struct drm_crtc base;
|
||||
|
@ -1633,7 +1633,6 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
|
||||
{
|
||||
struct device *dev = dsi->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *ep;
|
||||
int ret;
|
||||
|
||||
ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency",
|
||||
@ -1641,32 +1640,21 @@ static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ep = of_graph_get_endpoint_by_regs(node, DSI_PORT_OUT, 0);
|
||||
if (!ep) {
|
||||
dev_err(dev, "no output port with endpoint specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = exynos_dsi_of_read_u32(ep, "samsung,burst-clock-frequency",
|
||||
ret = exynos_dsi_of_read_u32(node, "samsung,burst-clock-frequency",
|
||||
&dsi->burst_clk_rate);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
return ret;
|
||||
|
||||
ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency",
|
||||
ret = exynos_dsi_of_read_u32(node, "samsung,esc-clock-frequency",
|
||||
&dsi->esc_clk_rate);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
of_node_put(ep);
|
||||
return ret;
|
||||
|
||||
dsi->bridge_node = of_graph_get_remote_node(node, DSI_PORT_OUT, 0);
|
||||
if (!dsi->bridge_node)
|
||||
return -EINVAL;
|
||||
|
||||
end:
|
||||
of_node_put(ep);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_dsi_bind(struct device *dev, struct device *master,
|
||||
@ -1817,6 +1805,10 @@ static int exynos_dsi_probe(struct platform_device *pdev)
|
||||
|
||||
static int exynos_dsi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_dsi *dsi = platform_get_drvdata(pdev);
|
||||
|
||||
of_node_put(dsi->bridge_node);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
component_del(&pdev->dev, &exynos_dsi_component_ops);
|
||||
|
@ -779,8 +779,26 @@ static void init_vgpu_execlist(struct intel_vgpu *vgpu, int ring_id)
|
||||
vgpu_vreg(vgpu, ctx_status_ptr_reg) = ctx_status_ptr.dw;
|
||||
}
|
||||
|
||||
static void clean_workloads(struct intel_vgpu *vgpu, unsigned long engine_mask)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
|
||||
struct intel_engine_cs *engine;
|
||||
struct intel_vgpu_workload *pos, *n;
|
||||
unsigned int tmp;
|
||||
|
||||
/* free the unsubmited workloads in the queues. */
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask, tmp) {
|
||||
list_for_each_entry_safe(pos, n,
|
||||
&vgpu->workload_q_head[engine->id], list) {
|
||||
list_del_init(&pos->list);
|
||||
free_workload(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void intel_vgpu_clean_execlist(struct intel_vgpu *vgpu)
|
||||
{
|
||||
clean_workloads(vgpu, ALL_ENGINES);
|
||||
kmem_cache_destroy(vgpu->workloads);
|
||||
}
|
||||
|
||||
@ -811,17 +829,9 @@ void intel_vgpu_reset_execlist(struct intel_vgpu *vgpu,
|
||||
{
|
||||
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
|
||||
struct intel_engine_cs *engine;
|
||||
struct intel_vgpu_workload *pos, *n;
|
||||
unsigned int tmp;
|
||||
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask, tmp) {
|
||||
/* free the unsubmited workload in the queue */
|
||||
list_for_each_entry_safe(pos, n,
|
||||
&vgpu->workload_q_head[engine->id], list) {
|
||||
list_del_init(&pos->list);
|
||||
free_workload(pos);
|
||||
}
|
||||
|
||||
clean_workloads(vgpu, engine_mask);
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask, tmp)
|
||||
init_vgpu_execlist(vgpu, engine->id);
|
||||
}
|
||||
}
|
||||
|
@ -1366,18 +1366,28 @@ static int skl_misc_ctl_write(struct intel_vgpu *vgpu, unsigned int offset,
|
||||
void *p_data, unsigned int bytes)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
|
||||
i915_reg_t reg = {.reg = offset};
|
||||
u32 v = *(u32 *)p_data;
|
||||
|
||||
if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv))
|
||||
return intel_vgpu_default_mmio_write(vgpu,
|
||||
offset, p_data, bytes);
|
||||
|
||||
switch (offset) {
|
||||
case 0x4ddc:
|
||||
vgpu_vreg(vgpu, offset) = 0x8000003c;
|
||||
/* WaCompressedResourceSamplerPbeMediaNewHashMode:skl */
|
||||
I915_WRITE(reg, vgpu_vreg(vgpu, offset));
|
||||
/* bypass WaCompressedResourceSamplerPbeMediaNewHashMode */
|
||||
vgpu_vreg(vgpu, offset) = v & ~(1 << 31);
|
||||
break;
|
||||
case 0x42080:
|
||||
vgpu_vreg(vgpu, offset) = 0x8000;
|
||||
/* WaCompressedResourceDisplayNewHashMode:skl */
|
||||
I915_WRITE(reg, vgpu_vreg(vgpu, offset));
|
||||
/* bypass WaCompressedResourceDisplayNewHashMode */
|
||||
vgpu_vreg(vgpu, offset) = v & ~(1 << 15);
|
||||
break;
|
||||
case 0xe194:
|
||||
/* bypass WaCompressedResourceSamplerPbeMediaNewHashMode */
|
||||
vgpu_vreg(vgpu, offset) = v & ~(1 << 8);
|
||||
break;
|
||||
case 0x7014:
|
||||
/* bypass WaCompressedResourceSamplerPbeMediaNewHashMode */
|
||||
vgpu_vreg(vgpu, offset) = v & ~(1 << 13);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -1634,7 +1644,8 @@ static int init_generic_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_DFH(GAM_ECOCHK, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(GEN7_COMMON_SLICE_CHICKEN1, D_ALL, F_MODE_MASK | F_CMD_ACCESS,
|
||||
NULL, NULL);
|
||||
MMIO_DFH(COMMON_SLICE_CHICKEN2, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(COMMON_SLICE_CHICKEN2, D_ALL, F_MODE_MASK | F_CMD_ACCESS, NULL,
|
||||
skl_misc_ctl_write);
|
||||
MMIO_DFH(0x9030, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(0x20a0, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(0x2420, D_ALL, F_CMD_ACCESS, NULL, NULL);
|
||||
@ -2568,7 +2579,8 @@ static int init_broadwell_mmio_info(struct intel_gvt *gvt)
|
||||
MMIO_D(0x6e570, D_BDW_PLUS);
|
||||
MMIO_D(0x65f10, D_BDW_PLUS);
|
||||
|
||||
MMIO_DFH(0xe194, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(0xe194, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL,
|
||||
skl_misc_ctl_write);
|
||||
MMIO_DFH(0xe188, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(HALF_SLICE_CHICKEN2, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
MMIO_DFH(0x2580, D_BDW_PLUS, F_MODE_MASK | F_CMD_ACCESS, NULL, NULL);
|
||||
|
@ -1272,10 +1272,6 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
dev_priv->ipc_enabled = false;
|
||||
|
||||
/* Everything is in place, we can now relax! */
|
||||
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
|
||||
driver.name, driver.major, driver.minor, driver.patchlevel,
|
||||
driver.date, pci_name(pdev), dev_priv->drm.primary->index);
|
||||
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG))
|
||||
DRM_INFO("DRM_I915_DEBUG enabled\n");
|
||||
if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))
|
||||
|
@ -562,7 +562,8 @@ struct intel_link_m_n {
|
||||
|
||||
void intel_link_compute_m_n(int bpp, int nlanes,
|
||||
int pixel_clock, int link_clock,
|
||||
struct intel_link_m_n *m_n);
|
||||
struct intel_link_m_n *m_n,
|
||||
bool reduce_m_n);
|
||||
|
||||
/* Interface history:
|
||||
*
|
||||
|
@ -2313,7 +2313,7 @@ static int aliasing_gtt_bind_vma(struct i915_vma *vma,
|
||||
appgtt->base.allocate_va_range) {
|
||||
ret = appgtt->base.allocate_va_range(&appgtt->base,
|
||||
vma->node.start,
|
||||
vma->node.size);
|
||||
vma->size);
|
||||
if (ret)
|
||||
goto err_pages;
|
||||
}
|
||||
|
@ -59,9 +59,6 @@ static void i915_gem_shrinker_unlock(struct drm_device *dev, bool unlock)
|
||||
return;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
/* expedite the RCU grace period to free some request slabs */
|
||||
synchronize_rcu_expedited();
|
||||
}
|
||||
|
||||
static bool any_vma_pinned(struct drm_i915_gem_object *obj)
|
||||
@ -274,8 +271,6 @@ unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv)
|
||||
I915_SHRINK_ACTIVE);
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
|
||||
synchronize_rcu(); /* wait for our earlier RCU delayed slab frees */
|
||||
|
||||
return freed;
|
||||
}
|
||||
|
||||
|
@ -2953,7 +2953,6 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
u32 pipestat_mask;
|
||||
u32 enable_mask;
|
||||
enum pipe pipe;
|
||||
u32 val;
|
||||
|
||||
pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
|
||||
PIPE_CRC_DONE_INTERRUPT_STATUS;
|
||||
@ -2964,18 +2963,16 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
|
||||
|
||||
enable_mask = I915_DISPLAY_PORT_INTERRUPT |
|
||||
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
|
||||
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
|
||||
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
|
||||
I915_LPE_PIPE_A_INTERRUPT |
|
||||
I915_LPE_PIPE_B_INTERRUPT;
|
||||
|
||||
if (IS_CHERRYVIEW(dev_priv))
|
||||
enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT;
|
||||
enable_mask |= I915_DISPLAY_PIPE_C_EVENT_INTERRUPT |
|
||||
I915_LPE_PIPE_C_INTERRUPT;
|
||||
|
||||
WARN_ON(dev_priv->irq_mask != ~0);
|
||||
|
||||
val = (I915_LPE_PIPE_A_INTERRUPT |
|
||||
I915_LPE_PIPE_B_INTERRUPT |
|
||||
I915_LPE_PIPE_C_INTERRUPT);
|
||||
|
||||
enable_mask |= val;
|
||||
|
||||
dev_priv->irq_mask = ~enable_mask;
|
||||
|
||||
GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
|
||||
|
@ -8280,7 +8280,7 @@ enum {
|
||||
|
||||
/* MIPI DSI registers */
|
||||
|
||||
#define _MIPI_PORT(port, a, c) ((port) ? c : a) /* ports A and C only */
|
||||
#define _MIPI_PORT(port, a, c) (((port) == PORT_A) ? a : c) /* ports A and C only */
|
||||
#define _MMIO_MIPI(port, a, c) _MMIO(_MIPI_PORT(port, a, c))
|
||||
|
||||
#define MIPIO_TXESC_CLK_DIV1 _MMIO(0x160004)
|
||||
|
@ -15,13 +15,9 @@ static struct intel_dsm_priv {
|
||||
acpi_handle dhandle;
|
||||
} intel_dsm_priv;
|
||||
|
||||
static const u8 intel_dsm_guid[] = {
|
||||
0xd3, 0x73, 0xd8, 0x7e,
|
||||
0xd0, 0xc2,
|
||||
0x4f, 0x4e,
|
||||
0xa8, 0x54,
|
||||
0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c
|
||||
};
|
||||
static const guid_t intel_dsm_guid =
|
||||
GUID_INIT(0x7ed873d3, 0xc2d0, 0x4e4f,
|
||||
0xa8, 0x54, 0x0f, 0x13, 0x17, 0xb0, 0x1c, 0x2c);
|
||||
|
||||
static char *intel_dsm_port_name(u8 id)
|
||||
{
|
||||
@ -80,7 +76,7 @@ static void intel_dsm_platform_mux_info(void)
|
||||
int i;
|
||||
union acpi_object *pkg, *connector_count;
|
||||
|
||||
pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, intel_dsm_guid,
|
||||
pkg = acpi_evaluate_dsm_typed(intel_dsm_priv.dhandle, &intel_dsm_guid,
|
||||
INTEL_DSM_REVISION_ID, INTEL_DSM_FN_PLATFORM_MUX_INFO,
|
||||
NULL, ACPI_TYPE_PACKAGE);
|
||||
if (!pkg) {
|
||||
@ -118,7 +114,7 @@ static bool intel_dsm_pci_probe(struct pci_dev *pdev)
|
||||
if (!dhandle)
|
||||
return false;
|
||||
|
||||
if (!acpi_check_dsm(dhandle, intel_dsm_guid, INTEL_DSM_REVISION_ID,
|
||||
if (!acpi_check_dsm(dhandle, &intel_dsm_guid, INTEL_DSM_REVISION_ID,
|
||||
1 << INTEL_DSM_FN_PLATFORM_MUX_INFO)) {
|
||||
DRM_DEBUG_KMS("no _DSM method for intel device\n");
|
||||
return false;
|
||||
|
@ -6101,7 +6101,7 @@ retry:
|
||||
pipe_config->fdi_lanes = lane;
|
||||
|
||||
intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
|
||||
link_bw, &pipe_config->fdi_m_n);
|
||||
link_bw, &pipe_config->fdi_m_n, false);
|
||||
|
||||
ret = ironlake_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
|
||||
if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
|
||||
@ -6277,7 +6277,8 @@ intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den)
|
||||
}
|
||||
|
||||
static void compute_m_n(unsigned int m, unsigned int n,
|
||||
uint32_t *ret_m, uint32_t *ret_n)
|
||||
uint32_t *ret_m, uint32_t *ret_n,
|
||||
bool reduce_m_n)
|
||||
{
|
||||
/*
|
||||
* Reduce M/N as much as possible without loss in precision. Several DP
|
||||
@ -6285,9 +6286,11 @@ static void compute_m_n(unsigned int m, unsigned int n,
|
||||
* values. The passed in values are more likely to have the least
|
||||
* significant bits zero than M after rounding below, so do this first.
|
||||
*/
|
||||
while ((m & 1) == 0 && (n & 1) == 0) {
|
||||
m >>= 1;
|
||||
n >>= 1;
|
||||
if (reduce_m_n) {
|
||||
while ((m & 1) == 0 && (n & 1) == 0) {
|
||||
m >>= 1;
|
||||
n >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
*ret_n = min_t(unsigned int, roundup_pow_of_two(n), DATA_LINK_N_MAX);
|
||||
@ -6298,16 +6301,19 @@ static void compute_m_n(unsigned int m, unsigned int n,
|
||||
void
|
||||
intel_link_compute_m_n(int bits_per_pixel, int nlanes,
|
||||
int pixel_clock, int link_clock,
|
||||
struct intel_link_m_n *m_n)
|
||||
struct intel_link_m_n *m_n,
|
||||
bool reduce_m_n)
|
||||
{
|
||||
m_n->tu = 64;
|
||||
|
||||
compute_m_n(bits_per_pixel * pixel_clock,
|
||||
link_clock * nlanes * 8,
|
||||
&m_n->gmch_m, &m_n->gmch_n);
|
||||
&m_n->gmch_m, &m_n->gmch_n,
|
||||
reduce_m_n);
|
||||
|
||||
compute_m_n(pixel_clock, link_clock,
|
||||
&m_n->link_m, &m_n->link_n);
|
||||
&m_n->link_m, &m_n->link_n,
|
||||
reduce_m_n);
|
||||
}
|
||||
|
||||
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
|
||||
|
@ -1507,37 +1507,6 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
|
||||
DRM_DEBUG_KMS("common rates: %s\n", str);
|
||||
}
|
||||
|
||||
bool
|
||||
__intel_dp_read_desc(struct intel_dp *intel_dp, struct intel_dp_desc *desc)
|
||||
{
|
||||
u32 base = drm_dp_is_branch(intel_dp->dpcd) ? DP_BRANCH_OUI :
|
||||
DP_SINK_OUI;
|
||||
|
||||
return drm_dp_dpcd_read(&intel_dp->aux, base, desc, sizeof(*desc)) ==
|
||||
sizeof(*desc);
|
||||
}
|
||||
|
||||
bool intel_dp_read_desc(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_dp_desc *desc = &intel_dp->desc;
|
||||
bool oui_sup = intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] &
|
||||
DP_OUI_SUPPORT;
|
||||
int dev_id_len;
|
||||
|
||||
if (!__intel_dp_read_desc(intel_dp, desc))
|
||||
return false;
|
||||
|
||||
dev_id_len = strnlen(desc->device_id, sizeof(desc->device_id));
|
||||
DRM_DEBUG_KMS("DP %s: OUI %*phD%s dev-ID %*pE HW-rev %d.%d SW-rev %d.%d\n",
|
||||
drm_dp_is_branch(intel_dp->dpcd) ? "branch" : "sink",
|
||||
(int)sizeof(desc->oui), desc->oui, oui_sup ? "" : "(NS)",
|
||||
dev_id_len, desc->device_id,
|
||||
desc->hw_rev >> 4, desc->hw_rev & 0xf,
|
||||
desc->sw_major_rev, desc->sw_minor_rev);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int rate_to_index(int find, const int *rates)
|
||||
{
|
||||
int i = 0;
|
||||
@ -1624,6 +1593,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
int common_rates[DP_MAX_SUPPORTED_RATES] = {};
|
||||
int common_len;
|
||||
uint8_t link_bw, rate_select;
|
||||
bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc,
|
||||
DP_DPCD_QUIRK_LIMITED_M_N);
|
||||
|
||||
common_len = intel_dp_common_rates(intel_dp, common_rates);
|
||||
|
||||
@ -1753,7 +1724,8 @@ found:
|
||||
intel_link_compute_m_n(bpp, lane_count,
|
||||
adjusted_mode->crtc_clock,
|
||||
pipe_config->port_clock,
|
||||
&pipe_config->dp_m_n);
|
||||
&pipe_config->dp_m_n,
|
||||
reduce_m_n);
|
||||
|
||||
if (intel_connector->panel.downclock_mode != NULL &&
|
||||
dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
|
||||
@ -1761,7 +1733,8 @@ found:
|
||||
intel_link_compute_m_n(bpp, lane_count,
|
||||
intel_connector->panel.downclock_mode->clock,
|
||||
pipe_config->port_clock,
|
||||
&pipe_config->dp_m2_n2);
|
||||
&pipe_config->dp_m2_n2,
|
||||
reduce_m_n);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3622,7 +3595,8 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp)
|
||||
if (!intel_dp_read_dpcd(intel_dp))
|
||||
return false;
|
||||
|
||||
intel_dp_read_desc(intel_dp);
|
||||
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
|
||||
drm_dp_is_branch(intel_dp->dpcd));
|
||||
|
||||
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
|
||||
dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
|
||||
@ -4624,7 +4598,8 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
|
||||
|
||||
intel_dp_print_rates(intel_dp);
|
||||
|
||||
intel_dp_read_desc(intel_dp);
|
||||
drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
|
||||
drm_dp_is_branch(intel_dp->dpcd));
|
||||
|
||||
intel_dp_configure_mst(intel_dp);
|
||||
|
||||
|
@ -44,6 +44,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
int lane_count, slots;
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
int mst_pbn;
|
||||
bool reduce_m_n = drm_dp_has_quirk(&intel_dp->desc,
|
||||
DP_DPCD_QUIRK_LIMITED_M_N);
|
||||
|
||||
pipe_config->has_pch_encoder = false;
|
||||
bpp = 24;
|
||||
@ -75,7 +77,8 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
intel_link_compute_m_n(bpp, lane_count,
|
||||
adjusted_mode->crtc_clock,
|
||||
pipe_config->port_clock,
|
||||
&pipe_config->dp_m_n);
|
||||
&pipe_config->dp_m_n,
|
||||
reduce_m_n);
|
||||
|
||||
pipe_config->dp_m_n.tu = slots;
|
||||
|
||||
|
@ -906,14 +906,6 @@ enum link_m_n_set {
|
||||
M2_N2
|
||||
};
|
||||
|
||||
struct intel_dp_desc {
|
||||
u8 oui[3];
|
||||
u8 device_id[6];
|
||||
u8 hw_rev;
|
||||
u8 sw_major_rev;
|
||||
u8 sw_minor_rev;
|
||||
} __packed;
|
||||
|
||||
struct intel_dp_compliance_data {
|
||||
unsigned long edid;
|
||||
uint8_t video_pattern;
|
||||
@ -957,7 +949,7 @@ struct intel_dp {
|
||||
/* Max link BW for the sink as per DPCD registers */
|
||||
int max_sink_link_bw;
|
||||
/* sink or branch descriptor */
|
||||
struct intel_dp_desc desc;
|
||||
struct drm_dp_desc desc;
|
||||
struct drm_dp_aux aux;
|
||||
enum intel_display_power_domain aux_power_domain;
|
||||
uint8_t train_set[4];
|
||||
@ -1532,9 +1524,6 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
|
||||
}
|
||||
|
||||
bool intel_dp_read_dpcd(struct intel_dp *intel_dp);
|
||||
bool __intel_dp_read_desc(struct intel_dp *intel_dp,
|
||||
struct intel_dp_desc *desc);
|
||||
bool intel_dp_read_desc(struct intel_dp *intel_dp);
|
||||
int intel_dp_link_required(int pixel_clock, int bpp);
|
||||
int intel_dp_max_data_rate(int max_link_clock, int max_lanes);
|
||||
bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
|
||||
|
@ -149,44 +149,10 @@ static void lpe_audio_platdev_destroy(struct drm_i915_private *dev_priv)
|
||||
|
||||
static void lpe_audio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = d->chip_data;
|
||||
unsigned long irqflags;
|
||||
u32 val = (I915_LPE_PIPE_A_INTERRUPT |
|
||||
I915_LPE_PIPE_B_INTERRUPT);
|
||||
|
||||
if (IS_CHERRYVIEW(dev_priv))
|
||||
val |= I915_LPE_PIPE_C_INTERRUPT;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
|
||||
|
||||
dev_priv->irq_mask &= ~val;
|
||||
I915_WRITE(VLV_IIR, val);
|
||||
I915_WRITE(VLV_IIR, val);
|
||||
I915_WRITE(VLV_IMR, dev_priv->irq_mask);
|
||||
POSTING_READ(VLV_IMR);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
}
|
||||
|
||||
static void lpe_audio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = d->chip_data;
|
||||
unsigned long irqflags;
|
||||
u32 val = (I915_LPE_PIPE_A_INTERRUPT |
|
||||
I915_LPE_PIPE_B_INTERRUPT);
|
||||
|
||||
if (IS_CHERRYVIEW(dev_priv))
|
||||
val |= I915_LPE_PIPE_C_INTERRUPT;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
|
||||
|
||||
dev_priv->irq_mask |= val;
|
||||
I915_WRITE(VLV_IMR, dev_priv->irq_mask);
|
||||
I915_WRITE(VLV_IIR, val);
|
||||
I915_WRITE(VLV_IIR, val);
|
||||
POSTING_READ(VLV_IIR);
|
||||
|
||||
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
|
||||
}
|
||||
|
||||
static struct irq_chip lpe_audio_irqchip = {
|
||||
@ -330,8 +296,6 @@ void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv)
|
||||
|
||||
desc = irq_to_desc(dev_priv->lpe_audio.irq);
|
||||
|
||||
lpe_audio_irq_mask(&desc->irq_data);
|
||||
|
||||
lpe_audio_platdev_destroy(dev_priv);
|
||||
|
||||
irq_free_desc(dev_priv->lpe_audio.irq);
|
||||
|
@ -1989,7 +1989,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
|
||||
|
||||
ce->ring = ring;
|
||||
ce->state = vma;
|
||||
ce->initialised = engine->init_context == NULL;
|
||||
ce->initialised |= engine->init_context == NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -240,7 +240,7 @@ bool lspcon_init(struct intel_digital_port *intel_dig_port)
|
||||
return false;
|
||||
}
|
||||
|
||||
intel_dp_read_desc(dp);
|
||||
drm_dp_read_desc(&dp->aux, &dp->desc, drm_dp_is_branch(dp->dpcd));
|
||||
|
||||
DRM_DEBUG_KMS("Success: LSPCON init\n");
|
||||
return true;
|
||||
|
@ -320,7 +320,7 @@ static unsigned long max_dwords(struct drm_i915_gem_object *obj)
|
||||
static int igt_ctx_exec(void *arg)
|
||||
{
|
||||
struct drm_i915_private *i915 = arg;
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct drm_i915_gem_object *obj = NULL;
|
||||
struct drm_file *file;
|
||||
IGT_TIMEOUT(end_time);
|
||||
LIST_HEAD(objects);
|
||||
@ -359,7 +359,7 @@ static int igt_ctx_exec(void *arg)
|
||||
}
|
||||
|
||||
for_each_engine(engine, i915, id) {
|
||||
if (dw == 0) {
|
||||
if (!obj) {
|
||||
obj = create_test_object(ctx, file, &objects);
|
||||
if (IS_ERR(obj)) {
|
||||
err = PTR_ERR(obj);
|
||||
@ -376,8 +376,10 @@ static int igt_ctx_exec(void *arg)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (++dw == max_dwords(obj))
|
||||
if (++dw == max_dwords(obj)) {
|
||||
obj = NULL;
|
||||
dw = 0;
|
||||
}
|
||||
ndwords++;
|
||||
}
|
||||
ncontexts++;
|
||||
|
@ -13,6 +13,7 @@ config DRM_MSM
|
||||
select QCOM_SCM
|
||||
select SND_SOC_HDMI_CODEC if SND_SOC
|
||||
select SYNC_FILE
|
||||
select PM_OPP
|
||||
default y
|
||||
help
|
||||
DRM/KMS driver for MSM/snapdragon.
|
||||
|
@ -116,7 +116,7 @@ static int mdss_hw_irqdomain_map(struct irq_domain *d, unsigned int irq,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_domain_ops mdss_hw_irqdomain_ops = {
|
||||
static const struct irq_domain_ops mdss_hw_irqdomain_ops = {
|
||||
.map = mdss_hw_irqdomain_map,
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
@ -225,9 +225,10 @@ mdp5_plane_duplicate_state(struct drm_plane *plane)
|
||||
|
||||
mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
|
||||
sizeof(*mdp5_state), GFP_KERNEL);
|
||||
if (!mdp5_state)
|
||||
return NULL;
|
||||
|
||||
if (mdp5_state && mdp5_state->base.fb)
|
||||
drm_framebuffer_reference(mdp5_state->base.fb);
|
||||
__drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base);
|
||||
|
||||
return &mdp5_state->base;
|
||||
}
|
||||
@ -444,6 +445,10 @@ static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
|
||||
mdp5_pipe_release(state->state, old_hwpipe);
|
||||
mdp5_pipe_release(state->state, old_right_hwpipe);
|
||||
}
|
||||
} else {
|
||||
mdp5_pipe_release(state->state, mdp5_state->hwpipe);
|
||||
mdp5_pipe_release(state->state, mdp5_state->r_hwpipe);
|
||||
mdp5_state->hwpipe = mdp5_state->r_hwpipe = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -830,6 +830,7 @@ static struct drm_driver msm_driver = {
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_export = drm_gem_prime_export,
|
||||
.gem_prime_import = drm_gem_prime_import,
|
||||
.gem_prime_res_obj = msm_gem_prime_res_obj,
|
||||
.gem_prime_pin = msm_gem_prime_pin,
|
||||
.gem_prime_unpin = msm_gem_prime_unpin,
|
||||
.gem_prime_get_sg_table = msm_gem_prime_get_sg_table,
|
||||
|
@ -224,6 +224,7 @@ struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);
|
||||
void *msm_gem_prime_vmap(struct drm_gem_object *obj);
|
||||
void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
|
||||
int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
|
||||
struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj);
|
||||
struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
|
||||
struct dma_buf_attachment *attach, struct sg_table *sg);
|
||||
int msm_gem_prime_pin(struct drm_gem_object *obj);
|
||||
|
@ -99,8 +99,8 @@ void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence)
|
||||
}
|
||||
|
||||
struct msm_fence {
|
||||
struct msm_fence_context *fctx;
|
||||
struct dma_fence base;
|
||||
struct msm_fence_context *fctx;
|
||||
};
|
||||
|
||||
static inline struct msm_fence *to_msm_fence(struct dma_fence *fence)
|
||||
@ -130,19 +130,13 @@ static bool msm_fence_signaled(struct dma_fence *fence)
|
||||
return fence_completed(f->fctx, f->base.seqno);
|
||||
}
|
||||
|
||||
static void msm_fence_release(struct dma_fence *fence)
|
||||
{
|
||||
struct msm_fence *f = to_msm_fence(fence);
|
||||
kfree_rcu(f, base.rcu);
|
||||
}
|
||||
|
||||
static const struct dma_fence_ops msm_fence_ops = {
|
||||
.get_driver_name = msm_fence_get_driver_name,
|
||||
.get_timeline_name = msm_fence_get_timeline_name,
|
||||
.enable_signaling = msm_fence_enable_signaling,
|
||||
.signaled = msm_fence_signaled,
|
||||
.wait = dma_fence_default_wait,
|
||||
.release = msm_fence_release,
|
||||
.release = dma_fence_free,
|
||||
};
|
||||
|
||||
struct dma_fence *
|
||||
|
@ -758,6 +758,8 @@ static int msm_gem_new_impl(struct drm_device *dev,
|
||||
struct msm_gem_object *msm_obj;
|
||||
bool use_vram = false;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
|
||||
|
||||
switch (flags & MSM_BO_CACHE_MASK) {
|
||||
case MSM_BO_UNCACHED:
|
||||
case MSM_BO_CACHED:
|
||||
@ -853,7 +855,11 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
|
||||
|
||||
size = PAGE_ALIGN(dmabuf->size);
|
||||
|
||||
/* Take mutex so we can modify the inactive list in msm_gem_new_impl */
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
|
@ -70,3 +70,10 @@ void msm_gem_prime_unpin(struct drm_gem_object *obj)
|
||||
if (!obj->import_attach)
|
||||
msm_gem_put_pages(obj);
|
||||
}
|
||||
|
||||
struct reservation_object *msm_gem_prime_res_obj(struct drm_gem_object *obj)
|
||||
{
|
||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||
|
||||
return msm_obj->resv;
|
||||
}
|
||||
|
@ -410,12 +410,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
if (!in_fence)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO if we get an array-fence due to userspace merging multiple
|
||||
* fences, we need a way to determine if all the backing fences
|
||||
* are from our own context..
|
||||
/*
|
||||
* Wait if the fence is from a foreign context, or if the fence
|
||||
* array contains any fence from a foreign context.
|
||||
*/
|
||||
|
||||
if (in_fence->context != gpu->fctx->context) {
|
||||
if (!dma_fence_match_context(in_fence, gpu->fctx->context)) {
|
||||
ret = dma_fence_wait(in_fence, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -496,8 +495,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((submit_cmd.size + submit_cmd.submit_offset) >=
|
||||
msm_obj->base.size) {
|
||||
if (!submit_cmd.size ||
|
||||
((submit_cmd.size + submit_cmd.submit_offset) >
|
||||
msm_obj->base.size)) {
|
||||
DRM_ERROR("invalid cmdstream size: %u\n", submit_cmd.size);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
|
@ -549,9 +549,9 @@ static int get_clocks(struct platform_device *pdev, struct msm_gpu *gpu)
|
||||
gpu->grp_clks[i] = get_clock(dev, name);
|
||||
|
||||
/* Remember the key clocks that we need to control later */
|
||||
if (!strcmp(name, "core"))
|
||||
if (!strcmp(name, "core") || !strcmp(name, "core_clk"))
|
||||
gpu->core_clk = gpu->grp_clks[i];
|
||||
else if (!strcmp(name, "rbbmtimer"))
|
||||
else if (!strcmp(name, "rbbmtimer") || !strcmp(name, "rbbmtimer_clk"))
|
||||
gpu->rbbmtimer_clk = gpu->grp_clks[i];
|
||||
|
||||
++i;
|
||||
|
@ -60,15 +60,13 @@ bool nouveau_is_v1_dsm(void) {
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VGA_SWITCHEROO
|
||||
static const char nouveau_dsm_muid[] = {
|
||||
0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
|
||||
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
|
||||
};
|
||||
static const guid_t nouveau_dsm_muid =
|
||||
GUID_INIT(0x9D95A0A0, 0x0060, 0x4D48,
|
||||
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4);
|
||||
|
||||
static const char nouveau_op_dsm_muid[] = {
|
||||
0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
|
||||
0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
|
||||
};
|
||||
static const guid_t nouveau_op_dsm_muid =
|
||||
GUID_INIT(0xA486D8F8, 0x0BDA, 0x471B,
|
||||
0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0);
|
||||
|
||||
static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
|
||||
{
|
||||
@ -86,7 +84,7 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
|
||||
args_buff[i] = (arg >> i * 8) & 0xFF;
|
||||
|
||||
*result = 0;
|
||||
obj = acpi_evaluate_dsm_typed(handle, nouveau_op_dsm_muid, 0x00000100,
|
||||
obj = acpi_evaluate_dsm_typed(handle, &nouveau_op_dsm_muid, 0x00000100,
|
||||
func, &argv4, ACPI_TYPE_BUFFER);
|
||||
if (!obj) {
|
||||
acpi_handle_info(handle, "failed to evaluate _DSM\n");
|
||||
@ -138,7 +136,7 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg)
|
||||
.integer.value = arg,
|
||||
};
|
||||
|
||||
obj = acpi_evaluate_dsm_typed(handle, nouveau_dsm_muid, 0x00000102,
|
||||
obj = acpi_evaluate_dsm_typed(handle, &nouveau_dsm_muid, 0x00000102,
|
||||
func, &argv4, ACPI_TYPE_INTEGER);
|
||||
if (!obj) {
|
||||
acpi_handle_info(handle, "failed to evaluate _DSM\n");
|
||||
@ -259,7 +257,7 @@ static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out
|
||||
if (!acpi_has_method(dhandle, "_DSM"))
|
||||
return;
|
||||
|
||||
supports_mux = acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102,
|
||||
supports_mux = acpi_check_dsm(dhandle, &nouveau_dsm_muid, 0x00000102,
|
||||
1 << NOUVEAU_DSM_POWER);
|
||||
optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);
|
||||
|
||||
|
@ -81,10 +81,9 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &mxm->subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
static char muid[] = {
|
||||
0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C,
|
||||
0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
|
||||
};
|
||||
static guid_t muid =
|
||||
GUID_INIT(0x4004A400, 0x917D, 0x4CF2,
|
||||
0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65);
|
||||
u32 mxms_args[] = { 0x00000000 };
|
||||
union acpi_object argv4 = {
|
||||
.buffer.type = ACPI_TYPE_BUFFER,
|
||||
@ -105,7 +104,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version)
|
||||
* unless you pass in exactly the version it supports..
|
||||
*/
|
||||
rev = (version & 0xf0) << 4 | (version & 0x0f);
|
||||
obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4);
|
||||
obj = acpi_evaluate_dsm(handle, &muid, rev, 0x00000010, &argv4);
|
||||
if (!obj) {
|
||||
nvkm_debug(subdev, "DSM MXMS failed\n");
|
||||
return false;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user