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:
Greg Kroah-Hartman
2022-10-09 14:08:34 +02:00
56 changed files with 1063 additions and 333 deletions
@@ -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
View File
@@ -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
+14
View File
@@ -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
*
+33 -21
View File
@@ -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
+2
View File
@@ -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 */
+1 -1
View File
@@ -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
+1
View File
@@ -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 */
+13
View File
@@ -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 */
+1
View File
@@ -743,6 +743,7 @@ extern void default_banner(void);
word 771b; \
.byte ptype; \
.byte 772b-771b; \
_ASM_ALIGN; \
.popsection
+1
View File
@@ -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. */
+2 -3
View File
@@ -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>
+45
View File
@@ -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 */
+9
View File
@@ -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;
+40 -4
View File
@@ -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;
}
+3
View File
@@ -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)
+12 -1
View File
@@ -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;
+14 -7
View File
@@ -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);
}
/**
-2
View File
@@ -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);
+1 -1
View File
@@ -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;
}
+7 -7
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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,
+138
View File
@@ -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)
-40
View File
@@ -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
+10
View File
@@ -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);
+3 -1
View File
@@ -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;
+23
View File
@@ -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);
}
-1
View File
@@ -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)
-4
View File
@@ -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
View File
@@ -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.)");
+1 -1
View File
@@ -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)
{
+19 -9
View File
@@ -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 },
+9 -14
View File
@@ -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
View File
@@ -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], &reg);
*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,
+7 -2
View File
@@ -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();
+17 -9
View File
@@ -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;
+16
View File
@@ -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,
-1
View File
@@ -37,7 +37,6 @@ int edac_workqueue_setup(void)
void edac_workqueue_teardown(void)
{
flush_workqueue(wq);
destroy_workqueue(wq);
wq = NULL;
}
+8
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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
+37
View File
@@ -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;
-40
View File
@@ -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
View File
@@ -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;
/*
+14
View File
@@ -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;
}
+3 -3
View File
@@ -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
View File
@@ -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",
+10
View File
@@ -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;
+4
View File
@@ -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
View File
@@ -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)
+2 -5
View File
@@ -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);
}
+3
View File
@@ -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
+2
View File
@@ -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
+3 -1
View File
@@ -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 */
+3
View File
@@ -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
};