Merge 9bf445b65d ("Merge tag 'x86_paravirt_for_v6.1_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip") into android-mainline
Steps on the way to 6.1-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: Ibe54b54865ce0e39d44708c4bab6be4495a657d8
This commit is contained in:
@@ -3813,6 +3813,10 @@
|
||||
|
||||
nox2apic [X86-64,APIC] Do not enable x2APIC mode.
|
||||
|
||||
NOTE: this parameter will be ignored on systems with the
|
||||
LEGACY_XAPIC_DISABLED bit set in the
|
||||
IA32_XAPIC_DISABLE_STATUS MSR.
|
||||
|
||||
nps_mtm_hs_ctr= [KNL,ARC]
|
||||
This parameter sets the maximum duration, in
|
||||
cycles, each HW thread of the CTOP can run
|
||||
|
||||
+7
-2
@@ -451,6 +451,11 @@ config X86_X2APIC
|
||||
This allows 32-bit apic IDs (so it can support very large systems),
|
||||
and accesses the local apic via MSRs not via mmio.
|
||||
|
||||
Some Intel systems circa 2022 and later are locked into x2APIC mode
|
||||
and can not fall back to the legacy APIC modes if SGX or TDX are
|
||||
enabled in the BIOS. They will be unable to boot without enabling
|
||||
this option.
|
||||
|
||||
If you don't know what to do here, say N.
|
||||
|
||||
config X86_MPPARSE
|
||||
@@ -1922,7 +1927,7 @@ endchoice
|
||||
|
||||
config X86_SGX
|
||||
bool "Software Guard eXtensions (SGX)"
|
||||
depends on X86_64 && CPU_SUP_INTEL
|
||||
depends on X86_64 && CPU_SUP_INTEL && X86_X2APIC
|
||||
depends on CRYPTO=y
|
||||
depends on CRYPTO_SHA256=y
|
||||
select SRCU
|
||||
@@ -2572,7 +2577,7 @@ menuconfig APM
|
||||
|
||||
1) make sure that you have enough swap space and that it is
|
||||
enabled.
|
||||
2) pass the "no-hlt" option to the kernel
|
||||
2) pass the "idle=poll" option to the kernel
|
||||
3) switch on floating point emulation in the kernel and pass
|
||||
the "no387" option to the kernel
|
||||
4) pass the "floppy=nodma" option to the kernel
|
||||
|
||||
@@ -10,6 +10,15 @@
|
||||
/* Bit 0 indicates whether guest VM is privileged */
|
||||
#define ACRN_FEATURE_PRIVILEGED_VM BIT(0)
|
||||
|
||||
/*
|
||||
* Timing Information.
|
||||
* This leaf returns the current TSC frequency in kHz.
|
||||
*
|
||||
* EAX: (Virtual) TSC frequency in kHz.
|
||||
* EBX, ECX, EDX: RESERVED (reserved fields are set to zero).
|
||||
*/
|
||||
#define ACRN_CPUID_TIMING_INFO 0x40000010
|
||||
|
||||
void acrn_setup_intr_handler(void (*handler)(void));
|
||||
void acrn_remove_intr_handler(void);
|
||||
|
||||
@@ -21,6 +30,11 @@ static inline u32 acrn_cpuid_base(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long acrn_get_tsc_khz(void)
|
||||
{
|
||||
return cpuid_eax(ACRN_CPUID_TIMING_INFO);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hypercalls for ACRN
|
||||
*
|
||||
|
||||
@@ -247,17 +247,30 @@ arch_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
|
||||
variable_test_bit(nr, addr);
|
||||
}
|
||||
|
||||
static __always_inline unsigned long variable__ffs(unsigned long word)
|
||||
{
|
||||
asm("rep; bsf %1,%0"
|
||||
: "=r" (word)
|
||||
: "rm" (word));
|
||||
return word;
|
||||
}
|
||||
|
||||
/**
|
||||
* __ffs - find first set bit in word
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static __always_inline unsigned long __ffs(unsigned long word)
|
||||
#define __ffs(word) \
|
||||
(__builtin_constant_p(word) ? \
|
||||
(unsigned long)__builtin_ctzl(word) : \
|
||||
variable__ffs(word))
|
||||
|
||||
static __always_inline unsigned long variable_ffz(unsigned long word)
|
||||
{
|
||||
asm("rep; bsf %1,%0"
|
||||
: "=r" (word)
|
||||
: "rm" (word));
|
||||
: "r" (~word));
|
||||
return word;
|
||||
}
|
||||
|
||||
@@ -267,13 +280,10 @@ static __always_inline unsigned long __ffs(unsigned long word)
|
||||
*
|
||||
* Undefined if no zero exists, so code should check against ~0UL first.
|
||||
*/
|
||||
static __always_inline unsigned long ffz(unsigned long word)
|
||||
{
|
||||
asm("rep; bsf %1,%0"
|
||||
: "=r" (word)
|
||||
: "r" (~word));
|
||||
return word;
|
||||
}
|
||||
#define ffz(word) \
|
||||
(__builtin_constant_p(word) ? \
|
||||
(unsigned long)__builtin_ctzl(~word) : \
|
||||
variable_ffz(word))
|
||||
|
||||
/*
|
||||
* __fls: find last set bit in word
|
||||
@@ -292,18 +302,7 @@ static __always_inline unsigned long __fls(unsigned long word)
|
||||
#undef ADDR
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/**
|
||||
* ffs - find first set bit in word
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as the libc and compiler builtin ffs
|
||||
* routines, therefore differs in spirit from the other bitops.
|
||||
*
|
||||
* ffs(value) returns 0 if value is 0 or the position of the first
|
||||
* set bit if value is nonzero. The first (least significant) bit
|
||||
* is at position 1.
|
||||
*/
|
||||
static __always_inline int ffs(int x)
|
||||
static __always_inline int variable_ffs(int x)
|
||||
{
|
||||
int r;
|
||||
|
||||
@@ -333,6 +332,19 @@ static __always_inline int ffs(int x)
|
||||
return r + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ffs - find first set bit in word
|
||||
* @x: the word to search
|
||||
*
|
||||
* This is defined the same way as the libc and compiler builtin ffs
|
||||
* routines, therefore differs in spirit from the other bitops.
|
||||
*
|
||||
* ffs(value) returns 0 if value is 0 or the position of the first
|
||||
* set bit if value is nonzero. The first (least significant) bit
|
||||
* is at position 1.
|
||||
*/
|
||||
#define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))
|
||||
|
||||
/**
|
||||
* fls - find last set bit in word
|
||||
* @x: the word to search
|
||||
|
||||
@@ -94,4 +94,6 @@ static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1,
|
||||
return p1 & p2;
|
||||
}
|
||||
|
||||
extern u64 x86_read_arch_cap_msr(void);
|
||||
|
||||
#endif /* _ASM_X86_CPU_H */
|
||||
|
||||
@@ -95,7 +95,7 @@ static inline unsigned char current_lock_cmos_reg(void)
|
||||
unsigned char rtc_cmos_read(unsigned char addr);
|
||||
void rtc_cmos_write(unsigned char val, unsigned char addr);
|
||||
|
||||
extern int mach_set_rtc_mmss(const struct timespec64 *now);
|
||||
extern int mach_set_cmos_time(const struct timespec64 *now);
|
||||
extern void mach_get_cmos_time(struct timespec64 *now);
|
||||
|
||||
#define RTC_IRQ 8
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#define MCI_STATUS_CEC_SHIFT 38 /* Corrected Error Count */
|
||||
#define MCI_STATUS_CEC_MASK GENMASK_ULL(52,38)
|
||||
#define MCI_STATUS_CEC(c) (((c) & MCI_STATUS_CEC_MASK) >> MCI_STATUS_CEC_SHIFT)
|
||||
#define MCI_STATUS_MSCOD(m) (((m) >> 16) & 0xffff)
|
||||
|
||||
/* AMD-specific bits */
|
||||
#define MCI_STATUS_TCC BIT_ULL(55) /* Task context corrupt */
|
||||
|
||||
@@ -155,6 +155,11 @@
|
||||
* Return Stack Buffer Predictions.
|
||||
*/
|
||||
|
||||
#define ARCH_CAP_XAPIC_DISABLE BIT(21) /*
|
||||
* IA32_XAPIC_DISABLE_STATUS MSR
|
||||
* supported
|
||||
*/
|
||||
|
||||
#define MSR_IA32_FLUSH_CMD 0x0000010b
|
||||
#define L1D_FLUSH BIT(0) /*
|
||||
* Writeback and invalidate the
|
||||
@@ -1054,4 +1059,12 @@
|
||||
#define MSR_IA32_HW_FEEDBACK_PTR 0x17d0
|
||||
#define MSR_IA32_HW_FEEDBACK_CONFIG 0x17d1
|
||||
|
||||
/* x2APIC locked status */
|
||||
#define MSR_IA32_XAPIC_DISABLE_STATUS 0xBD
|
||||
#define LEGACY_XAPIC_DISABLED BIT(0) /*
|
||||
* x2APIC mode is locked and
|
||||
* disabling x2APIC will cause
|
||||
* a #GP
|
||||
*/
|
||||
|
||||
#endif /* _ASM_X86_MSR_INDEX_H */
|
||||
|
||||
@@ -743,6 +743,7 @@ extern void default_banner(void);
|
||||
word 771b; \
|
||||
.byte ptype; \
|
||||
.byte 772b-771b; \
|
||||
_ASM_ALIGN; \
|
||||
.popsection
|
||||
|
||||
|
||||
|
||||
@@ -294,6 +294,7 @@ extern struct paravirt_patch_template pv_ops;
|
||||
" .byte " type "\n" \
|
||||
" .byte 772b-771b\n" \
|
||||
" .short " clobber "\n" \
|
||||
_ASM_ALIGN "\n" \
|
||||
".popsection\n"
|
||||
|
||||
/* Generate patchable code, with the default asm parameters. */
|
||||
|
||||
@@ -502,9 +502,6 @@ strncpy_from_user(char *dst, const char __user *src, long count);
|
||||
|
||||
extern __must_check long strnlen_user(const char __user *str, long n);
|
||||
|
||||
unsigned long __must_check clear_user(void __user *mem, unsigned long len);
|
||||
unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_COPY_MC
|
||||
unsigned long __must_check
|
||||
copy_mc_to_kernel(void *to, const void *from, unsigned len);
|
||||
@@ -526,6 +523,8 @@ extern struct movsl_mask {
|
||||
#define ARCH_HAS_NOCACHE_UACCESS 1
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
unsigned long __must_check clear_user(void __user *mem, unsigned long len);
|
||||
unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
|
||||
# include <asm/uaccess_32.h>
|
||||
#else
|
||||
# include <asm/uaccess_64.h>
|
||||
|
||||
@@ -79,4 +79,49 @@ __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size)
|
||||
kasan_check_write(dst, size);
|
||||
return __copy_user_flushcache(dst, src, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero Userspace.
|
||||
*/
|
||||
|
||||
__must_check unsigned long
|
||||
clear_user_original(void __user *addr, unsigned long len);
|
||||
__must_check unsigned long
|
||||
clear_user_rep_good(void __user *addr, unsigned long len);
|
||||
__must_check unsigned long
|
||||
clear_user_erms(void __user *addr, unsigned long len);
|
||||
|
||||
static __always_inline __must_check unsigned long __clear_user(void __user *addr, unsigned long size)
|
||||
{
|
||||
might_fault();
|
||||
stac();
|
||||
|
||||
/*
|
||||
* No memory constraint because it doesn't change any memory gcc
|
||||
* knows about.
|
||||
*/
|
||||
asm volatile(
|
||||
"1:\n\t"
|
||||
ALTERNATIVE_3("rep stosb",
|
||||
"call clear_user_erms", ALT_NOT(X86_FEATURE_FSRM),
|
||||
"call clear_user_rep_good", ALT_NOT(X86_FEATURE_ERMS),
|
||||
"call clear_user_original", ALT_NOT(X86_FEATURE_REP_GOOD))
|
||||
"2:\n"
|
||||
_ASM_EXTABLE_UA(1b, 2b)
|
||||
: "+c" (size), "+D" (addr), ASM_CALL_CONSTRAINT
|
||||
: "a" (0)
|
||||
/* rep_good clobbers %rdx */
|
||||
: "rdx");
|
||||
|
||||
clac();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static __always_inline unsigned long clear_user(void __user *to, unsigned long n)
|
||||
{
|
||||
if (access_ok(to, n))
|
||||
return __clear_user(to, n);
|
||||
return n;
|
||||
}
|
||||
#endif /* _ASM_X86_UACCESS_64_H */
|
||||
|
||||
@@ -453,6 +453,15 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
|
||||
return ret;
|
||||
i += ret;
|
||||
|
||||
/*
|
||||
* The compiler is supposed to EMIT an INT3 after every unconditional
|
||||
* JMP instruction due to AMD BTC. However, if the compiler is too old
|
||||
* or SLS isn't enabled, we still need an INT3 after indirect JMPs
|
||||
* even on Intel.
|
||||
*/
|
||||
if (op == JMP32_INSN_OPCODE && i < insn->length)
|
||||
bytes[i++] = INT3_INSN_OPCODE;
|
||||
|
||||
for (; i < insn->length;)
|
||||
bytes[i++] = BYTES_NOP1;
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#include <asm/cpu_device_id.h>
|
||||
#include <asm/intel-family.h>
|
||||
#include <asm/irq_regs.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
unsigned int num_processors;
|
||||
|
||||
@@ -1751,11 +1752,26 @@ EXPORT_SYMBOL_GPL(x2apic_mode);
|
||||
|
||||
enum {
|
||||
X2APIC_OFF,
|
||||
X2APIC_ON,
|
||||
X2APIC_DISABLED,
|
||||
/* All states below here have X2APIC enabled */
|
||||
X2APIC_ON,
|
||||
X2APIC_ON_LOCKED
|
||||
};
|
||||
static int x2apic_state;
|
||||
|
||||
static bool x2apic_hw_locked(void)
|
||||
{
|
||||
u64 ia32_cap;
|
||||
u64 msr;
|
||||
|
||||
ia32_cap = x86_read_arch_cap_msr();
|
||||
if (ia32_cap & ARCH_CAP_XAPIC_DISABLE) {
|
||||
rdmsrl(MSR_IA32_XAPIC_DISABLE_STATUS, msr);
|
||||
return (msr & LEGACY_XAPIC_DISABLED);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __x2apic_disable(void)
|
||||
{
|
||||
u64 msr;
|
||||
@@ -1793,6 +1809,10 @@ static int __init setup_nox2apic(char *str)
|
||||
apicid);
|
||||
return 0;
|
||||
}
|
||||
if (x2apic_hw_locked()) {
|
||||
pr_warn("APIC locked in x2apic mode, can't disable\n");
|
||||
return 0;
|
||||
}
|
||||
pr_warn("x2apic already enabled.\n");
|
||||
__x2apic_disable();
|
||||
}
|
||||
@@ -1807,10 +1827,18 @@ early_param("nox2apic", setup_nox2apic);
|
||||
void x2apic_setup(void)
|
||||
{
|
||||
/*
|
||||
* If x2apic is not in ON state, disable it if already enabled
|
||||
* Try to make the AP's APIC state match that of the BSP, but if the
|
||||
* BSP is unlocked and the AP is locked then there is a state mismatch.
|
||||
* Warn about the mismatch in case a GP fault occurs due to a locked AP
|
||||
* trying to be turned off.
|
||||
*/
|
||||
if (x2apic_state != X2APIC_ON_LOCKED && x2apic_hw_locked())
|
||||
pr_warn("x2apic lock mismatch between BSP and AP.\n");
|
||||
/*
|
||||
* If x2apic is not in ON or LOCKED state, disable it if already enabled
|
||||
* from BIOS.
|
||||
*/
|
||||
if (x2apic_state != X2APIC_ON) {
|
||||
if (x2apic_state < X2APIC_ON) {
|
||||
__x2apic_disable();
|
||||
return;
|
||||
}
|
||||
@@ -1831,6 +1859,11 @@ static __init void x2apic_disable(void)
|
||||
if (x2apic_id >= 255)
|
||||
panic("Cannot disable x2apic, id: %08x\n", x2apic_id);
|
||||
|
||||
if (x2apic_hw_locked()) {
|
||||
pr_warn("Cannot disable locked x2apic, id: %08x\n", x2apic_id);
|
||||
return;
|
||||
}
|
||||
|
||||
__x2apic_disable();
|
||||
register_lapic_address(mp_lapic_addr);
|
||||
}
|
||||
@@ -1889,7 +1922,10 @@ void __init check_x2apic(void)
|
||||
if (x2apic_enabled()) {
|
||||
pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n");
|
||||
x2apic_mode = 1;
|
||||
x2apic_state = X2APIC_ON;
|
||||
if (x2apic_hw_locked())
|
||||
x2apic_state = X2APIC_ON_LOCKED;
|
||||
else
|
||||
x2apic_state = X2APIC_ON;
|
||||
} else if (!boot_cpu_has(X86_FEATURE_X2APIC)) {
|
||||
x2apic_state = X2APIC_DISABLED;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ static void __init acrn_init_platform(void)
|
||||
{
|
||||
/* Setup the IDT for ACRN hypervisor callback */
|
||||
alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_acrn_hv_callback);
|
||||
|
||||
x86_platform.calibrate_tsc = acrn_get_tsc_khz;
|
||||
x86_platform.calibrate_cpu = acrn_get_tsc_khz;
|
||||
}
|
||||
|
||||
static bool acrn_x2apic_available(void)
|
||||
|
||||
@@ -29,15 +29,26 @@
|
||||
void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err)
|
||||
{
|
||||
struct mce m;
|
||||
int lsb;
|
||||
|
||||
if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Even if the ->validation_bits are set for address mask,
|
||||
* to be extra safe, check and reject an error radius '0',
|
||||
* and fall back to the default page size.
|
||||
*/
|
||||
if (mem_err->validation_bits & CPER_MEM_VALID_PA_MASK)
|
||||
lsb = find_first_bit((void *)&mem_err->physical_addr_mask, PAGE_SHIFT);
|
||||
else
|
||||
lsb = PAGE_SHIFT;
|
||||
|
||||
mce_setup(&m);
|
||||
m.bank = -1;
|
||||
/* Fake a memory read error with unknown channel */
|
||||
m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | MCI_STATUS_MISCV | 0x9f;
|
||||
m.misc = (MCI_MISC_ADDR_PHYS << 6) | PAGE_SHIFT;
|
||||
m.misc = (MCI_MISC_ADDR_PHYS << 6) | lsb;
|
||||
|
||||
if (severity >= GHES_SEV_RECOVERABLE)
|
||||
m.status |= MCI_STATUS_UC;
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include "encls.h"
|
||||
#include "sgx.h"
|
||||
|
||||
static int sgx_encl_lookup_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
struct sgx_backing *backing);
|
||||
|
||||
#define PCMDS_PER_PAGE (PAGE_SIZE / sizeof(struct sgx_pcmd))
|
||||
/*
|
||||
* 32 PCMD entries share a PCMD page. PCMD_FIRST_MASK is used to
|
||||
@@ -917,7 +920,7 @@ static struct page *sgx_encl_get_backing_page(struct sgx_encl *encl,
|
||||
}
|
||||
|
||||
/**
|
||||
* sgx_encl_get_backing() - Pin the backing storage
|
||||
* __sgx_encl_get_backing() - Pin the backing storage
|
||||
* @encl: an enclave pointer
|
||||
* @page_index: enclave page index
|
||||
* @backing: data for accessing backing storage for the page
|
||||
@@ -929,7 +932,7 @@ static struct page *sgx_encl_get_backing_page(struct sgx_encl *encl,
|
||||
* 0 on success,
|
||||
* -errno otherwise.
|
||||
*/
|
||||
static int sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
static int __sgx_encl_get_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
struct sgx_backing *backing)
|
||||
{
|
||||
pgoff_t page_pcmd_off = sgx_encl_get_backing_page_pcmd_offset(encl, page_index);
|
||||
@@ -1004,7 +1007,7 @@ static struct mem_cgroup *sgx_encl_get_mem_cgroup(struct sgx_encl *encl)
|
||||
}
|
||||
|
||||
/**
|
||||
* sgx_encl_alloc_backing() - allocate a new backing storage page
|
||||
* sgx_encl_alloc_backing() - create a new backing storage page
|
||||
* @encl: an enclave pointer
|
||||
* @page_index: enclave page index
|
||||
* @backing: data for accessing backing storage for the page
|
||||
@@ -1012,7 +1015,9 @@ static struct mem_cgroup *sgx_encl_get_mem_cgroup(struct sgx_encl *encl)
|
||||
* When called from ksgxd, sets the active memcg from one of the
|
||||
* mms in the enclave's mm_list prior to any backing page allocation,
|
||||
* in order to ensure that shmem page allocations are charged to the
|
||||
* enclave.
|
||||
* enclave. Create a backing page for loading data back into an EPC page with
|
||||
* ELDU. This function takes a reference on a new backing page which
|
||||
* must be dropped with a corresponding call to sgx_encl_put_backing().
|
||||
*
|
||||
* Return:
|
||||
* 0 on success,
|
||||
@@ -1025,7 +1030,7 @@ int sgx_encl_alloc_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
struct mem_cgroup *memcg = set_active_memcg(encl_memcg);
|
||||
int ret;
|
||||
|
||||
ret = sgx_encl_get_backing(encl, page_index, backing);
|
||||
ret = __sgx_encl_get_backing(encl, page_index, backing);
|
||||
|
||||
set_active_memcg(memcg);
|
||||
mem_cgroup_put(encl_memcg);
|
||||
@@ -1043,15 +1048,17 @@ int sgx_encl_alloc_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
* It is the caller's responsibility to ensure that it is appropriate to use
|
||||
* sgx_encl_lookup_backing() rather than sgx_encl_alloc_backing(). If lookup is
|
||||
* not used correctly, this will cause an allocation which is not accounted for.
|
||||
* This function takes a reference on an existing backing page which must be
|
||||
* dropped with a corresponding call to sgx_encl_put_backing().
|
||||
*
|
||||
* Return:
|
||||
* 0 on success,
|
||||
* -errno otherwise.
|
||||
*/
|
||||
int sgx_encl_lookup_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
static int sgx_encl_lookup_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
struct sgx_backing *backing)
|
||||
{
|
||||
return sgx_encl_get_backing(encl, page_index, backing);
|
||||
return __sgx_encl_get_backing(encl, page_index, backing);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -107,8 +107,6 @@ bool current_is_ksgxd(void);
|
||||
void sgx_encl_release(struct kref *ref);
|
||||
int sgx_encl_mm_add(struct sgx_encl *encl, struct mm_struct *mm);
|
||||
const cpumask_t *sgx_encl_cpumask(struct sgx_encl *encl);
|
||||
int sgx_encl_lookup_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
struct sgx_backing *backing);
|
||||
int sgx_encl_alloc_backing(struct sgx_encl *encl, unsigned long page_index,
|
||||
struct sgx_backing *backing);
|
||||
void sgx_encl_put_backing(struct sgx_backing *backing);
|
||||
|
||||
@@ -128,7 +128,7 @@ void show_opcodes(struct pt_regs *regs, const char *loglvl)
|
||||
/* No access to the user space stack of other tasks. Ignore. */
|
||||
break;
|
||||
default:
|
||||
printk("%sCode: Unable to access opcode bytes at RIP 0x%lx.\n",
|
||||
printk("%sCode: Unable to access opcode bytes at 0x%lx.\n",
|
||||
loglvl, prologue);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -264,11 +264,11 @@ static __init void early_pci_serial_init(char *s)
|
||||
bar0 = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
|
||||
|
||||
/*
|
||||
* Verify it is a UART type device
|
||||
* Verify it is a 16550-UART type device
|
||||
*/
|
||||
if (((classcode >> 16 != PCI_CLASS_COMMUNICATION_MODEM) &&
|
||||
(classcode >> 16 != PCI_CLASS_COMMUNICATION_SERIAL)) ||
|
||||
(((classcode >> 8) & 0xff) != 0x02)) /* 16550 I/F at BAR0 */ {
|
||||
(((classcode >> 8) & 0xff) != PCI_SERIAL_16550_COMPATIBLE)) {
|
||||
if (!force)
|
||||
return;
|
||||
}
|
||||
@@ -276,22 +276,22 @@ static __init void early_pci_serial_init(char *s)
|
||||
/*
|
||||
* Determine if it is IO or memory mapped
|
||||
*/
|
||||
if (bar0 & 0x01) {
|
||||
if ((bar0 & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
/* it is IO mapped */
|
||||
serial_in = io_serial_in;
|
||||
serial_out = io_serial_out;
|
||||
early_serial_base = bar0&0xfffffffc;
|
||||
early_serial_base = bar0 & PCI_BASE_ADDRESS_IO_MASK;
|
||||
write_pci_config(bus, slot, func, PCI_COMMAND,
|
||||
cmdreg|PCI_COMMAND_IO);
|
||||
cmdreg|PCI_COMMAND_IO);
|
||||
} else {
|
||||
/* It is memory mapped - assume 32-bit alignment */
|
||||
serial_in = mem32_serial_in;
|
||||
serial_out = mem32_serial_out;
|
||||
/* WARNING! assuming the address is always in the first 4G */
|
||||
early_serial_base =
|
||||
(unsigned long)early_ioremap(bar0 & 0xfffffff0, 0x10);
|
||||
(unsigned long)early_ioremap(bar0 & PCI_BASE_ADDRESS_MEM_MASK, 0x10);
|
||||
write_pci_config(bus, slot, func, PCI_COMMAND,
|
||||
cmdreg|PCI_COMMAND_MEMORY);
|
||||
cmdreg|PCI_COMMAND_MEMORY);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+9
-54
@@ -4,11 +4,8 @@
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <asm/vsyscall.h>
|
||||
#include <asm/x86_init.h>
|
||||
@@ -20,26 +17,23 @@
|
||||
/*
|
||||
* This is a special lock that is owned by the CPU and holds the index
|
||||
* register we are working with. It is required for NMI access to the
|
||||
* CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details.
|
||||
* CMOS/RTC registers. See arch/x86/include/asm/mc146818rtc.h for details.
|
||||
*/
|
||||
volatile unsigned long cmos_lock;
|
||||
EXPORT_SYMBOL(cmos_lock);
|
||||
#endif /* CONFIG_X86_32 */
|
||||
|
||||
/* For two digit years assume time is always after that */
|
||||
#define CMOS_YEARS_OFFS 2000
|
||||
|
||||
DEFINE_SPINLOCK(rtc_lock);
|
||||
EXPORT_SYMBOL(rtc_lock);
|
||||
|
||||
/*
|
||||
* In order to set the CMOS clock precisely, set_rtc_mmss has to be
|
||||
* In order to set the CMOS clock precisely, mach_set_cmos_time has to be
|
||||
* called 500 ms after the second nowtime has started, because when
|
||||
* nowtime is written into the registers of the CMOS clock, it will
|
||||
* jump to the next second precisely 500 ms later. Check the Motorola
|
||||
* MC146818A or Dallas DS12887 data sheet for details.
|
||||
*/
|
||||
int mach_set_rtc_mmss(const struct timespec64 *now)
|
||||
int mach_set_cmos_time(const struct timespec64 *now)
|
||||
{
|
||||
unsigned long long nowtime = now->tv_sec;
|
||||
struct rtc_time tm;
|
||||
@@ -62,8 +56,7 @@ int mach_set_rtc_mmss(const struct timespec64 *now)
|
||||
|
||||
void mach_get_cmos_time(struct timespec64 *now)
|
||||
{
|
||||
unsigned int status, year, mon, day, hour, min, sec, century = 0;
|
||||
unsigned long flags;
|
||||
struct rtc_time tm;
|
||||
|
||||
/*
|
||||
* If pm_trace abused the RTC as storage, set the timespec to 0,
|
||||
@@ -74,51 +67,13 @@ void mach_get_cmos_time(struct timespec64 *now)
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
|
||||
/*
|
||||
* If UIP is clear, then we have >= 244 microseconds before
|
||||
* RTC registers will be updated. Spec sheet says that this
|
||||
* is the reliable way to read RTC - registers. If UIP is set
|
||||
* then the register access might be invalid.
|
||||
*/
|
||||
while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
|
||||
cpu_relax();
|
||||
|
||||
sec = CMOS_READ(RTC_SECONDS);
|
||||
min = CMOS_READ(RTC_MINUTES);
|
||||
hour = CMOS_READ(RTC_HOURS);
|
||||
day = CMOS_READ(RTC_DAY_OF_MONTH);
|
||||
mon = CMOS_READ(RTC_MONTH);
|
||||
year = CMOS_READ(RTC_YEAR);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
|
||||
acpi_gbl_FADT.century)
|
||||
century = CMOS_READ(acpi_gbl_FADT.century);
|
||||
#endif
|
||||
|
||||
status = CMOS_READ(RTC_CONTROL);
|
||||
WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY));
|
||||
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
||||
if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) {
|
||||
sec = bcd2bin(sec);
|
||||
min = bcd2bin(min);
|
||||
hour = bcd2bin(hour);
|
||||
day = bcd2bin(day);
|
||||
mon = bcd2bin(mon);
|
||||
year = bcd2bin(year);
|
||||
if (mc146818_get_time(&tm)) {
|
||||
pr_err("Unable to read current time from RTC\n");
|
||||
now->tv_sec = now->tv_nsec = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (century) {
|
||||
century = bcd2bin(century);
|
||||
year += century * 100;
|
||||
} else
|
||||
year += CMOS_YEARS_OFFS;
|
||||
|
||||
now->tv_sec = mktime64(year, mon, day, hour, min, sec);
|
||||
now->tv_sec = rtc_tm_to_time64(&tm);
|
||||
now->tv_nsec = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ struct x86_platform_ops x86_platform __ro_after_init = {
|
||||
.calibrate_cpu = native_calibrate_cpu_early,
|
||||
.calibrate_tsc = native_calibrate_tsc,
|
||||
.get_wallclock = mach_get_cmos_time,
|
||||
.set_wallclock = mach_set_rtc_mmss,
|
||||
.set_wallclock = mach_set_cmos_time,
|
||||
.iommu_shutdown = iommu_shutdown_noop,
|
||||
.is_untracked_pat_range = is_ISA_range,
|
||||
.nmi_init = default_nmi_init,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/export.h>
|
||||
|
||||
/*
|
||||
@@ -50,3 +51,140 @@ SYM_FUNC_START(clear_page_erms)
|
||||
RET
|
||||
SYM_FUNC_END(clear_page_erms)
|
||||
EXPORT_SYMBOL_GPL(clear_page_erms)
|
||||
|
||||
/*
|
||||
* Default clear user-space.
|
||||
* Input:
|
||||
* rdi destination
|
||||
* rcx count
|
||||
*
|
||||
* Output:
|
||||
* rcx: uncleared bytes or 0 if successful.
|
||||
*/
|
||||
SYM_FUNC_START(clear_user_original)
|
||||
/*
|
||||
* Copy only the lower 32 bits of size as that is enough to handle the rest bytes,
|
||||
* i.e., no need for a 'q' suffix and thus a REX prefix.
|
||||
*/
|
||||
mov %ecx,%eax
|
||||
shr $3,%rcx
|
||||
jz .Lrest_bytes
|
||||
|
||||
# do the qwords first
|
||||
.p2align 4
|
||||
.Lqwords:
|
||||
movq $0,(%rdi)
|
||||
lea 8(%rdi),%rdi
|
||||
dec %rcx
|
||||
jnz .Lqwords
|
||||
|
||||
.Lrest_bytes:
|
||||
and $7, %eax
|
||||
jz .Lexit
|
||||
|
||||
# now do the rest bytes
|
||||
.Lbytes:
|
||||
movb $0,(%rdi)
|
||||
inc %rdi
|
||||
dec %eax
|
||||
jnz .Lbytes
|
||||
|
||||
.Lexit:
|
||||
/*
|
||||
* %rax still needs to be cleared in the exception case because this function is called
|
||||
* from inline asm and the compiler expects %rax to be zero when exiting the inline asm,
|
||||
* in case it might reuse it somewhere.
|
||||
*/
|
||||
xor %eax,%eax
|
||||
RET
|
||||
|
||||
.Lqwords_exception:
|
||||
# convert remaining qwords back into bytes to return to caller
|
||||
shl $3, %rcx
|
||||
and $7, %eax
|
||||
add %rax,%rcx
|
||||
jmp .Lexit
|
||||
|
||||
.Lbytes_exception:
|
||||
mov %eax,%ecx
|
||||
jmp .Lexit
|
||||
|
||||
_ASM_EXTABLE_UA(.Lqwords, .Lqwords_exception)
|
||||
_ASM_EXTABLE_UA(.Lbytes, .Lbytes_exception)
|
||||
SYM_FUNC_END(clear_user_original)
|
||||
EXPORT_SYMBOL(clear_user_original)
|
||||
|
||||
/*
|
||||
* Alternative clear user-space when CPU feature X86_FEATURE_REP_GOOD is
|
||||
* present.
|
||||
* Input:
|
||||
* rdi destination
|
||||
* rcx count
|
||||
*
|
||||
* Output:
|
||||
* rcx: uncleared bytes or 0 if successful.
|
||||
*/
|
||||
SYM_FUNC_START(clear_user_rep_good)
|
||||
# call the original thing for less than a cacheline
|
||||
cmp $64, %rcx
|
||||
jb clear_user_original
|
||||
|
||||
.Lprep:
|
||||
# copy lower 32-bits for rest bytes
|
||||
mov %ecx, %edx
|
||||
shr $3, %rcx
|
||||
jz .Lrep_good_rest_bytes
|
||||
|
||||
.Lrep_good_qwords:
|
||||
rep stosq
|
||||
|
||||
.Lrep_good_rest_bytes:
|
||||
and $7, %edx
|
||||
jz .Lrep_good_exit
|
||||
|
||||
.Lrep_good_bytes:
|
||||
mov %edx, %ecx
|
||||
rep stosb
|
||||
|
||||
.Lrep_good_exit:
|
||||
# see .Lexit comment above
|
||||
xor %eax, %eax
|
||||
RET
|
||||
|
||||
.Lrep_good_qwords_exception:
|
||||
# convert remaining qwords back into bytes to return to caller
|
||||
shl $3, %rcx
|
||||
and $7, %edx
|
||||
add %rdx, %rcx
|
||||
jmp .Lrep_good_exit
|
||||
|
||||
_ASM_EXTABLE_UA(.Lrep_good_qwords, .Lrep_good_qwords_exception)
|
||||
_ASM_EXTABLE_UA(.Lrep_good_bytes, .Lrep_good_exit)
|
||||
SYM_FUNC_END(clear_user_rep_good)
|
||||
EXPORT_SYMBOL(clear_user_rep_good)
|
||||
|
||||
/*
|
||||
* Alternative clear user-space when CPU feature X86_FEATURE_ERMS is present.
|
||||
* Input:
|
||||
* rdi destination
|
||||
* rcx count
|
||||
*
|
||||
* Output:
|
||||
* rcx: uncleared bytes or 0 if successful.
|
||||
*
|
||||
*/
|
||||
SYM_FUNC_START(clear_user_erms)
|
||||
# call the original thing for less than a cacheline
|
||||
cmp $64, %rcx
|
||||
jb clear_user_original
|
||||
|
||||
.Lerms_bytes:
|
||||
rep stosb
|
||||
|
||||
.Lerms_exit:
|
||||
xorl %eax,%eax
|
||||
RET
|
||||
|
||||
_ASM_EXTABLE_UA(.Lerms_bytes, .Lerms_exit)
|
||||
SYM_FUNC_END(clear_user_erms)
|
||||
EXPORT_SYMBOL(clear_user_erms)
|
||||
|
||||
@@ -14,46 +14,6 @@
|
||||
* Zero Userspace
|
||||
*/
|
||||
|
||||
unsigned long __clear_user(void __user *addr, unsigned long size)
|
||||
{
|
||||
long __d0;
|
||||
might_fault();
|
||||
/* no memory constraint because it doesn't change any memory gcc knows
|
||||
about */
|
||||
stac();
|
||||
asm volatile(
|
||||
" testq %[size8],%[size8]\n"
|
||||
" jz 4f\n"
|
||||
" .align 16\n"
|
||||
"0: movq $0,(%[dst])\n"
|
||||
" addq $8,%[dst]\n"
|
||||
" decl %%ecx ; jnz 0b\n"
|
||||
"4: movq %[size1],%%rcx\n"
|
||||
" testl %%ecx,%%ecx\n"
|
||||
" jz 2f\n"
|
||||
"1: movb $0,(%[dst])\n"
|
||||
" incq %[dst]\n"
|
||||
" decl %%ecx ; jnz 1b\n"
|
||||
"2:\n"
|
||||
|
||||
_ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN8, %[size1])
|
||||
_ASM_EXTABLE_UA(1b, 2b)
|
||||
|
||||
: [size8] "=&c"(size), [dst] "=&D" (__d0)
|
||||
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr));
|
||||
clac();
|
||||
return size;
|
||||
}
|
||||
EXPORT_SYMBOL(__clear_user);
|
||||
|
||||
unsigned long clear_user(void __user *to, unsigned long n)
|
||||
{
|
||||
if (access_ok(to, n))
|
||||
return __clear_user(to, n);
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL(clear_user);
|
||||
|
||||
#ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE
|
||||
/**
|
||||
* clean_cache_range - write back a cache range with CLWB
|
||||
|
||||
@@ -769,6 +769,8 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
|
||||
unsigned long address, struct task_struct *tsk)
|
||||
{
|
||||
const char *loglvl = task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG;
|
||||
/* This is a racy snapshot, but it's better than nothing. */
|
||||
int cpu = raw_smp_processor_id();
|
||||
|
||||
if (!unhandled_signal(tsk, SIGSEGV))
|
||||
return;
|
||||
@@ -782,6 +784,14 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
|
||||
|
||||
print_vma_addr(KERN_CONT " in ", regs->ip);
|
||||
|
||||
/*
|
||||
* Dump the likely CPU where the fatal segfault happened.
|
||||
* This can help identify faulty hardware.
|
||||
*/
|
||||
printk(KERN_CONT " likely on CPU %d (core %d, socket %d)", cpu,
|
||||
topology_core_id(cpu), topology_physical_package_id(cpu));
|
||||
|
||||
|
||||
printk(KERN_CONT "\n");
|
||||
|
||||
show_opcodes(regs, loglvl);
|
||||
|
||||
@@ -419,7 +419,9 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
|
||||
OPTIMIZER_HIDE_VAR(reg);
|
||||
emit_jump(&prog, &__x86_indirect_thunk_array[reg], ip);
|
||||
} else {
|
||||
EMIT2(0xFF, 0xE0 + reg);
|
||||
EMIT2(0xFF, 0xE0 + reg); /* jmp *%\reg */
|
||||
if (IS_ENABLED(CONFIG_RETPOLINE) || IS_ENABLED(CONFIG_SLS))
|
||||
EMIT1(0xCC); /* int3 */
|
||||
}
|
||||
|
||||
*pprog = prog;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/namei.h>
|
||||
#include <linux/part_stat.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/stat.h>
|
||||
#include "../fs/internal.h"
|
||||
#include "blk.h"
|
||||
|
||||
@@ -1069,3 +1070,25 @@ void sync_bdevs(bool wait)
|
||||
spin_unlock(&blockdev_superblock->s_inode_list_lock);
|
||||
iput(old_inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle STATX_DIOALIGN for block devices.
|
||||
*
|
||||
* Note that the inode passed to this is the inode of a block device node file,
|
||||
* not the block device's internal inode. Therefore it is *not* valid to use
|
||||
* I_BDEV() here; the block device has to be looked up by i_rdev instead.
|
||||
*/
|
||||
void bdev_statx_dioalign(struct inode *inode, struct kstat *stat)
|
||||
{
|
||||
struct block_device *bdev;
|
||||
|
||||
bdev = blkdev_get_no_open(inode->i_rdev);
|
||||
if (!bdev)
|
||||
return;
|
||||
|
||||
stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
|
||||
stat->dio_offset_align = bdev_logical_block_size(bdev);
|
||||
stat->result_mask |= STATX_DIOALIGN;
|
||||
|
||||
blkdev_put_no_open(bdev);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,6 @@ static void edac_mc_dump_dimm(struct dimm_info *dimm)
|
||||
edac_dbg(4, " dimm->label = '%s'\n", dimm->label);
|
||||
edac_dbg(4, " dimm->nr_pages = 0x%x\n", dimm->nr_pages);
|
||||
edac_dbg(4, " dimm->grain = %d\n", dimm->grain);
|
||||
edac_dbg(4, " dimm->nr_pages = 0x%x\n", dimm->nr_pages);
|
||||
}
|
||||
|
||||
static void edac_mc_dump_csrow(struct csrow_info *csrow)
|
||||
|
||||
@@ -28,13 +28,9 @@ void edac_mc_sysfs_exit(void);
|
||||
extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
|
||||
const struct attribute_group **groups);
|
||||
extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
|
||||
extern int edac_get_log_ue(void);
|
||||
extern int edac_get_log_ce(void);
|
||||
extern int edac_get_panic_on_ue(void);
|
||||
extern int edac_mc_get_log_ue(void);
|
||||
extern int edac_mc_get_log_ce(void);
|
||||
extern int edac_mc_get_panic_on_ue(void);
|
||||
extern int edac_get_poll_msec(void);
|
||||
extern unsigned int edac_mc_get_poll_msec(void);
|
||||
|
||||
unsigned edac_dimm_info_location(struct dimm_info *dimm, char *buf,
|
||||
|
||||
+263
-24
@@ -74,31 +74,47 @@ static struct list_head *i10nm_edac_list;
|
||||
|
||||
static struct res_config *res_cfg;
|
||||
static int retry_rd_err_log;
|
||||
static int decoding_via_mca;
|
||||
static bool mem_cfg_2lm;
|
||||
|
||||
static u32 offsets_scrub_icx[] = {0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8};
|
||||
static u32 offsets_scrub_spr[] = {0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8};
|
||||
static u32 offsets_scrub_spr_hbm0[] = {0x2860, 0x2854, 0x2b08, 0x2858, 0x2828, 0x0ed8};
|
||||
static u32 offsets_scrub_spr_hbm1[] = {0x2c60, 0x2c54, 0x2f08, 0x2c58, 0x2c28, 0x0fa8};
|
||||
static u32 offsets_demand_icx[] = {0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0};
|
||||
static u32 offsets_demand_spr[] = {0x22e54, 0x22e60, 0x22f10, 0x22e58, 0x22e5c, 0x20ee0};
|
||||
static u32 offsets_demand2_spr[] = {0x22c70, 0x22d80, 0x22f18, 0x22d58, 0x22c64, 0x20f10};
|
||||
static u32 offsets_demand_spr_hbm0[] = {0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0};
|
||||
static u32 offsets_demand_spr_hbm1[] = {0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0};
|
||||
|
||||
static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable)
|
||||
static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable,
|
||||
u32 *offsets_scrub, u32 *offsets_demand,
|
||||
u32 *offsets_demand2)
|
||||
{
|
||||
u32 s, d;
|
||||
u32 s, d, d2;
|
||||
|
||||
if (!imc->mbase)
|
||||
return;
|
||||
|
||||
s = I10NM_GET_REG32(imc, chan, res_cfg->offsets_scrub[0]);
|
||||
d = I10NM_GET_REG32(imc, chan, res_cfg->offsets_demand[0]);
|
||||
s = I10NM_GET_REG32(imc, chan, offsets_scrub[0]);
|
||||
d = I10NM_GET_REG32(imc, chan, offsets_demand[0]);
|
||||
if (offsets_demand2)
|
||||
d2 = I10NM_GET_REG32(imc, chan, offsets_demand2[0]);
|
||||
|
||||
if (enable) {
|
||||
/* Save default configurations */
|
||||
imc->chan[chan].retry_rd_err_log_s = s;
|
||||
imc->chan[chan].retry_rd_err_log_d = d;
|
||||
if (offsets_demand2)
|
||||
imc->chan[chan].retry_rd_err_log_d2 = d2;
|
||||
|
||||
s &= ~RETRY_RD_ERR_LOG_NOOVER_UC;
|
||||
s |= RETRY_RD_ERR_LOG_EN;
|
||||
d &= ~RETRY_RD_ERR_LOG_NOOVER_UC;
|
||||
d |= RETRY_RD_ERR_LOG_EN;
|
||||
|
||||
if (offsets_demand2) {
|
||||
d2 &= ~RETRY_RD_ERR_LOG_UC;
|
||||
d2 |= RETRY_RD_ERR_LOG_NOOVER;
|
||||
d2 |= RETRY_RD_ERR_LOG_EN;
|
||||
}
|
||||
} else {
|
||||
/* Restore default configurations */
|
||||
if (imc->chan[chan].retry_rd_err_log_s & RETRY_RD_ERR_LOG_UC)
|
||||
@@ -113,23 +129,55 @@ static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable
|
||||
d |= RETRY_RD_ERR_LOG_NOOVER;
|
||||
if (!(imc->chan[chan].retry_rd_err_log_d & RETRY_RD_ERR_LOG_EN))
|
||||
d &= ~RETRY_RD_ERR_LOG_EN;
|
||||
|
||||
if (offsets_demand2) {
|
||||
if (imc->chan[chan].retry_rd_err_log_d2 & RETRY_RD_ERR_LOG_UC)
|
||||
d2 |= RETRY_RD_ERR_LOG_UC;
|
||||
if (!(imc->chan[chan].retry_rd_err_log_d2 & RETRY_RD_ERR_LOG_NOOVER))
|
||||
d2 &= ~RETRY_RD_ERR_LOG_NOOVER;
|
||||
if (!(imc->chan[chan].retry_rd_err_log_d2 & RETRY_RD_ERR_LOG_EN))
|
||||
d2 &= ~RETRY_RD_ERR_LOG_EN;
|
||||
}
|
||||
}
|
||||
|
||||
I10NM_SET_REG32(imc, chan, res_cfg->offsets_scrub[0], s);
|
||||
I10NM_SET_REG32(imc, chan, res_cfg->offsets_demand[0], d);
|
||||
I10NM_SET_REG32(imc, chan, offsets_scrub[0], s);
|
||||
I10NM_SET_REG32(imc, chan, offsets_demand[0], d);
|
||||
if (offsets_demand2)
|
||||
I10NM_SET_REG32(imc, chan, offsets_demand2[0], d2);
|
||||
}
|
||||
|
||||
static void enable_retry_rd_err_log(bool enable)
|
||||
{
|
||||
struct skx_imc *imc;
|
||||
struct skx_dev *d;
|
||||
int i, j;
|
||||
|
||||
edac_dbg(2, "\n");
|
||||
|
||||
list_for_each_entry(d, i10nm_edac_list, list)
|
||||
for (i = 0; i < I10NM_NUM_IMC; i++)
|
||||
for (j = 0; j < I10NM_NUM_CHANNELS; j++)
|
||||
__enable_retry_rd_err_log(&d->imc[i], j, enable);
|
||||
for (i = 0; i < I10NM_NUM_IMC; i++) {
|
||||
imc = &d->imc[i];
|
||||
if (!imc->mbase)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < I10NM_NUM_CHANNELS; j++) {
|
||||
if (imc->hbm_mc) {
|
||||
__enable_retry_rd_err_log(imc, j, enable,
|
||||
res_cfg->offsets_scrub_hbm0,
|
||||
res_cfg->offsets_demand_hbm0,
|
||||
NULL);
|
||||
__enable_retry_rd_err_log(imc, j, enable,
|
||||
res_cfg->offsets_scrub_hbm1,
|
||||
res_cfg->offsets_demand_hbm1,
|
||||
NULL);
|
||||
} else {
|
||||
__enable_retry_rd_err_log(imc, j, enable,
|
||||
res_cfg->offsets_scrub,
|
||||
res_cfg->offsets_demand,
|
||||
res_cfg->offsets_demand2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
|
||||
@@ -138,14 +186,33 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
|
||||
struct skx_imc *imc = &res->dev->imc[res->imc];
|
||||
u32 log0, log1, log2, log3, log4;
|
||||
u32 corr0, corr1, corr2, corr3;
|
||||
u32 lxg0, lxg1, lxg3, lxg4;
|
||||
u32 *xffsets = NULL;
|
||||
u64 log2a, log5;
|
||||
u64 lxg2a, lxg5;
|
||||
u32 *offsets;
|
||||
int n;
|
||||
int n, pch;
|
||||
|
||||
if (!imc->mbase)
|
||||
return;
|
||||
|
||||
offsets = scrub_err ? res_cfg->offsets_scrub : res_cfg->offsets_demand;
|
||||
if (imc->hbm_mc) {
|
||||
pch = res->cs & 1;
|
||||
|
||||
if (pch)
|
||||
offsets = scrub_err ? res_cfg->offsets_scrub_hbm1 :
|
||||
res_cfg->offsets_demand_hbm1;
|
||||
else
|
||||
offsets = scrub_err ? res_cfg->offsets_scrub_hbm0 :
|
||||
res_cfg->offsets_demand_hbm0;
|
||||
} else {
|
||||
if (scrub_err) {
|
||||
offsets = res_cfg->offsets_scrub;
|
||||
} else {
|
||||
offsets = res_cfg->offsets_demand;
|
||||
xffsets = res_cfg->offsets_demand2;
|
||||
}
|
||||
}
|
||||
|
||||
log0 = I10NM_GET_REG32(imc, res->channel, offsets[0]);
|
||||
log1 = I10NM_GET_REG32(imc, res->channel, offsets[1]);
|
||||
@@ -153,20 +220,52 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
|
||||
log4 = I10NM_GET_REG32(imc, res->channel, offsets[4]);
|
||||
log5 = I10NM_GET_REG64(imc, res->channel, offsets[5]);
|
||||
|
||||
if (xffsets) {
|
||||
lxg0 = I10NM_GET_REG32(imc, res->channel, xffsets[0]);
|
||||
lxg1 = I10NM_GET_REG32(imc, res->channel, xffsets[1]);
|
||||
lxg3 = I10NM_GET_REG32(imc, res->channel, xffsets[3]);
|
||||
lxg4 = I10NM_GET_REG32(imc, res->channel, xffsets[4]);
|
||||
lxg5 = I10NM_GET_REG64(imc, res->channel, xffsets[5]);
|
||||
}
|
||||
|
||||
if (res_cfg->type == SPR) {
|
||||
log2a = I10NM_GET_REG64(imc, res->channel, offsets[2]);
|
||||
n = snprintf(msg, len, " retry_rd_err_log[%.8x %.8x %.16llx %.8x %.8x %.16llx]",
|
||||
n = snprintf(msg, len, " retry_rd_err_log[%.8x %.8x %.16llx %.8x %.8x %.16llx",
|
||||
log0, log1, log2a, log3, log4, log5);
|
||||
|
||||
if (len - n > 0) {
|
||||
if (xffsets) {
|
||||
lxg2a = I10NM_GET_REG64(imc, res->channel, xffsets[2]);
|
||||
n += snprintf(msg + n, len - n, " %.8x %.8x %.16llx %.8x %.8x %.16llx]",
|
||||
lxg0, lxg1, lxg2a, lxg3, lxg4, lxg5);
|
||||
} else {
|
||||
n += snprintf(msg + n, len - n, "]");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log2 = I10NM_GET_REG32(imc, res->channel, offsets[2]);
|
||||
n = snprintf(msg, len, " retry_rd_err_log[%.8x %.8x %.8x %.8x %.8x %.16llx]",
|
||||
log0, log1, log2, log3, log4, log5);
|
||||
}
|
||||
|
||||
corr0 = I10NM_GET_REG32(imc, res->channel, 0x22c18);
|
||||
corr1 = I10NM_GET_REG32(imc, res->channel, 0x22c1c);
|
||||
corr2 = I10NM_GET_REG32(imc, res->channel, 0x22c20);
|
||||
corr3 = I10NM_GET_REG32(imc, res->channel, 0x22c24);
|
||||
if (imc->hbm_mc) {
|
||||
if (pch) {
|
||||
corr0 = I10NM_GET_REG32(imc, res->channel, 0x2c18);
|
||||
corr1 = I10NM_GET_REG32(imc, res->channel, 0x2c1c);
|
||||
corr2 = I10NM_GET_REG32(imc, res->channel, 0x2c20);
|
||||
corr3 = I10NM_GET_REG32(imc, res->channel, 0x2c24);
|
||||
} else {
|
||||
corr0 = I10NM_GET_REG32(imc, res->channel, 0x2818);
|
||||
corr1 = I10NM_GET_REG32(imc, res->channel, 0x281c);
|
||||
corr2 = I10NM_GET_REG32(imc, res->channel, 0x2820);
|
||||
corr3 = I10NM_GET_REG32(imc, res->channel, 0x2824);
|
||||
}
|
||||
} else {
|
||||
corr0 = I10NM_GET_REG32(imc, res->channel, 0x22c18);
|
||||
corr1 = I10NM_GET_REG32(imc, res->channel, 0x22c1c);
|
||||
corr2 = I10NM_GET_REG32(imc, res->channel, 0x22c20);
|
||||
corr3 = I10NM_GET_REG32(imc, res->channel, 0x22c24);
|
||||
}
|
||||
|
||||
if (len - n > 0)
|
||||
snprintf(msg + n, len - n,
|
||||
@@ -177,9 +276,16 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
|
||||
corr3 & 0xffff, corr3 >> 16);
|
||||
|
||||
/* Clear status bits */
|
||||
if (retry_rd_err_log == 2 && (log0 & RETRY_RD_ERR_LOG_OVER_UC_V)) {
|
||||
log0 &= ~RETRY_RD_ERR_LOG_OVER_UC_V;
|
||||
I10NM_SET_REG32(imc, res->channel, offsets[0], log0);
|
||||
if (retry_rd_err_log == 2) {
|
||||
if (log0 & RETRY_RD_ERR_LOG_OVER_UC_V) {
|
||||
log0 &= ~RETRY_RD_ERR_LOG_OVER_UC_V;
|
||||
I10NM_SET_REG32(imc, res->channel, offsets[0], log0);
|
||||
}
|
||||
|
||||
if (xffsets && (lxg0 & RETRY_RD_ERR_LOG_OVER_UC_V)) {
|
||||
lxg0 &= ~RETRY_RD_ERR_LOG_OVER_UC_V;
|
||||
I10NM_SET_REG32(imc, res->channel, xffsets[0], lxg0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +337,103 @@ static bool i10nm_check_2lm(struct res_config *cfg)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the error comes from DDRT by ICX/Tremont model specific error code.
|
||||
* Refer to SDM vol3B 16.11.3 Intel IMC MC error codes for IA32_MCi_STATUS.
|
||||
*/
|
||||
static bool i10nm_mscod_is_ddrt(u32 mscod)
|
||||
{
|
||||
switch (mscod) {
|
||||
case 0x0106: case 0x0107:
|
||||
case 0x0800: case 0x0804:
|
||||
case 0x0806 ... 0x0808:
|
||||
case 0x080a ... 0x080e:
|
||||
case 0x0810: case 0x0811:
|
||||
case 0x0816: case 0x081e:
|
||||
case 0x081f:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool i10nm_mc_decode_available(struct mce *mce)
|
||||
{
|
||||
u8 bank;
|
||||
|
||||
if (!decoding_via_mca || mem_cfg_2lm)
|
||||
return false;
|
||||
|
||||
if ((mce->status & (MCI_STATUS_MISCV | MCI_STATUS_ADDRV))
|
||||
!= (MCI_STATUS_MISCV | MCI_STATUS_ADDRV))
|
||||
return false;
|
||||
|
||||
bank = mce->bank;
|
||||
|
||||
switch (res_cfg->type) {
|
||||
case I10NM:
|
||||
if (bank < 13 || bank > 26)
|
||||
return false;
|
||||
|
||||
/* DDRT errors can't be decoded from MCA bank registers */
|
||||
if (MCI_MISC_ECC_MODE(mce->misc) == MCI_MISC_ECC_DDRT)
|
||||
return false;
|
||||
|
||||
if (i10nm_mscod_is_ddrt(MCI_STATUS_MSCOD(mce->status)))
|
||||
return false;
|
||||
|
||||
/* Check whether one of {13,14,17,18,21,22,25,26} */
|
||||
return ((bank - 13) & BIT(1)) == 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool i10nm_mc_decode(struct decoded_addr *res)
|
||||
{
|
||||
struct mce *m = res->mce;
|
||||
struct skx_dev *d;
|
||||
u8 bank;
|
||||
|
||||
if (!i10nm_mc_decode_available(m))
|
||||
return false;
|
||||
|
||||
list_for_each_entry(d, i10nm_edac_list, list) {
|
||||
if (d->imc[0].src_id == m->socketid) {
|
||||
res->socket = m->socketid;
|
||||
res->dev = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (res_cfg->type) {
|
||||
case I10NM:
|
||||
bank = m->bank - 13;
|
||||
res->imc = bank / 4;
|
||||
res->channel = bank % 2;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!res->dev) {
|
||||
skx_printk(KERN_ERR, "No device for src_id %d imc %d\n",
|
||||
m->socketid, res->imc);
|
||||
return false;
|
||||
}
|
||||
|
||||
res->column = GET_BITFIELD(m->misc, 9, 18) << 2;
|
||||
res->row = GET_BITFIELD(m->misc, 19, 39);
|
||||
res->bank_group = GET_BITFIELD(m->misc, 40, 41);
|
||||
res->bank_address = GET_BITFIELD(m->misc, 42, 43);
|
||||
res->bank_group |= GET_BITFIELD(m->misc, 44, 44) << 2;
|
||||
res->rank = GET_BITFIELD(m->misc, 56, 58);
|
||||
res->dimm = res->rank >> 2;
|
||||
res->rank = res->rank % 4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int i10nm_get_ddr_munits(void)
|
||||
{
|
||||
struct pci_dev *mdev;
|
||||
@@ -420,7 +623,12 @@ static struct res_config spr_cfg = {
|
||||
.sad_all_devfn = PCI_DEVFN(10, 0),
|
||||
.sad_all_offset = 0x300,
|
||||
.offsets_scrub = offsets_scrub_spr,
|
||||
.offsets_scrub_hbm0 = offsets_scrub_spr_hbm0,
|
||||
.offsets_scrub_hbm1 = offsets_scrub_spr_hbm1,
|
||||
.offsets_demand = offsets_demand_spr,
|
||||
.offsets_demand2 = offsets_demand2_spr,
|
||||
.offsets_demand_hbm0 = offsets_demand_spr_hbm0,
|
||||
.offsets_demand_hbm1 = offsets_demand_spr_hbm1,
|
||||
};
|
||||
|
||||
static const struct x86_cpu_id i10nm_cpuids[] = {
|
||||
@@ -574,7 +782,8 @@ static int __init i10nm_init(void)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
skx_set_mem_cfg(i10nm_check_2lm(cfg));
|
||||
mem_cfg_2lm = i10nm_check_2lm(cfg);
|
||||
skx_set_mem_cfg(mem_cfg_2lm);
|
||||
|
||||
rc = i10nm_get_ddr_munits();
|
||||
|
||||
@@ -626,9 +835,11 @@ static int __init i10nm_init(void)
|
||||
setup_i10nm_debug();
|
||||
|
||||
if (retry_rd_err_log && res_cfg->offsets_scrub && res_cfg->offsets_demand) {
|
||||
skx_set_decode(NULL, show_retry_rd_err_log);
|
||||
skx_set_decode(i10nm_mc_decode, show_retry_rd_err_log);
|
||||
if (retry_rd_err_log == 2)
|
||||
enable_retry_rd_err_log(true);
|
||||
} else {
|
||||
skx_set_decode(i10nm_mc_decode, NULL);
|
||||
}
|
||||
|
||||
i10nm_printk(KERN_INFO, "%s\n", I10NM_REVISION);
|
||||
@@ -658,6 +869,34 @@ static void __exit i10nm_exit(void)
|
||||
module_init(i10nm_init);
|
||||
module_exit(i10nm_exit);
|
||||
|
||||
static int set_decoding_via_mca(const char *buf, const struct kernel_param *kp)
|
||||
{
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(buf, 0, &val);
|
||||
|
||||
if (ret || val > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (val && mem_cfg_2lm) {
|
||||
i10nm_printk(KERN_NOTICE, "Decoding errors via MCA banks for 2LM isn't supported yet\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = param_set_int(buf, kp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops decoding_via_mca_param_ops = {
|
||||
.set = set_decoding_via_mca,
|
||||
.get = param_get_int,
|
||||
};
|
||||
|
||||
module_param_cb(decoding_via_mca, &decoding_via_mca_param_ops, &decoding_via_mca, 0644);
|
||||
MODULE_PARM_DESC(decoding_via_mca, "decoding_via_mca: 0=off(default), 1=enable");
|
||||
|
||||
module_param(retry_rd_err_log, int, 0444);
|
||||
MODULE_PARM_DESC(retry_rd_err_log, "retry_rd_err_log: 0=off(default), 1=bios(Linux doesn't reset any control bits, but just reports values.), 2=linux(Linux tries to take control and resets mode bits, clear valid/UC bits after reading.)");
|
||||
|
||||
|
||||
@@ -1193,7 +1193,7 @@ static int __init i7300_init(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* i7300_init() - Unregisters the driver
|
||||
* i7300_exit() - Unregisters the driver
|
||||
*/
|
||||
static void __exit i7300_exit(void)
|
||||
{
|
||||
|
||||
@@ -20,11 +20,15 @@
|
||||
* 0c08: Xeon E3-1200 v3 Processor DRAM Controller
|
||||
* 1918: Xeon E3-1200 v5 Skylake Host Bridge/DRAM Registers
|
||||
* 5918: Xeon E3-1200 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers
|
||||
* 190f: 6th Gen Core Dual-Core Processor Host Bridge/DRAM Registers
|
||||
* 191f: 6th Gen Core Quad-Core Processor Host Bridge/DRAM Registers
|
||||
* 3e..: 8th/9th Gen Core Processor Host Bridge/DRAM Registers
|
||||
*
|
||||
* Based on Intel specification:
|
||||
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v3-vol-2-datasheet.pdf
|
||||
* http://www.intel.com/content/www/us/en/processors/xeon/xeon-e3-1200-family-vol-2-datasheet.html
|
||||
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/desktop-6th-gen-core-family-datasheet-vol-2.pdf
|
||||
* https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xeon-e3-1200v6-vol-2-datasheet.pdf
|
||||
* https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-h-processor-lines-datasheet-vol-2.html
|
||||
* https://www.intel.com/content/www/us/en/products/docs/processors/core/8th-gen-core-family-datasheet-vol-2.html
|
||||
*
|
||||
@@ -53,15 +57,17 @@
|
||||
#define ie31200_printk(level, fmt, arg...) \
|
||||
edac_printk(level, "ie31200", fmt, ##arg)
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_1 0x0108
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_2 0x010c
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_3 0x0150
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_4 0x0158
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x1918
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x5918
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_1 0x0108
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_2 0x010c
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_3 0x0150
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_4 0x0158
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_5 0x015c
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_6 0x0c04
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_7 0x0c08
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_8 0x190F
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_9 0x1918
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_10 0x191F
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_11 0x5918
|
||||
|
||||
/* Coffee Lake-S */
|
||||
#define PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK 0x3e00
|
||||
@@ -80,6 +86,8 @@
|
||||
#define DEVICE_ID_SKYLAKE_OR_LATER(did) \
|
||||
(((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_8) || \
|
||||
((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_9) || \
|
||||
((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_10) || \
|
||||
((did) == PCI_DEVICE_ID_INTEL_IE31200_HB_11) || \
|
||||
(((did) & PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK) == \
|
||||
PCI_DEVICE_ID_INTEL_IE31200_HB_CFL_MASK))
|
||||
|
||||
@@ -577,6 +585,8 @@ static const struct pci_device_id ie31200_pci_tbl[] = {
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_7), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_8), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_9), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_10), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_11), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_CFL_1), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_CFL_2), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
{ PCI_VEND_DEV(INTEL, IE31200_HB_CFL_3), PCI_ANY_ID, PCI_ANY_ID, 0, 0, IE31200 },
|
||||
|
||||
@@ -178,11 +178,6 @@ struct ppc4xx_ecc_status {
|
||||
u32 wmirq;
|
||||
};
|
||||
|
||||
/* Function Prototypes */
|
||||
|
||||
static int ppc4xx_edac_probe(struct platform_device *device);
|
||||
static int ppc4xx_edac_remove(struct platform_device *device);
|
||||
|
||||
/* Global Variables */
|
||||
|
||||
/*
|
||||
@@ -197,15 +192,6 @@ static const struct of_device_id ppc4xx_edac_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ppc4xx_edac_match);
|
||||
|
||||
static struct platform_driver ppc4xx_edac_driver = {
|
||||
.probe = ppc4xx_edac_probe,
|
||||
.remove = ppc4xx_edac_remove,
|
||||
.driver = {
|
||||
.name = PPC4XX_EDAC_MODULE_NAME,
|
||||
.of_match_table = ppc4xx_edac_match,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO: The row and channel parameters likely need to be dynamically
|
||||
* set based on the aforementioned variant controller realizations.
|
||||
@@ -1391,6 +1377,15 @@ ppc4xx_edac_opstate_init(void)
|
||||
EDAC_OPSTATE_UNKNOWN_STR)));
|
||||
}
|
||||
|
||||
static struct platform_driver ppc4xx_edac_driver = {
|
||||
.probe = ppc4xx_edac_probe,
|
||||
.remove = ppc4xx_edac_remove,
|
||||
.driver = {
|
||||
.name = PPC4XX_EDAC_MODULE_NAME,
|
||||
.of_match_table = ppc4xx_edac_match,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* ppc4xx_edac_init - driver/module insertion entry point
|
||||
*
|
||||
|
||||
+138
-10
@@ -335,6 +335,12 @@ struct sbridge_info {
|
||||
struct sbridge_channel {
|
||||
u32 ranks;
|
||||
u32 dimms;
|
||||
struct dimm {
|
||||
u32 rowbits;
|
||||
u32 colbits;
|
||||
u32 bank_xor_enable;
|
||||
u32 amap_fine;
|
||||
} dimm[MAX_DIMMS];
|
||||
};
|
||||
|
||||
struct pci_id_descr {
|
||||
@@ -1603,7 +1609,7 @@ static int __populate_dimms(struct mem_ctl_info *mci,
|
||||
banks = 8;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
u32 mtr;
|
||||
u32 mtr, amap = 0;
|
||||
|
||||
int max_dimms_per_channel;
|
||||
|
||||
@@ -1615,6 +1621,7 @@ static int __populate_dimms(struct mem_ctl_info *mci,
|
||||
max_dimms_per_channel = ARRAY_SIZE(mtr_regs);
|
||||
if (!pvt->pci_tad[i])
|
||||
continue;
|
||||
pci_read_config_dword(pvt->pci_tad[i], 0x8c, &amap);
|
||||
}
|
||||
|
||||
for (j = 0; j < max_dimms_per_channel; j++) {
|
||||
@@ -1627,6 +1634,7 @@ static int __populate_dimms(struct mem_ctl_info *mci,
|
||||
mtr_regs[j], &mtr);
|
||||
}
|
||||
edac_dbg(4, "Channel #%d MTR%d = %x\n", i, j, mtr);
|
||||
|
||||
if (IS_DIMM_PRESENT(mtr)) {
|
||||
if (!IS_ECC_ENABLED(pvt->info.mcmtr)) {
|
||||
sbridge_printk(KERN_ERR, "CPU SrcID #%d, Ha #%d, Channel #%d has DIMMs, but ECC is disabled\n",
|
||||
@@ -1661,6 +1669,11 @@ static int __populate_dimms(struct mem_ctl_info *mci,
|
||||
dimm->dtype = pvt->info.get_width(pvt, mtr);
|
||||
dimm->mtype = mtype;
|
||||
dimm->edac_mode = mode;
|
||||
pvt->channel[i].dimm[j].rowbits = order_base_2(rows);
|
||||
pvt->channel[i].dimm[j].colbits = order_base_2(cols);
|
||||
pvt->channel[i].dimm[j].bank_xor_enable =
|
||||
GET_BITFIELD(pvt->info.mcmtr, 9, 9);
|
||||
pvt->channel[i].dimm[j].amap_fine = GET_BITFIELD(amap, 0, 0);
|
||||
snprintf(dimm->label, sizeof(dimm->label),
|
||||
"CPU_SrcID#%u_Ha#%u_Chan#%u_DIMM#%u",
|
||||
pvt->sbridge_dev->source_id, pvt->sbridge_dev->dom, i, j);
|
||||
@@ -1922,6 +1935,99 @@ static struct mem_ctl_info *get_mci_for_node_id(u8 node_id, u8 ha)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u8 sb_close_row[] = {
|
||||
15, 16, 17, 18, 20, 21, 22, 28, 10, 11, 12, 13, 29, 30, 31, 32, 33
|
||||
};
|
||||
|
||||
static u8 sb_close_column[] = {
|
||||
3, 4, 5, 14, 19, 23, 24, 25, 26, 27
|
||||
};
|
||||
|
||||
static u8 sb_open_row[] = {
|
||||
14, 15, 16, 20, 28, 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33
|
||||
};
|
||||
|
||||
static u8 sb_open_column[] = {
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12
|
||||
};
|
||||
|
||||
static u8 sb_open_fine_column[] = {
|
||||
3, 4, 5, 7, 8, 9, 10, 11, 12, 13
|
||||
};
|
||||
|
||||
static int sb_bits(u64 addr, int nbits, u8 *bits)
|
||||
{
|
||||
int i, res = 0;
|
||||
|
||||
for (i = 0; i < nbits; i++)
|
||||
res |= ((addr >> bits[i]) & 1) << i;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int sb_bank_bits(u64 addr, int b0, int b1, int do_xor, int x0, int x1)
|
||||
{
|
||||
int ret = GET_BITFIELD(addr, b0, b0) | (GET_BITFIELD(addr, b1, b1) << 1);
|
||||
|
||||
if (do_xor)
|
||||
ret ^= GET_BITFIELD(addr, x0, x0) | (GET_BITFIELD(addr, x1, x1) << 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool sb_decode_ddr4(struct mem_ctl_info *mci, int ch, u8 rank,
|
||||
u64 rank_addr, char *msg)
|
||||
{
|
||||
int dimmno = 0;
|
||||
int row, col, bank_address, bank_group;
|
||||
struct sbridge_pvt *pvt;
|
||||
u32 bg0 = 0, rowbits = 0, colbits = 0;
|
||||
u32 amap_fine = 0, bank_xor_enable = 0;
|
||||
|
||||
dimmno = (rank < 12) ? rank / 4 : 2;
|
||||
pvt = mci->pvt_info;
|
||||
amap_fine = pvt->channel[ch].dimm[dimmno].amap_fine;
|
||||
bg0 = amap_fine ? 6 : 13;
|
||||
rowbits = pvt->channel[ch].dimm[dimmno].rowbits;
|
||||
colbits = pvt->channel[ch].dimm[dimmno].colbits;
|
||||
bank_xor_enable = pvt->channel[ch].dimm[dimmno].bank_xor_enable;
|
||||
|
||||
if (pvt->is_lockstep) {
|
||||
pr_warn_once("LockStep row/column decode is not supported yet!\n");
|
||||
msg[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pvt->is_close_pg) {
|
||||
row = sb_bits(rank_addr, rowbits, sb_close_row);
|
||||
col = sb_bits(rank_addr, colbits, sb_close_column);
|
||||
col |= 0x400; /* C10 is autoprecharge, always set */
|
||||
bank_address = sb_bank_bits(rank_addr, 8, 9, bank_xor_enable, 22, 28);
|
||||
bank_group = sb_bank_bits(rank_addr, 6, 7, bank_xor_enable, 20, 21);
|
||||
} else {
|
||||
row = sb_bits(rank_addr, rowbits, sb_open_row);
|
||||
if (amap_fine)
|
||||
col = sb_bits(rank_addr, colbits, sb_open_fine_column);
|
||||
else
|
||||
col = sb_bits(rank_addr, colbits, sb_open_column);
|
||||
bank_address = sb_bank_bits(rank_addr, 18, 19, bank_xor_enable, 22, 23);
|
||||
bank_group = sb_bank_bits(rank_addr, bg0, 17, bank_xor_enable, 20, 21);
|
||||
}
|
||||
|
||||
row &= (1u << rowbits) - 1;
|
||||
|
||||
sprintf(msg, "row:0x%x col:0x%x bank_addr:%d bank_group:%d",
|
||||
row, col, bank_address, bank_group);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sb_decode_ddr3(struct mem_ctl_info *mci, int ch, u8 rank,
|
||||
u64 rank_addr, char *msg)
|
||||
{
|
||||
pr_warn_once("DDR3 row/column decode not support yet!\n");
|
||||
msg[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
static int get_memory_error_data(struct mem_ctl_info *mci,
|
||||
u64 addr,
|
||||
u8 *socket, u8 *ha,
|
||||
@@ -1937,12 +2043,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
|
||||
int interleave_mode, shiftup = 0;
|
||||
unsigned int sad_interleave[MAX_INTERLEAVE];
|
||||
u32 reg, dram_rule;
|
||||
u8 ch_way, sck_way, pkg, sad_ha = 0;
|
||||
u8 ch_way, sck_way, pkg, sad_ha = 0, rankid = 0;
|
||||
u32 tad_offset;
|
||||
u32 rir_way;
|
||||
u32 mb, gb;
|
||||
u64 ch_addr, offset, limit = 0, prv = 0;
|
||||
|
||||
u64 rank_addr;
|
||||
enum mem_type mtype;
|
||||
|
||||
/*
|
||||
* Step 0) Check if the address is at special memory ranges
|
||||
@@ -2226,6 +2333,28 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
|
||||
pci_read_config_dword(pvt->pci_tad[base_ch], rir_offset[n_rir][idx], ®);
|
||||
*rank = RIR_RNK_TGT(pvt->info.type, reg);
|
||||
|
||||
if (pvt->info.type == BROADWELL) {
|
||||
if (pvt->is_close_pg)
|
||||
shiftup = 6;
|
||||
else
|
||||
shiftup = 13;
|
||||
|
||||
rank_addr = ch_addr >> shiftup;
|
||||
rank_addr /= (1 << rir_way);
|
||||
rank_addr <<= shiftup;
|
||||
rank_addr |= ch_addr & GENMASK_ULL(shiftup - 1, 0);
|
||||
rank_addr -= RIR_OFFSET(pvt->info.type, reg);
|
||||
|
||||
mtype = pvt->info.get_memory_type(pvt);
|
||||
rankid = *rank;
|
||||
if (mtype == MEM_DDR4 || mtype == MEM_RDDR4)
|
||||
sb_decode_ddr4(mci, base_ch, rankid, rank_addr, msg);
|
||||
else
|
||||
sb_decode_ddr3(mci, base_ch, rankid, rank_addr, msg);
|
||||
} else {
|
||||
msg[0] = '\0';
|
||||
}
|
||||
|
||||
edac_dbg(0, "RIR#%d: channel address 0x%08Lx < 0x%08Lx, RIR interleave %d, index %d\n",
|
||||
n_rir,
|
||||
ch_addr,
|
||||
@@ -2950,7 +3079,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
|
||||
struct mem_ctl_info *new_mci;
|
||||
struct sbridge_pvt *pvt = mci->pvt_info;
|
||||
enum hw_event_mc_err_type tp_event;
|
||||
char *optype, msg[256];
|
||||
char *optype, msg[256], msg_full[512];
|
||||
bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0);
|
||||
bool overflow = GET_BITFIELD(m->status, 62, 62);
|
||||
bool uncorrected_error = GET_BITFIELD(m->status, 61, 61);
|
||||
@@ -3089,18 +3218,17 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
|
||||
*/
|
||||
if (!pvt->is_lockstep && !pvt->is_cur_addr_mirrored && !pvt->is_close_pg)
|
||||
channel = first_channel;
|
||||
|
||||
snprintf(msg, sizeof(msg),
|
||||
"%s%s area:%s err_code:%04x:%04x socket:%d ha:%d channel_mask:%ld rank:%d",
|
||||
snprintf(msg_full, sizeof(msg_full),
|
||||
"%s%s area:%s err_code:%04x:%04x socket:%d ha:%d channel_mask:%ld rank:%d %s",
|
||||
overflow ? " OVERFLOW" : "",
|
||||
(uncorrected_error && recoverable) ? " recoverable" : "",
|
||||
area_type,
|
||||
mscod, errcode,
|
||||
socket, ha,
|
||||
channel_mask,
|
||||
rank);
|
||||
rank, msg);
|
||||
|
||||
edac_dbg(0, "%s\n", msg);
|
||||
edac_dbg(0, "%s\n", msg_full);
|
||||
|
||||
/* FIXME: need support for channel mask */
|
||||
|
||||
@@ -3111,7 +3239,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
|
||||
edac_mc_handle_error(tp_event, mci, core_err_cnt,
|
||||
m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
|
||||
channel, dimm, -1,
|
||||
optype, msg);
|
||||
optype, msg_full);
|
||||
return;
|
||||
err_parsing:
|
||||
edac_mc_handle_error(tp_event, mci, core_err_cnt, 0, 0, 0,
|
||||
|
||||
@@ -714,8 +714,13 @@ static int __init skx_init(void)
|
||||
|
||||
skx_set_decode(skx_decode, skx_show_retry_rd_err_log);
|
||||
|
||||
if (nvdimm_count && skx_adxl_get() == -ENODEV)
|
||||
skx_printk(KERN_NOTICE, "Only decoding DDR4 address!\n");
|
||||
if (nvdimm_count && skx_adxl_get() != -ENODEV) {
|
||||
skx_set_decode(NULL, skx_show_retry_rd_err_log);
|
||||
} else {
|
||||
if (nvdimm_count)
|
||||
skx_printk(KERN_NOTICE, "Only decoding DDR4 address!\n");
|
||||
skx_set_decode(skx_decode, skx_show_retry_rd_err_log);
|
||||
}
|
||||
|
||||
/* Ensure that the OPSTATE is set correctly for POLL or NMI */
|
||||
opstate_init();
|
||||
|
||||
@@ -27,9 +27,11 @@ static const char * const component_names[] = {
|
||||
[INDEX_MEMCTRL] = "MemoryControllerId",
|
||||
[INDEX_CHANNEL] = "ChannelId",
|
||||
[INDEX_DIMM] = "DimmSlotId",
|
||||
[INDEX_CS] = "ChipSelect",
|
||||
[INDEX_NM_MEMCTRL] = "NmMemoryControllerId",
|
||||
[INDEX_NM_CHANNEL] = "NmChannelId",
|
||||
[INDEX_NM_DIMM] = "NmDimmSlotId",
|
||||
[INDEX_NM_CS] = "NmChipSelect",
|
||||
};
|
||||
|
||||
static int component_indices[ARRAY_SIZE(component_names)];
|
||||
@@ -40,7 +42,7 @@ static char *adxl_msg;
|
||||
static unsigned long adxl_nm_bitmap;
|
||||
|
||||
static char skx_msg[MSG_SIZE];
|
||||
static skx_decode_f skx_decode;
|
||||
static skx_decode_f driver_decode;
|
||||
static skx_show_retry_log_f skx_show_retry_rd_err_log;
|
||||
static u64 skx_tolm, skx_tohm;
|
||||
static LIST_HEAD(dev_edac_list);
|
||||
@@ -139,10 +141,13 @@ static bool skx_adxl_decode(struct decoded_addr *res, bool error_in_1st_level_me
|
||||
(int)adxl_values[component_indices[INDEX_NM_CHANNEL]] : -1;
|
||||
res->dimm = (adxl_nm_bitmap & BIT_NM_DIMM) ?
|
||||
(int)adxl_values[component_indices[INDEX_NM_DIMM]] : -1;
|
||||
res->cs = (adxl_nm_bitmap & BIT_NM_CS) ?
|
||||
(int)adxl_values[component_indices[INDEX_NM_CS]] : -1;
|
||||
} else {
|
||||
res->imc = (int)adxl_values[component_indices[INDEX_MEMCTRL]];
|
||||
res->channel = (int)adxl_values[component_indices[INDEX_CHANNEL]];
|
||||
res->dimm = (int)adxl_values[component_indices[INDEX_DIMM]];
|
||||
res->cs = (int)adxl_values[component_indices[INDEX_CS]];
|
||||
}
|
||||
|
||||
if (res->imc > NUM_IMC - 1 || res->imc < 0) {
|
||||
@@ -173,6 +178,8 @@ static bool skx_adxl_decode(struct decoded_addr *res, bool error_in_1st_level_me
|
||||
break;
|
||||
}
|
||||
|
||||
res->decoded_by_adxl = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -183,7 +190,7 @@ void skx_set_mem_cfg(bool mem_cfg_2lm)
|
||||
|
||||
void skx_set_decode(skx_decode_f decode, skx_show_retry_log_f show_retry_log)
|
||||
{
|
||||
skx_decode = decode;
|
||||
driver_decode = decode;
|
||||
skx_show_retry_rd_err_log = show_retry_log;
|
||||
}
|
||||
|
||||
@@ -591,19 +598,19 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (adxl_component_count) {
|
||||
if (res->decoded_by_adxl) {
|
||||
len = snprintf(skx_msg, MSG_SIZE, "%s%s err_code:0x%04x:0x%04x %s",
|
||||
overflow ? " OVERFLOW" : "",
|
||||
(uncorrected_error && recoverable) ? " recoverable" : "",
|
||||
mscod, errcode, adxl_msg);
|
||||
} else {
|
||||
len = snprintf(skx_msg, MSG_SIZE,
|
||||
"%s%s err_code:0x%04x:0x%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:0x%x col:0x%x",
|
||||
"%s%s err_code:0x%04x:0x%04x ProcessorSocketId:0x%x MemoryControllerId:0x%x PhysicalRankId:0x%x Row:0x%x Column:0x%x Bank:0x%x BankGroup:0x%x",
|
||||
overflow ? " OVERFLOW" : "",
|
||||
(uncorrected_error && recoverable) ? " recoverable" : "",
|
||||
mscod, errcode,
|
||||
res->socket, res->imc, res->rank,
|
||||
res->bank_group, res->bank_address, res->row, res->column);
|
||||
res->row, res->column, res->bank_address, res->bank_group);
|
||||
}
|
||||
|
||||
if (skx_show_retry_rd_err_log)
|
||||
@@ -649,13 +656,14 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
|
||||
return NOTIFY_DONE;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.mce = mce;
|
||||
res.addr = mce->addr;
|
||||
|
||||
if (adxl_component_count) {
|
||||
if (!skx_adxl_decode(&res, skx_error_in_1st_level_mem(mce)))
|
||||
/* Try driver decoder first */
|
||||
if (!(driver_decode && driver_decode(&res))) {
|
||||
/* Then try firmware decoder (ACPI DSM methods) */
|
||||
if (!(adxl_component_count && skx_adxl_decode(&res, skx_error_in_1st_level_mem(mce))))
|
||||
return NOTIFY_DONE;
|
||||
} else if (!skx_decode || !skx_decode(&res)) {
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
mci = res.dev->imc[res.imc].mci;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define _SKX_COMM_EDAC_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <asm/mce.h>
|
||||
|
||||
#define MSG_SIZE 1024
|
||||
|
||||
@@ -52,6 +53,9 @@
|
||||
#define IS_DIMM_PRESENT(r) GET_BITFIELD(r, 15, 15)
|
||||
#define IS_NVDIMM_PRESENT(r, i) GET_BITFIELD(r, i, i)
|
||||
|
||||
#define MCI_MISC_ECC_MODE(m) (((m) >> 59) & 15)
|
||||
#define MCI_MISC_ECC_DDRT 8 /* read from DDRT */
|
||||
|
||||
/*
|
||||
* Each cpu socket contains some pci devices that provide global
|
||||
* information, and also some that are local to each of the two
|
||||
@@ -82,6 +86,7 @@ struct skx_dev {
|
||||
struct pci_dev *edev;
|
||||
u32 retry_rd_err_log_s;
|
||||
u32 retry_rd_err_log_d;
|
||||
u32 retry_rd_err_log_d2;
|
||||
struct skx_dimm {
|
||||
u8 close_pg;
|
||||
u8 bank_xor_enable;
|
||||
@@ -108,18 +113,22 @@ enum {
|
||||
INDEX_MEMCTRL,
|
||||
INDEX_CHANNEL,
|
||||
INDEX_DIMM,
|
||||
INDEX_CS,
|
||||
INDEX_NM_FIRST,
|
||||
INDEX_NM_MEMCTRL = INDEX_NM_FIRST,
|
||||
INDEX_NM_CHANNEL,
|
||||
INDEX_NM_DIMM,
|
||||
INDEX_NM_CS,
|
||||
INDEX_MAX
|
||||
};
|
||||
|
||||
#define BIT_NM_MEMCTRL BIT_ULL(INDEX_NM_MEMCTRL)
|
||||
#define BIT_NM_CHANNEL BIT_ULL(INDEX_NM_CHANNEL)
|
||||
#define BIT_NM_DIMM BIT_ULL(INDEX_NM_DIMM)
|
||||
#define BIT_NM_CS BIT_ULL(INDEX_NM_CS)
|
||||
|
||||
struct decoded_addr {
|
||||
struct mce *mce;
|
||||
struct skx_dev *dev;
|
||||
u64 addr;
|
||||
int socket;
|
||||
@@ -129,6 +138,7 @@ struct decoded_addr {
|
||||
int sktways;
|
||||
int chanways;
|
||||
int dimm;
|
||||
int cs;
|
||||
int rank;
|
||||
int channel_rank;
|
||||
u64 rank_address;
|
||||
@@ -136,6 +146,7 @@ struct decoded_addr {
|
||||
int column;
|
||||
int bank_address;
|
||||
int bank_group;
|
||||
bool decoded_by_adxl;
|
||||
};
|
||||
|
||||
struct res_config {
|
||||
@@ -154,7 +165,12 @@ struct res_config {
|
||||
int sad_all_offset;
|
||||
/* Offsets of retry_rd_err_log registers */
|
||||
u32 *offsets_scrub;
|
||||
u32 *offsets_scrub_hbm0;
|
||||
u32 *offsets_scrub_hbm1;
|
||||
u32 *offsets_demand;
|
||||
u32 *offsets_demand2;
|
||||
u32 *offsets_demand_hbm0;
|
||||
u32 *offsets_demand_hbm1;
|
||||
};
|
||||
|
||||
typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci,
|
||||
|
||||
@@ -37,7 +37,6 @@ int edac_workqueue_setup(void)
|
||||
|
||||
void edac_workqueue_teardown(void)
|
||||
{
|
||||
flush_workqueue(wq);
|
||||
destroy_workqueue(wq);
|
||||
wq = NULL;
|
||||
}
|
||||
|
||||
@@ -556,6 +556,14 @@ static int __init cec_init(void)
|
||||
if (ce_arr.disabled)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Intel systems may avoid uncorrectable errors
|
||||
* if pages with corrected errors are aggressively
|
||||
* taken offline.
|
||||
*/
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
|
||||
action_threshold = 2;
|
||||
|
||||
ce_arr.array = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!ce_arr.array) {
|
||||
pr_err("Error allocating CE array page!\n");
|
||||
|
||||
+24
-25
@@ -460,46 +460,45 @@ bool fscrypt_mergeable_bio_bh(struct bio *bio,
|
||||
EXPORT_SYMBOL_GPL(fscrypt_mergeable_bio_bh);
|
||||
|
||||
/**
|
||||
* fscrypt_dio_supported() - check whether a DIO (direct I/O) request is
|
||||
* supported as far as encryption is concerned
|
||||
* @iocb: the file and position the I/O is targeting
|
||||
* @iter: the I/O data segment(s)
|
||||
* fscrypt_dio_supported() - check whether DIO (direct I/O) is supported on an
|
||||
* inode, as far as encryption is concerned
|
||||
* @inode: the inode in question
|
||||
*
|
||||
* Return: %true if there are no encryption constraints that prevent DIO from
|
||||
* being supported; %false if DIO is unsupported. (Note that in the
|
||||
* %true case, the filesystem might have other, non-encryption-related
|
||||
* constraints that prevent DIO from actually being supported.)
|
||||
* constraints that prevent DIO from actually being supported. Also, on
|
||||
* encrypted files the filesystem is still responsible for only allowing
|
||||
* DIO when requests are filesystem-block-aligned.)
|
||||
*/
|
||||
bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter)
|
||||
bool fscrypt_dio_supported(struct inode *inode)
|
||||
{
|
||||
const struct inode *inode = file_inode(iocb->ki_filp);
|
||||
const unsigned int blocksize = i_blocksize(inode);
|
||||
int err;
|
||||
|
||||
/* If the file is unencrypted, no veto from us. */
|
||||
if (!fscrypt_needs_contents_encryption(inode))
|
||||
return true;
|
||||
|
||||
/* We only support DIO with inline crypto, not fs-layer crypto. */
|
||||
if (!fscrypt_inode_uses_inline_crypto(inode))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Since the granularity of encryption is filesystem blocks, the file
|
||||
* position and total I/O length must be aligned to the filesystem block
|
||||
* size -- not just to the block device's logical block size as is
|
||||
* traditionally the case for DIO on many filesystems.
|
||||
* We only support DIO with inline crypto, not fs-layer crypto.
|
||||
*
|
||||
* We require that the user-provided memory buffers be filesystem block
|
||||
* aligned too. It is simpler to have a single alignment value required
|
||||
* for all properties of the I/O, as is normally the case for DIO.
|
||||
* Also, allowing less aligned buffers would imply that data units could
|
||||
* cross bvecs, which would greatly complicate the I/O stack, which
|
||||
* assumes that bios can be split at any bvec boundary.
|
||||
* To determine whether the inode is using inline crypto, we have to set
|
||||
* up the key if it wasn't already done. This is because in the current
|
||||
* design of fscrypt, the decision of whether to use inline crypto or
|
||||
* not isn't made until the inode's encryption key is being set up. In
|
||||
* the DIO read/write case, the key will always be set up already, since
|
||||
* the file will be open. But in the case of statx(), the key might not
|
||||
* be set up yet, as the file might not have been opened yet.
|
||||
*/
|
||||
if (!IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), blocksize))
|
||||
err = fscrypt_require_key(inode);
|
||||
if (err) {
|
||||
/*
|
||||
* Key unavailable or couldn't be set up. This edge case isn't
|
||||
* worth worrying about; just report that DIO is unsupported.
|
||||
*/
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return fscrypt_inode_uses_inline_crypto(inode);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fscrypt_dio_supported);
|
||||
|
||||
|
||||
@@ -2977,6 +2977,7 @@ extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
|
||||
extern int ext4_write_inode(struct inode *, struct writeback_control *);
|
||||
extern int ext4_setattr(struct user_namespace *, struct dentry *,
|
||||
struct iattr *);
|
||||
extern u32 ext4_dio_alignment(struct inode *inode);
|
||||
extern int ext4_getattr(struct user_namespace *, const struct path *,
|
||||
struct kstat *, u32, unsigned int);
|
||||
extern void ext4_evict_inode(struct inode *);
|
||||
|
||||
+26
-11
@@ -36,19 +36,34 @@
|
||||
#include "acl.h"
|
||||
#include "truncate.h"
|
||||
|
||||
static bool ext4_dio_supported(struct kiocb *iocb, struct iov_iter *iter)
|
||||
/*
|
||||
* Returns %true if the given DIO request should be attempted with DIO, or
|
||||
* %false if it should fall back to buffered I/O.
|
||||
*
|
||||
* DIO isn't well specified; when it's unsupported (either due to the request
|
||||
* being misaligned, or due to the file not supporting DIO at all), filesystems
|
||||
* either fall back to buffered I/O or return EINVAL. For files that don't use
|
||||
* any special features like encryption or verity, ext4 has traditionally
|
||||
* returned EINVAL for misaligned DIO. iomap_dio_rw() uses this convention too.
|
||||
* In this case, we should attempt the DIO, *not* fall back to buffered I/O.
|
||||
*
|
||||
* In contrast, in cases where DIO is unsupported due to ext4 features, ext4
|
||||
* traditionally falls back to buffered I/O.
|
||||
*
|
||||
* This function implements the traditional ext4 behavior in all these cases.
|
||||
*/
|
||||
static bool ext4_should_use_dio(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct inode *inode = file_inode(iocb->ki_filp);
|
||||
u32 dio_align = ext4_dio_alignment(inode);
|
||||
|
||||
if (!fscrypt_dio_supported(iocb, iter))
|
||||
if (dio_align == 0)
|
||||
return false;
|
||||
if (fsverity_active(inode))
|
||||
return false;
|
||||
if (ext4_should_journal_data(inode))
|
||||
return false;
|
||||
if (ext4_has_inline_data(inode))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if (dio_align == 1)
|
||||
return true;
|
||||
|
||||
return IS_ALIGNED(iocb->ki_pos | iov_iter_alignment(iter), dio_align);
|
||||
}
|
||||
|
||||
static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
@@ -63,7 +78,7 @@ static ssize_t ext4_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
inode_lock_shared(inode);
|
||||
}
|
||||
|
||||
if (!ext4_dio_supported(iocb, to)) {
|
||||
if (!ext4_should_use_dio(iocb, to)) {
|
||||
inode_unlock_shared(inode);
|
||||
/*
|
||||
* Fallback to buffered I/O if the operation being performed on
|
||||
@@ -511,7 +526,7 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
}
|
||||
|
||||
/* Fallback to buffered I/O if the inode does not support direct I/O. */
|
||||
if (!ext4_dio_supported(iocb, from)) {
|
||||
if (!ext4_should_use_dio(iocb, from)) {
|
||||
if (ilock_shared)
|
||||
inode_unlock_shared(inode);
|
||||
else
|
||||
|
||||
@@ -5550,6 +5550,22 @@ err_out:
|
||||
return error;
|
||||
}
|
||||
|
||||
u32 ext4_dio_alignment(struct inode *inode)
|
||||
{
|
||||
if (fsverity_active(inode))
|
||||
return 0;
|
||||
if (ext4_should_journal_data(inode))
|
||||
return 0;
|
||||
if (ext4_has_inline_data(inode))
|
||||
return 0;
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
if (!fscrypt_dio_supported(inode))
|
||||
return 0;
|
||||
return i_blocksize(inode);
|
||||
}
|
||||
return 1; /* use the iomap defaults */
|
||||
}
|
||||
|
||||
int ext4_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int query_flags)
|
||||
{
|
||||
@@ -5565,6 +5581,27 @@ int ext4_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
stat->btime.tv_nsec = ei->i_crtime.tv_nsec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the DIO alignment restrictions if requested. We only return
|
||||
* this information when requested, since on encrypted files it might
|
||||
* take a fair bit of work to get if the file wasn't opened recently.
|
||||
*/
|
||||
if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->i_mode)) {
|
||||
u32 dio_align = ext4_dio_alignment(inode);
|
||||
|
||||
stat->result_mask |= STATX_DIOALIGN;
|
||||
if (dio_align == 1) {
|
||||
struct block_device *bdev = inode->i_sb->s_bdev;
|
||||
|
||||
/* iomap defaults */
|
||||
stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
|
||||
stat->dio_offset_align = bdev_logical_block_size(bdev);
|
||||
} else {
|
||||
stat->dio_mem_align = dio_align;
|
||||
stat->dio_offset_align = dio_align;
|
||||
}
|
||||
}
|
||||
|
||||
flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
|
||||
if (flags & EXT4_APPEND_FL)
|
||||
stat->attributes |= STATX_ATTR_APPEND;
|
||||
|
||||
@@ -4471,17 +4471,6 @@ static inline void f2fs_i_compr_blocks_update(struct inode *inode,
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
|
||||
static inline int block_unaligned_IO(struct inode *inode,
|
||||
struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
unsigned int i_blkbits = READ_ONCE(inode->i_blkbits);
|
||||
unsigned int blocksize_mask = (1 << i_blkbits) - 1;
|
||||
loff_t offset = iocb->ki_pos;
|
||||
unsigned long align = offset | iov_iter_alignment(iter);
|
||||
|
||||
return align & blocksize_mask;
|
||||
}
|
||||
|
||||
static inline bool f2fs_allow_multi_device_dio(struct f2fs_sb_info *sbi,
|
||||
int flag)
|
||||
{
|
||||
@@ -4492,35 +4481,6 @@ static inline bool f2fs_allow_multi_device_dio(struct f2fs_sb_info *sbi,
|
||||
return sbi->aligned_blksize;
|
||||
}
|
||||
|
||||
static inline bool f2fs_force_buffered_io(struct inode *inode,
|
||||
struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
int rw = iov_iter_rw(iter);
|
||||
|
||||
if (!fscrypt_dio_supported(iocb, iter))
|
||||
return true;
|
||||
if (fsverity_active(inode))
|
||||
return true;
|
||||
if (f2fs_compressed_file(inode))
|
||||
return true;
|
||||
|
||||
/* disallow direct IO if any of devices has unaligned blksize */
|
||||
if (f2fs_is_multi_device(sbi) && !sbi->aligned_blksize)
|
||||
return true;
|
||||
|
||||
if (f2fs_lfs_mode(sbi) && (rw == WRITE)) {
|
||||
if (block_unaligned_IO(inode, iocb, iter))
|
||||
return true;
|
||||
if (F2FS_IO_ALIGNED(sbi))
|
||||
return true;
|
||||
}
|
||||
if (is_sbi_flag_set(F2FS_I_SB(inode), SBI_CP_DISABLED))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool f2fs_need_verity(const struct inode *inode, pgoff_t idx)
|
||||
{
|
||||
return fsverity_active(inode) &&
|
||||
|
||||
+42
-1
@@ -808,6 +808,29 @@ int f2fs_truncate(struct inode *inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool f2fs_force_buffered_io(struct inode *inode, int rw)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
|
||||
if (!fscrypt_dio_supported(inode))
|
||||
return true;
|
||||
if (fsverity_active(inode))
|
||||
return true;
|
||||
if (f2fs_compressed_file(inode))
|
||||
return true;
|
||||
|
||||
/* disallow direct IO if any of devices has unaligned blksize */
|
||||
if (f2fs_is_multi_device(sbi) && !sbi->aligned_blksize)
|
||||
return true;
|
||||
|
||||
if (f2fs_lfs_mode(sbi) && rw == WRITE && F2FS_IO_ALIGNED(sbi))
|
||||
return true;
|
||||
if (is_sbi_flag_set(sbi, SBI_CP_DISABLED))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int f2fs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int query_flags)
|
||||
{
|
||||
@@ -824,6 +847,24 @@ int f2fs_getattr(struct user_namespace *mnt_userns, const struct path *path,
|
||||
stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the DIO alignment restrictions if requested. We only return
|
||||
* this information when requested, since on encrypted files it might
|
||||
* take a fair bit of work to get if the file wasn't opened recently.
|
||||
*
|
||||
* f2fs sometimes supports DIO reads but not DIO writes. STATX_DIOALIGN
|
||||
* cannot represent that, so in that case we report no DIO support.
|
||||
*/
|
||||
if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->i_mode)) {
|
||||
unsigned int bsize = i_blocksize(inode);
|
||||
|
||||
stat->result_mask |= STATX_DIOALIGN;
|
||||
if (!f2fs_force_buffered_io(inode, WRITE)) {
|
||||
stat->dio_mem_align = bsize;
|
||||
stat->dio_offset_align = bsize;
|
||||
}
|
||||
}
|
||||
|
||||
flags = fi->i_flags;
|
||||
if (flags & F2FS_COMPR_FL)
|
||||
stat->attributes |= STATX_ATTR_COMPRESSED;
|
||||
@@ -4182,7 +4223,7 @@ static bool f2fs_should_use_dio(struct inode *inode, struct kiocb *iocb,
|
||||
if (!(iocb->ki_flags & IOCB_DIRECT))
|
||||
return false;
|
||||
|
||||
if (f2fs_force_buffered_io(inode, iocb, iter))
|
||||
if (f2fs_force_buffered_io(inode, iov_iter_rw(iter)))
|
||||
return false;
|
||||
|
||||
/*
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -230,11 +231,22 @@ retry:
|
||||
goto out;
|
||||
|
||||
error = vfs_getattr(&path, stat, request_mask, flags);
|
||||
|
||||
stat->mnt_id = real_mount(path.mnt)->mnt_id;
|
||||
stat->result_mask |= STATX_MNT_ID;
|
||||
|
||||
if (path.mnt->mnt_root == path.dentry)
|
||||
stat->attributes |= STATX_ATTR_MOUNT_ROOT;
|
||||
stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT;
|
||||
|
||||
/* Handle STATX_DIOALIGN for block devices. */
|
||||
if (request_mask & STATX_DIOALIGN) {
|
||||
struct inode *inode = d_backing_inode(path.dentry);
|
||||
|
||||
if (S_ISBLK(inode->i_mode))
|
||||
bdev_statx_dioalign(inode, stat);
|
||||
}
|
||||
|
||||
path_put(&path);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
@@ -611,6 +623,8 @@ cp_statx(const struct kstat *stat, struct statx __user *buffer)
|
||||
tmp.stx_dev_major = MAJOR(stat->dev);
|
||||
tmp.stx_dev_minor = MINOR(stat->dev);
|
||||
tmp.stx_mnt_id = stat->mnt_id;
|
||||
tmp.stx_dio_mem_align = stat->dio_mem_align;
|
||||
tmp.stx_dio_offset_align = stat->dio_offset_align;
|
||||
|
||||
return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
@@ -53,14 +53,14 @@ static int fsverity_read_merkle_tree(struct inode *inode,
|
||||
break;
|
||||
}
|
||||
|
||||
virt = kmap(page);
|
||||
virt = kmap_local_page(page);
|
||||
if (copy_to_user(buf, virt + offs_in_page, bytes_to_copy)) {
|
||||
kunmap(page);
|
||||
kunmap_local(virt);
|
||||
put_page(page);
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
kunmap(page);
|
||||
kunmap_local(virt);
|
||||
put_page(page);
|
||||
|
||||
retval += bytes_to_copy;
|
||||
|
||||
+2
-12
@@ -39,16 +39,6 @@ static void hash_at_level(const struct merkle_tree_params *params,
|
||||
(params->log_blocksize - params->log_arity);
|
||||
}
|
||||
|
||||
/* Extract a hash from a hash page */
|
||||
static void extract_hash(struct page *hpage, unsigned int hoffset,
|
||||
unsigned int hsize, u8 *out)
|
||||
{
|
||||
void *virt = kmap_atomic(hpage);
|
||||
|
||||
memcpy(out, virt + hoffset, hsize);
|
||||
kunmap_atomic(virt);
|
||||
}
|
||||
|
||||
static inline int cmp_hashes(const struct fsverity_info *vi,
|
||||
const u8 *want_hash, const u8 *real_hash,
|
||||
pgoff_t index, int level)
|
||||
@@ -129,7 +119,7 @@ static bool verify_page(struct inode *inode, const struct fsverity_info *vi,
|
||||
}
|
||||
|
||||
if (PageChecked(hpage)) {
|
||||
extract_hash(hpage, hoffset, hsize, _want_hash);
|
||||
memcpy_from_page(_want_hash, hpage, hoffset, hsize);
|
||||
want_hash = _want_hash;
|
||||
put_page(hpage);
|
||||
pr_debug_ratelimited("Hash page already checked, want %s:%*phN\n",
|
||||
@@ -158,7 +148,7 @@ descend:
|
||||
if (err)
|
||||
goto out;
|
||||
SetPageChecked(hpage);
|
||||
extract_hash(hpage, hoffset, hsize, _want_hash);
|
||||
memcpy_from_page(_want_hash, hpage, hoffset, hsize);
|
||||
want_hash = _want_hash;
|
||||
put_page(hpage);
|
||||
pr_debug("Verified hash page at level %d, now want %s:%*phN\n",
|
||||
|
||||
@@ -604,6 +604,16 @@ xfs_vn_getattr(
|
||||
stat->blksize = BLKDEV_IOSIZE;
|
||||
stat->rdev = inode->i_rdev;
|
||||
break;
|
||||
case S_IFREG:
|
||||
if (request_mask & STATX_DIOALIGN) {
|
||||
struct xfs_buftarg *target = xfs_inode_buftarg(ip);
|
||||
struct block_device *bdev = target->bt_bdev;
|
||||
|
||||
stat->result_mask |= STATX_DIOALIGN;
|
||||
stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
|
||||
stat->dio_offset_align = bdev_logical_block_size(bdev);
|
||||
}
|
||||
fallthrough;
|
||||
default:
|
||||
stat->blksize = xfs_stat_blksize(ip);
|
||||
stat->rdev = 0;
|
||||
|
||||
@@ -1498,6 +1498,7 @@ int sync_blockdev(struct block_device *bdev);
|
||||
int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend);
|
||||
int sync_blockdev_nowait(struct block_device *bdev);
|
||||
void sync_bdevs(bool wait);
|
||||
void bdev_statx_dioalign(struct inode *inode, struct kstat *stat);
|
||||
void printk_all_partitions(void);
|
||||
#else
|
||||
static inline void invalidate_bdev(struct block_device *bdev)
|
||||
@@ -1514,6 +1515,9 @@ static inline int sync_blockdev_nowait(struct block_device *bdev)
|
||||
static inline void sync_bdevs(bool wait)
|
||||
{
|
||||
}
|
||||
static inline void bdev_statx_dioalign(struct inode *inode, struct kstat *stat)
|
||||
{
|
||||
}
|
||||
static inline void printk_all_partitions(void)
|
||||
{
|
||||
}
|
||||
|
||||
+15
-15
@@ -231,21 +231,21 @@ enum mem_type {
|
||||
#define MEM_FLAG_DDR BIT(MEM_DDR)
|
||||
#define MEM_FLAG_RDDR BIT(MEM_RDDR)
|
||||
#define MEM_FLAG_RMBS BIT(MEM_RMBS)
|
||||
#define MEM_FLAG_DDR2 BIT(MEM_DDR2)
|
||||
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
|
||||
#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
|
||||
#define MEM_FLAG_XDR BIT(MEM_XDR)
|
||||
#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
|
||||
#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
|
||||
#define MEM_FLAG_LPDDR3 BIT(MEM_LPDDR3)
|
||||
#define MEM_FLAG_DDR4 BIT(MEM_DDR4)
|
||||
#define MEM_FLAG_RDDR4 BIT(MEM_RDDR4)
|
||||
#define MEM_FLAG_LRDDR4 BIT(MEM_LRDDR4)
|
||||
#define MEM_FLAG_LPDDR4 BIT(MEM_LPDDR4)
|
||||
#define MEM_FLAG_DDR5 BIT(MEM_DDR5)
|
||||
#define MEM_FLAG_RDDR5 BIT(MEM_RDDR5)
|
||||
#define MEM_FLAG_LRDDR5 BIT(MEM_LRDDR5)
|
||||
#define MEM_FLAG_NVDIMM BIT(MEM_NVDIMM)
|
||||
#define MEM_FLAG_DDR2 BIT(MEM_DDR2)
|
||||
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
|
||||
#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
|
||||
#define MEM_FLAG_XDR BIT(MEM_XDR)
|
||||
#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
|
||||
#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
|
||||
#define MEM_FLAG_LPDDR3 BIT(MEM_LPDDR3)
|
||||
#define MEM_FLAG_DDR4 BIT(MEM_DDR4)
|
||||
#define MEM_FLAG_RDDR4 BIT(MEM_RDDR4)
|
||||
#define MEM_FLAG_LRDDR4 BIT(MEM_LRDDR4)
|
||||
#define MEM_FLAG_LPDDR4 BIT(MEM_LPDDR4)
|
||||
#define MEM_FLAG_DDR5 BIT(MEM_DDR5)
|
||||
#define MEM_FLAG_RDDR5 BIT(MEM_RDDR5)
|
||||
#define MEM_FLAG_LRDDR5 BIT(MEM_LRDDR5)
|
||||
#define MEM_FLAG_NVDIMM BIT(MEM_NVDIMM)
|
||||
#define MEM_FLAG_WIO2 BIT(MEM_WIO2)
|
||||
#define MEM_FLAG_HBM2 BIT(MEM_HBM2)
|
||||
|
||||
|
||||
@@ -764,7 +764,7 @@ bool fscrypt_mergeable_bio(struct bio *bio, const struct inode *inode,
|
||||
bool fscrypt_mergeable_bio_bh(struct bio *bio,
|
||||
const struct buffer_head *next_bh);
|
||||
|
||||
bool fscrypt_dio_supported(struct kiocb *iocb, struct iov_iter *iter);
|
||||
bool fscrypt_dio_supported(struct inode *inode);
|
||||
|
||||
u64 fscrypt_limit_io_blocks(const struct inode *inode, u64 lblk, u64 nr_blocks);
|
||||
|
||||
@@ -797,11 +797,8 @@ static inline bool fscrypt_mergeable_bio_bh(struct bio *bio,
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool fscrypt_dio_supported(struct kiocb *iocb,
|
||||
struct iov_iter *iter)
|
||||
static inline bool fscrypt_dio_supported(struct inode *inode)
|
||||
{
|
||||
const struct inode *inode = file_inode(iocb->ki_filp);
|
||||
|
||||
return !fscrypt_needs_contents_encryption(inode);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
#define PCI_CLASS_COMMUNICATION_MODEM 0x0703
|
||||
#define PCI_CLASS_COMMUNICATION_OTHER 0x0780
|
||||
|
||||
/* Interface for SERIAL/MODEM */
|
||||
#define PCI_SERIAL_16550_COMPATIBLE 0x02
|
||||
|
||||
#define PCI_BASE_CLASS_SYSTEM 0x08
|
||||
#define PCI_CLASS_SYSTEM_PIC 0x0800
|
||||
#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010
|
||||
|
||||
@@ -50,6 +50,8 @@ struct kstat {
|
||||
struct timespec64 btime; /* File creation time */
|
||||
u64 blocks;
|
||||
u64 mnt_id;
|
||||
u32 dio_mem_align;
|
||||
u32 dio_offset_align;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -124,7 +124,8 @@ struct statx {
|
||||
__u32 stx_dev_minor;
|
||||
/* 0x90 */
|
||||
__u64 stx_mnt_id;
|
||||
__u64 __spare2;
|
||||
__u32 stx_dio_mem_align; /* Memory buffer alignment for direct I/O */
|
||||
__u32 stx_dio_offset_align; /* File offset alignment for direct I/O */
|
||||
/* 0xa0 */
|
||||
__u64 __spare3[12]; /* Spare space for future expansion */
|
||||
/* 0x100 */
|
||||
@@ -152,6 +153,7 @@ struct statx {
|
||||
#define STATX_BASIC_STATS 0x000007ffU /* The stuff in the normal stat struct */
|
||||
#define STATX_BTIME 0x00000800U /* Want/got stx_btime */
|
||||
#define STATX_MNT_ID 0x00001000U /* Got stx_mnt_id */
|
||||
#define STATX_DIOALIGN 0x00002000U /* Want/got direct I/O alignment info */
|
||||
|
||||
#define STATX__RESERVED 0x80000000U /* Reserved for future struct statx expansion */
|
||||
|
||||
|
||||
@@ -1073,6 +1073,9 @@ static const char *uaccess_safe_builtin[] = {
|
||||
"copy_mc_fragile_handle_tail",
|
||||
"copy_mc_enhanced_fast_string",
|
||||
"ftrace_likely_update", /* CONFIG_TRACE_BRANCH_PROFILING */
|
||||
"clear_user_erms",
|
||||
"clear_user_rep_good",
|
||||
"clear_user_original",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user